Merge pull request #311159 from r-ryantm/auto-update/python311Packages.pytorch-lightning
[NixPkgs.git] / lib / gvariant.nix
blob54aa4ea805719fc7332e035e5ae7816d9af30c6b
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   };
44   /* Check if a value is a GVariant value
46      Type:
47        isGVariant :: Any -> Bool
48   */
49   isGVariant = v: v._type or "" == "gvariant";
52 rec {
54   inherit type isGVariant;
56   intConstructors = [
57     {
58       name = "mkInt32";
59       type = type.int32;
60       min = -2147483648;
61       max = 2147483647;
62     }
63     {
64       name = "mkUint32";
65       type = type.uint32;
66       min = 0;
67       max = 4294967295;
68     }
69     {
70       name = "mkInt64";
71       type = type.int64;
72       # Nix does not support such large numbers.
73       min = null;
74       max = null;
75     }
76     {
77       name = "mkUint64";
78       type = type.uint64;
79       min = 0;
80       # Nix does not support such large numbers.
81       max = null;
82     }
83     {
84       name = "mkInt16";
85       type = type.int16;
86       min = -32768;
87       max = 32767;
88     }
89     {
90       name = "mkUint16";
91       type = type.uint16;
92       min = 0;
93       max = 65535;
94     }
95     {
96       name = "mkUchar";
97       type = type.uchar;
98       min = 0;
99       max = 255;
100     }
101   ];
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.
106      Type:
107        mkValue :: Any -> gvariant
108   */
109   mkValue = v:
110     if builtins.isBool v then
111       mkBoolean v
112     else if builtins.isFloat v then
113       mkDouble v
114     else if builtins.isString v then
115       mkString v
116     else if builtins.isList v then
117       mkArray v
118     else if isGVariant v then
119       v
120     else if builtins.isInt v then
121       let
122         validConstructors = builtins.filter ({ min, max, ... }: (min == null || min <= v) && (max == null || v <= max)) intConstructors;
123       in
124       throw ''
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}
129       ''
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`."
132     else
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.
137      Type:
138        mkArray :: [Any] -> gvariant
140      Example:
141        # Creating a string array
142        lib.gvariant.mkArray [ "a" "b" "c" ]
143   */
144   mkArray = elems:
145     let
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."
149         (head vs).type;
150     in
151     mkPrimitive (type.arrayOf elemType) vs // {
152       __toString = self:
153         "@${self.type} [${concatMapStringsSep "," toString self.value}]";
154     };
156   /* Returns the GVariant array from the given empty Nix list.
158      Type:
159        mkEmptyArray :: gvariant.type -> gvariant
161      Example:
162        # Creating an empty string array
163        lib.gvariant.mkEmptyArray (lib.gvariant.type.string)
164   */
165   mkEmptyArray = elemType: mkPrimitive (type.arrayOf elemType) [ ] // {
166     __toString = self: "@${self.type} []";
167   };
170   /* Returns the GVariant variant from the given Nix value. Variants are containers
171      of different GVariant type.
173      Type:
174        mkVariant :: Any -> gvariant
176      Example:
177        lib.gvariant.mkArray [
178          (lib.gvariant.mkVariant "a string")
179          (lib.gvariant.mkVariant (lib.gvariant.mkInt32 1))
180        ]
181   */
182   mkVariant = elem:
183     let gvarElem = mkValue elem;
184     in mkPrimitive type.variant gvarElem // {
185       __toString = self: "<${toString self.value}>";
186     };
188   /* Returns the GVariant dictionary entry from the given key and value.
190      Type:
191        mkDictionaryEntry :: String -> Any -> gvariant
193      Example:
194        # A dictionary describing an Epiphany’s search provider
195        [
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"))
199        ]
200   */
201   mkDictionaryEntry =
202     # The key of the entry
203     name:
204     # The value of the entry
205     value:
206     let
207       name' = mkValue name;
208       value' = mkValue value;
209       dictionaryType = type.dictionaryEntryOf name'.type value'.type;
210     in
211     mkPrimitive dictionaryType { inherit name value; } // {
212       __toString = self: "@${self.type} {${name'},${value'}}";
213     };
215   /* Returns the GVariant maybe from the given element type.
217      Type:
218        mkMaybe :: gvariant.type -> Any -> gvariant
219   */
220   mkMaybe = elemType: elem:
221     mkPrimitive (type.maybeOf elemType) elem // {
222       __toString = self:
223         if self.value == null then
224           "@${self.type} nothing"
225         else
226           "just ${toString self.value}";
227     };
229   /* Returns the GVariant nothing from the given element type.
231      Type:
232        mkNothing :: gvariant.type -> gvariant
233   */
234   mkNothing = elemType: mkMaybe elemType null;
236   /* Returns the GVariant just from the given Nix value.
238      Type:
239        mkJust :: Any -> gvariant
240   */
241   mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem;
243   /* Returns the GVariant tuple from the given Nix list.
245      Type:
246        mkTuple :: [Any] -> gvariant
247   */
248   mkTuple = elems:
249     let
250       gvarElems = map mkValue elems;
251       tupleType = type.tupleOf (map (e: e.type) gvarElems);
252     in
253     mkPrimitive tupleType gvarElems // {
254       __toString = self:
255         "@${self.type} (${concatMapStringsSep "," toString self.value})";
256     };
258   /* Returns the GVariant boolean from the given Nix bool value.
260      Type:
261        mkBoolean :: Bool -> gvariant
262   */
263   mkBoolean = v:
264     mkPrimitive type.boolean v // {
265       __toString = self: if self.value then "true" else "false";
266     };
268   /* Returns the GVariant string from the given Nix string value.
270      Type:
271        mkString :: String -> gvariant
272   */
273   mkString = v:
274     let sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s);
275     in mkPrimitive type.string v // {
276       __toString = self: "'${sanitize self.value}'";
277     };
279   /* Returns the GVariant object path from the given Nix string value.
281      Type:
282        mkObjectpath :: String -> gvariant
283   */
284   mkObjectpath = v:
285     mkPrimitive type.string v // {
286       __toString = self: "objectpath '${escape [ "'" ] self.value}'";
287     };
289   /* Returns the GVariant uchar from the given Nix int value.
291      Type:
292        mkUchar :: Int -> gvariant
293   */
294   mkUchar = mkPrimitive type.uchar;
296   /* Returns the GVariant int16 from the given Nix int value.
298      Type:
299        mkInt16 :: Int -> gvariant
300   */
301   mkInt16 = mkPrimitive type.int16;
303   /* Returns the GVariant uint16 from the given Nix int value.
305      Type:
306        mkUint16 :: Int -> gvariant
307   */
308   mkUint16 = mkPrimitive type.uint16;
310   /* Returns the GVariant int32 from the given Nix int value.
312      Type:
313        mkInt32 :: Int -> gvariant
314   */
315   mkInt32 = v:
316     mkPrimitive type.int32 v // {
317       __toString = self: toString self.value;
318     };
320   /* Returns the GVariant uint32 from the given Nix int value.
322      Type:
323        mkUint32 :: Int -> gvariant
324   */
325   mkUint32 = mkPrimitive type.uint32;
327   /* Returns the GVariant int64 from the given Nix int value.
329      Type:
330        mkInt64 :: Int -> gvariant
331   */
332   mkInt64 = mkPrimitive type.int64;
334   /* Returns the GVariant uint64 from the given Nix int value.
336      Type:
337        mkUint64 :: Int -> gvariant
338   */
339   mkUint64 = mkPrimitive type.uint64;
341   /* Returns the GVariant double from the given Nix float value.
343      Type:
344        mkDouble :: Float -> gvariant
345   */
346   mkDouble = v:
347     mkPrimitive type.double v // {
348       __toString = self: toString self.value;
349     };