python312Packages.dissect-util: 3.18 -> 3.19
[NixPkgs.git] / lib / gvariant.nix
blobd542df4d7b9a0adfba06f7596cc2413e0428008d
1 /**
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.
5   :::{.warning}
6   This API is not considered fully stable and it might therefore
7   change in backwards incompatible ways without prior notice.
8   :::
9 */
11 # This file is based on https://github.com/nix-community/home-manager
12 # Copyright (c) 2017-2022 Home Manager contributors
13 { lib }:
15 let
16   inherit (lib)
17     concatMapStringsSep concatStrings escape head replaceStrings;
19   mkPrimitive = t: v: {
20     _type = "gvariant";
21     type = t;
22     value = v;
23     __toString = self: "@${self.type} ${toString self.value}"; # https://docs.gtk.org/glib/gvariant-text.html
24   };
26   type = {
27     arrayOf = t: "a${t}";
28     maybeOf = t: "m${t}";
29     tupleOf = ts: "(${concatStrings ts})";
30     dictionaryEntryOf = nameType: valueType: "{${nameType}${valueType}}";
31     string = "s";
32     boolean = "b";
33     uchar = "y";
34     int16 = "n";
35     uint16 = "q";
36     int32 = "i";
37     uint32 = "u";
38     int64 = "x";
39     uint64 = "t";
40     double = "d";
41     variant = "v";
42   };
45 rec {
47   inherit type;
49   /**
50     Check if a value is a GVariant value
53     # Inputs
55     `v`
57     : value to check
59     # Type
61     ```
62     isGVariant :: Any -> Bool
63     ```
64   */
65   isGVariant = v: v._type or "" == "gvariant";
67   intConstructors = [
68     {
69       name = "mkInt32";
70       type = type.int32;
71       min = -2147483648;
72       max = 2147483647;
73     }
74     {
75       name = "mkUint32";
76       type = type.uint32;
77       min = 0;
78       max = 4294967295;
79     }
80     {
81       name = "mkInt64";
82       type = type.int64;
83       # Nix does not support such large numbers.
84       min = null;
85       max = null;
86     }
87     {
88       name = "mkUint64";
89       type = type.uint64;
90       min = 0;
91       # Nix does not support such large numbers.
92       max = null;
93     }
94     {
95       name = "mkInt16";
96       type = type.int16;
97       min = -32768;
98       max = 32767;
99     }
100     {
101       name = "mkUint16";
102       type = type.uint16;
103       min = 0;
104       max = 65535;
105     }
106     {
107       name = "mkUchar";
108       type = type.uchar;
109       min = 0;
110       max = 255;
111     }
112   ];
114   /**
115     Returns the GVariant value that most closely matches the given Nix value.
116     If no GVariant value can be found unambiguously then error is thrown.
119     # Inputs
121     `v`
123     : 1\. Function argument
125     # Type
127     ```
128     mkValue :: Any -> gvariant
129     ```
130   */
131   mkValue = v:
132     if builtins.isBool v then
133       mkBoolean v
134     else if builtins.isFloat v then
135       mkDouble v
136     else if builtins.isString v then
137       mkString v
138     else if builtins.isList v then
139       mkArray v
140     else if isGVariant v then
141       v
142     else if builtins.isInt v then
143       let
144         validConstructors = builtins.filter ({ min, max, ... }: (min == null || min <= v) && (max == null || v <= max)) intConstructors;
145       in
146       throw ''
147         The GVariant type for number “${builtins.toString v}” is unclear.
148         Please wrap the value with one of the following, depending on the value type in GSettings schema:
150         ${lib.concatMapStringsSep "\n" ({ name, type, ...}: "- `lib.gvariant.${name}` for `${type}`") validConstructors}
151       ''
152     else if builtins.isAttrs v then
153       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`."
154     else
155       throw "The GVariant type of “${builtins.typeOf v}” can't be inferred.";
157   /**
158     Returns the GVariant array from the given type of the elements and a Nix list.
161     # Inputs
163     `elems`
165     : 1\. Function argument
167     # Type
169     ```
170     mkArray :: [Any] -> gvariant
171     ```
173     # Examples
174     :::{.example}
175     ## `lib.gvariant.mkArray` usage example
177     ```nix
178     # Creating a string array
179     lib.gvariant.mkArray [ "a" "b" "c" ]
180     ```
182     :::
183   */
184   mkArray = elems:
185     let
186       vs = map mkValue (lib.throwIf (elems == [ ]) "Please create empty array with mkEmptyArray." elems);
187       elemType = lib.throwIfNot (lib.all (t: (head vs).type == t) (map (v: v.type) vs))
188         "Elements in a list should have same type."
189         (head vs).type;
190     in
191     mkPrimitive (type.arrayOf elemType) vs // {
192       __toString = self:
193         "@${self.type} [${concatMapStringsSep "," toString self.value}]";
194     };
196   /**
197     Returns the GVariant array from the given empty Nix list.
200     # Inputs
202     `elemType`
204     : 1\. Function argument
206     # Type
208     ```
209     mkEmptyArray :: gvariant.type -> gvariant
210     ```
212     # Examples
213     :::{.example}
214     ## `lib.gvariant.mkEmptyArray` usage example
216     ```nix
217     # Creating an empty string array
218     lib.gvariant.mkEmptyArray (lib.gvariant.type.string)
219     ```
221     :::
222   */
223   mkEmptyArray = elemType: mkPrimitive (type.arrayOf elemType) [ ] // {
224     __toString = self: "@${self.type} []";
225   };
228   /**
229     Returns the GVariant variant from the given Nix value. Variants are containers
230     of different GVariant type.
233     # Inputs
235     `elem`
237     : 1\. Function argument
239     # Type
241     ```
242     mkVariant :: Any -> gvariant
243     ```
245     # Examples
246     :::{.example}
247     ## `lib.gvariant.mkVariant` usage example
249     ```nix
250     lib.gvariant.mkArray [
251       (lib.gvariant.mkVariant "a string")
252       (lib.gvariant.mkVariant (lib.gvariant.mkInt32 1))
253     ]
254     ```
256     :::
257   */
258   mkVariant = elem:
259     let gvarElem = mkValue elem;
260     in mkPrimitive type.variant gvarElem // {
261       __toString = self: "<${toString self.value}>";
262     };
264   /**
265     Returns the GVariant dictionary entry from the given key and value.
268     # Inputs
270     `name`
272     : The key of the entry
274     `value`
276     : The value of the entry
278     # Type
280     ```
281     mkDictionaryEntry :: String -> Any -> gvariant
282     ```
284     # Examples
285     :::{.example}
286     ## `lib.gvariant.mkDictionaryEntry` usage example
288     ```nix
289     # A dictionary describing an Epiphany’s search provider
290     [
291       (lib.gvariant.mkDictionaryEntry "url" (lib.gvariant.mkVariant "https://duckduckgo.com/?q=%s&t=epiphany"))
292       (lib.gvariant.mkDictionaryEntry "bang" (lib.gvariant.mkVariant "!d"))
293       (lib.gvariant.mkDictionaryEntry "name" (lib.gvariant.mkVariant "DuckDuckGo"))
294     ]
295     ```
297     :::
298   */
299   mkDictionaryEntry =
300     name:
301     value:
302     let
303       name' = mkValue name;
304       value' = mkValue value;
305       dictionaryType = type.dictionaryEntryOf name'.type value'.type;
306     in
307     mkPrimitive dictionaryType { inherit name value; } // {
308       __toString = self: "@${self.type} {${name'},${value'}}";
309     };
311   /**
312     Returns the GVariant maybe from the given element type.
315     # Inputs
317     `elemType`
319     : 1\. Function argument
321     `elem`
323     : 2\. Function argument
325     # Type
327     ```
328     mkMaybe :: gvariant.type -> Any -> gvariant
329     ```
330   */
331   mkMaybe = elemType: elem:
332     mkPrimitive (type.maybeOf elemType) elem // {
333       __toString = self:
334         if self.value == null then
335           "@${self.type} nothing"
336         else
337           "just ${toString self.value}";
338     };
340   /**
341     Returns the GVariant nothing from the given element type.
344     # Inputs
346     `elemType`
348     : 1\. Function argument
350     # Type
352     ```
353     mkNothing :: gvariant.type -> gvariant
354     ```
355   */
356   mkNothing = elemType: mkMaybe elemType null;
358   /**
359     Returns the GVariant just from the given Nix value.
362     # Inputs
364     `elem`
366     : 1\. Function argument
368     # Type
370     ```
371     mkJust :: Any -> gvariant
372     ```
373   */
374   mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem;
376   /**
377     Returns the GVariant tuple from the given Nix list.
380     # Inputs
382     `elems`
384     : 1\. Function argument
386     # Type
388     ```
389     mkTuple :: [Any] -> gvariant
390     ```
391   */
392   mkTuple = elems:
393     let
394       gvarElems = map mkValue elems;
395       tupleType = type.tupleOf (map (e: e.type) gvarElems);
396     in
397     mkPrimitive tupleType gvarElems // {
398       __toString = self:
399         "@${self.type} (${concatMapStringsSep "," toString self.value})";
400     };
402   /**
403     Returns the GVariant boolean from the given Nix bool value.
406     # Inputs
408     `v`
410     : 1\. Function argument
412     # Type
414     ```
415     mkBoolean :: Bool -> gvariant
416     ```
417   */
418   mkBoolean = v:
419     mkPrimitive type.boolean v // {
420       __toString = self: if self.value then "true" else "false";
421     };
423   /**
424     Returns the GVariant string from the given Nix string value.
427     # Inputs
429     `v`
431     : 1\. Function argument
433     # Type
435     ```
436     mkString :: String -> gvariant
437     ```
438   */
439   mkString = v:
440     let sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s);
441     in mkPrimitive type.string v // {
442       __toString = self: "'${sanitize self.value}'";
443     };
445   /**
446     Returns the GVariant object path from the given Nix string value.
449     # Inputs
451     `v`
453     : 1\. Function argument
455     # Type
457     ```
458     mkObjectpath :: String -> gvariant
459     ```
460   */
461   mkObjectpath = v:
462     mkPrimitive type.string v // {
463       __toString = self: "objectpath '${escape [ "'" ] self.value}'";
464     };
466   /**
467     Returns the GVariant uchar from the given Nix int value.
469     # Type
471     ```
472     mkUchar :: Int -> gvariant
473     ```
474   */
475   mkUchar = mkPrimitive type.uchar;
477   /**
478     Returns the GVariant int16 from the given Nix int value.
480     # Type
482     ```
483     mkInt16 :: Int -> gvariant
484     ```
485   */
486   mkInt16 = mkPrimitive type.int16;
488   /**
489     Returns the GVariant uint16 from the given Nix int value.
491     # Type
493     ```
494     mkUint16 :: Int -> gvariant
495     ```
496   */
497   mkUint16 = mkPrimitive type.uint16;
499   /**
500     Returns the GVariant int32 from the given Nix int value.
503     # Inputs
505     `v`
507     : 1\. Function argument
509     # Type
511     ```
512     mkInt32 :: Int -> gvariant
513     ```
514   */
515   mkInt32 = v:
516     mkPrimitive type.int32 v // {
517       __toString = self: toString self.value;
518     };
520   /**
521     Returns the GVariant uint32 from the given Nix int value.
523     # Type
525     ```
526     mkUint32 :: Int -> gvariant
527     ```
528   */
529   mkUint32 = mkPrimitive type.uint32;
531   /**
532     Returns the GVariant int64 from the given Nix int value.
534     # Type
536     ```
537     mkInt64 :: Int -> gvariant
538     ```
539   */
540   mkInt64 = mkPrimitive type.int64;
542   /**
543     Returns the GVariant uint64 from the given Nix int value.
545     # Type
547     ```
548     mkUint64 :: Int -> gvariant
549     ```
550   */
551   mkUint64 = mkPrimitive type.uint64;
553   /**
554     Returns the GVariant double from the given Nix float value.
557     # Inputs
559     `v`
561     : 1\. Function argument
563     # Type
565     ```
566     mkDouble :: Float -> gvariant
567     ```
568   */
569   mkDouble = v:
570     mkPrimitive type.double v // {
571       __toString = self: toString self.value;
572     };