diff --git a/docs/writing-modules.adoc b/docs/writing-modules.adoc index 0f3336ff..d8d69e82 100644 --- a/docs/writing-modules.adoc +++ b/docs/writing-modules.adoc @@ -167,9 +167,11 @@ Builds a GVariant array containing the given list of elements, where each elemen - `hm.gvariant.type.int64` - `hm.gvariant.type.uint64` - `hm.gvariant.type.double` +- `hm.gvariant.type.variant` - `hm.gvariant.type.arrayOf type` - `hm.gvariant.type.maybeOf type` - `hm.gvariant.type.tupleOf types` +- `hm.gvariant.type.dictionaryEntryOf types` -- + where `type` and `types` are themselves a type and list of types, respectively. @@ -185,3 +187,9 @@ Builds a GVariant maybe value containing the given GVariant element. + `hm.gvariant.mkTuple elements`::: Builds a GVariant tuple containing the given list of elements, where each element is a GVariant value. ++ +`hm.gvariant.mkVariant element`::: +Builds a GVariant variant which contains the value of a GVariant element. ++ +`hm.gvariant.mkDictionaryEntry elements`::: +Builds a GVariant dictionary entry containing the given list of elements, where each element is a GVariant value. diff --git a/modules/lib/gvariant.nix b/modules/lib/gvariant.nix index 7c4ca5b0..bbb97c64 100644 --- a/modules/lib/gvariant.nix +++ b/modules/lib/gvariant.nix @@ -20,6 +20,7 @@ let arrayOf = t: "a${t}"; maybeOf = t: "m${t}"; tupleOf = ts: "(${concatStrings ts})"; + dictionaryEntryOf = ts: "{${concatStrings ts}}"; string = "s"; boolean = "b"; uchar = "y"; @@ -30,6 +31,7 @@ let int64 = "x"; uint64 = "t"; double = "d"; + variant = "v"; }; # Returns the GVariant type of a given Nix value. If no type can be @@ -74,13 +76,13 @@ in rec { isGVariant = v: v._type or "" == "gvariant"; isArray = hasPrefix "a"; + isDictionaryEntry = hasPrefix "{"; 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 @@ -105,6 +107,21 @@ in rec { mkEmptyArray = elemType: mkArray elemType [ ]; + mkVariant = elem: + let gvarElem = mkValue elem; + in mkPrimitive type.variant gvarElem // { + __toString = self: "@${self.type} <${toString self.value}>"; + }; + + mkDictionaryEntry = elems: + let + gvarElems = map mkValue elems; + dictionaryType = type.dictionaryEntryOf (map (e: e.type) gvarElems); + in mkPrimitive dictionaryType gvarElems // { + __toString = self: + "@${self.type} {${concatMapStringsSep "," toString self.value}}"; + }; + mkNothing = elemType: mkMaybe elemType null; mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem; diff --git a/modules/lib/types.nix b/modules/lib/types.nix index d2ed24a3..de741b1e 100644 --- a/modules/lib/types.nix +++ b/modules/lib/types.nix @@ -95,6 +95,10 @@ in rec { mergeOneOption loc defs else if gvar.isMaybe sharedDefType && allChecked then mergeOneOption loc defs + else if gvar.isDictionaryEntry sharedDefType && allChecked then + mergeOneOption loc defs + else if gvar.type.variant == sharedDefType && allChecked then + mergeOneOption loc defs else if gvar.type.string == sharedDefType && allChecked then types.str.merge loc defs else if gvar.type.double == sharedDefType && allChecked then diff --git a/tests/lib/types/gvariant-merge.nix b/tests/lib/types/gvariant-merge.nix index c4de6827..5a04848a 100644 --- a/tests/lib/types/gvariant-merge.nix +++ b/tests/lib/types/gvariant-merge.nix @@ -50,6 +50,11 @@ in { { maybe1 = mkNothing type.string; } { maybe2 = mkJust (mkUint32 4); } + + { variant1 = mkVariant "foo"; } + { variant2 = mkVariant 42; } + + { dictionaryEntry = mkDictionaryEntry [ 1 [ "foo" ] ]; } ]; home.file."result.txt".text = let @@ -65,6 +70,7 @@ in { array1 = @as ['one','two'] array2 = @au [1,2] bool = true + dictionaryEntry = @{ias} {1,@as ['foo']} emptyArray1 = @as [] emptyArray2 = @au [] escapedString = '\'\\\n' @@ -79,6 +85,8 @@ in { uint16 = @q 42 uint32 = @u 42 uint64 = @t 42 + variant1 = @v <'foo'> + variant2 = @v <42> '' } '';