2 A partial and basic implementation of GVariant formatted strings.
3 See [GVariant Format Strings](https://docs.gtk.org/glib/gvariant-format-strings.html) for details.
6 This API is not considered fully stable and it might therefore
7 change in backwards incompatible ways without prior notice.
11 # This file is based on https://github.com/nix-community/home-manager
12 # Copyright (c) 2017-2022 Home Manager contributors
17 concatMapStringsSep concatStrings escape head replaceStrings;
23 __toString = self: "@${self.type} ${toString self.value}"; # https://docs.gtk.org/glib/gvariant-text.html
29 tupleOf = ts: "(${concatStrings ts})";
30 dictionaryEntryOf = nameType: valueType: "{${nameType}${valueType}}";
44 /* Check if a value is a GVariant value
47 isGVariant :: Any -> Bool
49 isGVariant = v: v._type or "" == "gvariant";
54 inherit type isGVariant;
72 # Nix does not support such large numbers.
80 # Nix does not support such large numbers.
103 /* Returns the GVariant value that most closely matches the given Nix value.
104 If no GVariant value can be found unambiguously then error is thrown.
107 mkValue :: Any -> gvariant
110 if builtins.isBool v then
112 else if builtins.isFloat v then
114 else if builtins.isString v then
116 else if builtins.isList v then
118 else if isGVariant v then
120 else if builtins.isInt v then
122 validConstructors = builtins.filter ({ min, max, ... }: (min == null || min <= v) && (max == null || v <= max)) intConstructors;
125 The GVariant type for number “${builtins.toString v}” is unclear.
126 Please wrap the value with one of the following, depending on the value type in GSettings schema:
128 ${lib.concatMapStringsSep "\n" ({ name, type, ...}: "- `lib.gvariant.${name}` for `${type}`") validConstructors}
130 else if builtins.isAttrs v then
131 throw "Cannot construct GVariant value from an attribute set. If you want to construct a dictionary, you will need to create an array containing items constructed with `lib.gvariant.mkDictionaryEntry`."
133 throw "The GVariant type of “${builtins.typeOf v}” can't be inferred.";
135 /* Returns the GVariant array from the given type of the elements and a Nix list.
138 mkArray :: [Any] -> gvariant
141 # Creating a string array
142 lib.gvariant.mkArray [ "a" "b" "c" ]
146 vs = map mkValue (lib.throwIf (elems == [ ]) "Please create empty array with mkEmptyArray." elems);
147 elemType = lib.throwIfNot (lib.all (t: (head vs).type == t) (map (v: v.type) vs))
148 "Elements in a list should have same type."
151 mkPrimitive (type.arrayOf elemType) vs // {
153 "@${self.type} [${concatMapStringsSep "," toString self.value}]";
156 /* Returns the GVariant array from the given empty Nix list.
159 mkEmptyArray :: gvariant.type -> gvariant
162 # Creating an empty string array
163 lib.gvariant.mkEmptyArray (lib.gvariant.type.string)
165 mkEmptyArray = elemType: mkPrimitive (type.arrayOf elemType) [ ] // {
166 __toString = self: "@${self.type} []";
170 /* Returns the GVariant variant from the given Nix value. Variants are containers
171 of different GVariant type.
174 mkVariant :: Any -> gvariant
177 lib.gvariant.mkArray [
178 (lib.gvariant.mkVariant "a string")
179 (lib.gvariant.mkVariant (lib.gvariant.mkInt32 1))
183 let gvarElem = mkValue elem;
184 in mkPrimitive type.variant gvarElem // {
185 __toString = self: "<${toString self.value}>";
188 /* Returns the GVariant dictionary entry from the given key and value.
191 mkDictionaryEntry :: String -> Any -> gvariant
194 # A dictionary describing an Epiphany’s search provider
196 (lib.gvariant.mkDictionaryEntry "url" (lib.gvariant.mkVariant "https://duckduckgo.com/?q=%s&t=epiphany"))
197 (lib.gvariant.mkDictionaryEntry "bang" (lib.gvariant.mkVariant "!d"))
198 (lib.gvariant.mkDictionaryEntry "name" (lib.gvariant.mkVariant "DuckDuckGo"))
202 # The key of the entry
204 # The value of the entry
207 name' = mkValue name;
208 value' = mkValue value;
209 dictionaryType = type.dictionaryEntryOf name'.type value'.type;
211 mkPrimitive dictionaryType { inherit name value; } // {
212 __toString = self: "@${self.type} {${name'},${value'}}";
215 /* Returns the GVariant maybe from the given element type.
218 mkMaybe :: gvariant.type -> Any -> gvariant
220 mkMaybe = elemType: elem:
221 mkPrimitive (type.maybeOf elemType) elem // {
223 if self.value == null then
224 "@${self.type} nothing"
226 "just ${toString self.value}";
229 /* Returns the GVariant nothing from the given element type.
232 mkNothing :: gvariant.type -> gvariant
234 mkNothing = elemType: mkMaybe elemType null;
236 /* Returns the GVariant just from the given Nix value.
239 mkJust :: Any -> gvariant
241 mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem;
243 /* Returns the GVariant tuple from the given Nix list.
246 mkTuple :: [Any] -> gvariant
250 gvarElems = map mkValue elems;
251 tupleType = type.tupleOf (map (e: e.type) gvarElems);
253 mkPrimitive tupleType gvarElems // {
255 "@${self.type} (${concatMapStringsSep "," toString self.value})";
258 /* Returns the GVariant boolean from the given Nix bool value.
261 mkBoolean :: Bool -> gvariant
264 mkPrimitive type.boolean v // {
265 __toString = self: if self.value then "true" else "false";
268 /* Returns the GVariant string from the given Nix string value.
271 mkString :: String -> gvariant
274 let sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s);
275 in mkPrimitive type.string v // {
276 __toString = self: "'${sanitize self.value}'";
279 /* Returns the GVariant object path from the given Nix string value.
282 mkObjectpath :: String -> gvariant
285 mkPrimitive type.string v // {
286 __toString = self: "objectpath '${escape [ "'" ] self.value}'";
289 /* Returns the GVariant uchar from the given Nix int value.
292 mkUchar :: Int -> gvariant
294 mkUchar = mkPrimitive type.uchar;
296 /* Returns the GVariant int16 from the given Nix int value.
299 mkInt16 :: Int -> gvariant
301 mkInt16 = mkPrimitive type.int16;
303 /* Returns the GVariant uint16 from the given Nix int value.
306 mkUint16 :: Int -> gvariant
308 mkUint16 = mkPrimitive type.uint16;
310 /* Returns the GVariant int32 from the given Nix int value.
313 mkInt32 :: Int -> gvariant
316 mkPrimitive type.int32 v // {
317 __toString = self: toString self.value;
320 /* Returns the GVariant uint32 from the given Nix int value.
323 mkUint32 :: Int -> gvariant
325 mkUint32 = mkPrimitive type.uint32;
327 /* Returns the GVariant int64 from the given Nix int value.
330 mkInt64 :: Int -> gvariant
332 mkInt64 = mkPrimitive type.int64;
334 /* Returns the GVariant uint64 from the given Nix int value.
337 mkUint64 :: Int -> gvariant
339 mkUint64 = mkPrimitive type.uint64;
341 /* Returns the GVariant double from the given Nix float value.
344 mkDouble :: Float -> gvariant
347 mkPrimitive type.double v // {
348 __toString = self: toString self.value;