aboutsummaryrefslogtreecommitdiff
path: root/home-manager/modules/lib/gvariant.nix
diff options
context:
space:
mode:
Diffstat (limited to 'home-manager/modules/lib/gvariant.nix')
-rw-r--r--home-manager/modules/lib/gvariant.nix156
1 files changed, 156 insertions, 0 deletions
diff --git a/home-manager/modules/lib/gvariant.nix b/home-manager/modules/lib/gvariant.nix
new file mode 100644
index 00000000000..92aa7d98371
--- /dev/null
+++ b/home-manager/modules/lib/gvariant.nix
@@ -0,0 +1,156 @@
+# A partial and basic implementation of GVariant formatted strings.
+#
+# Note, this API is not considered fully stable and it might therefore
+# change in backwards incompatible ways without prior notice.
+
+{ lib }:
+
+with lib;
+
+let
+
+ mkPrimitive = t: v: {
+ _type = "gvariant";
+ type = t;
+ value = v;
+ __toString = self: "@${self.type} ${toString self.value}";
+ };
+
+ type = {
+ arrayOf = t: "a${t}";
+ maybeOf = t: "m${t}";
+ tupleOf = ts: "(${concatStrings ts})";
+ string = "s";
+ boolean = "b";
+ uchar = "y";
+ int16 = "n";
+ uint16 = "q";
+ int32 = "i";
+ uint32 = "u";
+ int64 = "x";
+ uint64 = "t";
+ double = "d";
+ };
+
+ # Returns the GVariant type of a given Nix value. If no type can be
+ # found for the value then the empty string is returned.
+ typeOf = v:
+ with type;
+ if builtins.isBool v then
+ boolean
+ else if builtins.isInt v then
+ int32
+ else if builtins.isFloat v then
+ double
+ else if builtins.isString v then
+ string
+ else if builtins.isList v then
+ let elemType = elemTypeOf v;
+ in if elemType == "" then "" else arrayOf elemType
+ else if builtins.isAttrs v && v ? type then
+ v.type
+ else
+ "";
+
+ elemTypeOf = vs:
+ if builtins.isList vs then
+ if vs == [ ] then "" else typeOf (head vs)
+ else
+ "";
+
+ mkMaybe = elemType: elem:
+ mkPrimitive (type.maybeOf elemType) elem // {
+ __toString = self:
+ if self.value == null then
+ "@${self.type} nothing"
+ else
+ "just ${toString self.value}";
+ };
+
+in rec {
+
+ inherit type typeOf;
+
+ isArray = hasPrefix "a";
+ isMaybe = hasPrefix "m";
+ isTuple = hasPrefix "(";
+
+ # Returns the GVariant value that most closely matches the given Nix
+ # value. If no GVariant value can be found then `null` is returned.
+ #
+ # No support for dictionaries, maybe types, or variants.
+ mkValue = v:
+ if builtins.isBool v then
+ mkBoolean v
+ else if builtins.isInt v then
+ mkInt32 v
+ else if builtins.isFloat v then
+ mkDouble v
+ else if builtins.isString v then
+ mkString v
+ else if builtins.isList v then
+ if v == [ ] then mkArray type.string [ ] else mkArray (elemTypeOf v) v
+ else if builtins.isAttrs v && (v._type or "") == "gvariant" then
+ v
+ else
+ null;
+
+ mkArray = elemType: elems:
+ mkPrimitive (type.arrayOf elemType) (map mkValue elems) // {
+ __toString = self:
+ "@${self.type} [${concatMapStringsSep "," toString self.value}]";
+ };
+
+ mkEmptyArray = elemType: mkArray elemType [ ];
+
+ mkNothing = elemType: mkMaybe elemType null;
+
+ mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem;
+
+ mkTuple = elems:
+ let
+ gvarElems = map mkValue elems;
+ tupleType = type.tupleOf (map (e: e.type) gvarElems);
+ in mkPrimitive tupleType gvarElems // {
+ __toString = self:
+ "@${self.type} (${concatMapStringsSep "," toString self.value})";
+ };
+
+ mkBoolean = v:
+ mkPrimitive type.boolean v // {
+ __toString = self: if self.value then "true" else "false";
+ };
+
+ mkString = v:
+ mkPrimitive type.string v // {
+ __toString = self: "'${escape [ "'" "\\" ] self.value}'";
+ };
+
+ mkObjectpath = v:
+ mkPrimitive type.string v // {
+ __toString = self: "objectpath '${escape [ "'" ] self.value}'";
+ };
+
+ mkUchar = mkPrimitive type.uchar;
+
+ mkInt16 = mkPrimitive type.int16;
+
+ mkUint16 = mkPrimitive type.uint16;
+
+ mkInt32 = v:
+ mkPrimitive type.int32 v // {
+ __toString = self: toString self.value;
+ };
+
+ mkUint32 = mkPrimitive type.uint32;
+
+ mkInt64 = mkPrimitive type.int64;
+
+ mkUint64 = mkPrimitive type.uint64;
+
+ mkDouble = v:
+ mkPrimitive type.double v // {
+ __toString = self: toString self.value;
+ };
+
+}