Merge pull request #306723 from alyssais/patchutils-musl
[NixPkgs.git] / lib / gvariant.nix
blob708213224d3e35fac34de148f12202c383890e73
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   /* Returns the GVariant value that most closely matches the given Nix value.
57      If no GVariant value can be found unambiguously then error is thrown.
59      Type:
60        mkValue :: Any -> gvariant
61   */
62   mkValue = v:
63     if builtins.isBool v then
64       mkBoolean v
65     else if builtins.isFloat v then
66       mkDouble v
67     else if builtins.isString v then
68       mkString v
69     else if builtins.isList v then
70       mkArray v
71     else if isGVariant v then
72       v
73     else
74       throw "The GVariant type of ${v} can't be inferred.";
76   /* Returns the GVariant array from the given type of the elements and a Nix list.
78      Type:
79        mkArray :: [Any] -> gvariant
81      Example:
82        # Creating a string array
83        lib.gvariant.mkArray [ "a" "b" "c" ]
84   */
85   mkArray = elems:
86     let
87       vs = map mkValue (lib.throwIf (elems == [ ]) "Please create empty array with mkEmptyArray." elems);
88       elemType = lib.throwIfNot (lib.all (t: (head vs).type == t) (map (v: v.type) vs))
89         "Elements in a list should have same type."
90         (head vs).type;
91     in
92     mkPrimitive (type.arrayOf elemType) vs // {
93       __toString = self:
94         "@${self.type} [${concatMapStringsSep "," toString self.value}]";
95     };
97   /* Returns the GVariant array from the given empty Nix list.
99      Type:
100        mkEmptyArray :: gvariant.type -> gvariant
102      Example:
103        # Creating an empty string array
104        lib.gvariant.mkEmptyArray (lib.gvariant.type.string)
105   */
106   mkEmptyArray = elemType: mkPrimitive (type.arrayOf elemType) [ ] // {
107     __toString = self: "@${self.type} []";
108   };
111   /* Returns the GVariant variant from the given Nix value. Variants are containers
112      of different GVariant type.
114      Type:
115        mkVariant :: Any -> gvariant
117      Example:
118        lib.gvariant.mkArray [
119          (lib.gvariant.mkVariant "a string")
120          (lib.gvariant.mkVariant (lib.gvariant.mkInt32 1))
121        ]
122   */
123   mkVariant = elem:
124     let gvarElem = mkValue elem;
125     in mkPrimitive type.variant gvarElem // {
126       __toString = self: "<${toString self.value}>";
127     };
129   /* Returns the GVariant dictionary entry from the given key and value.
131      Type:
132        mkDictionaryEntry :: String -> Any -> gvariant
134      Example:
135        # A dictionary describing an Epiphany’s search provider
136        [
137          (lib.gvariant.mkDictionaryEntry "url" (lib.gvariant.mkVariant "https://duckduckgo.com/?q=%s&t=epiphany"))
138          (lib.gvariant.mkDictionaryEntry "bang" (lib.gvariant.mkVariant "!d"))
139          (lib.gvariant.mkDictionaryEntry "name" (lib.gvariant.mkVariant "DuckDuckGo"))
140        ]
141   */
142   mkDictionaryEntry =
143     # The key of the entry
144     name:
145     # The value of the entry
146     value:
147     let
148       name' = mkValue name;
149       value' = mkValue value;
150       dictionaryType = type.dictionaryEntryOf name'.type value'.type;
151     in
152     mkPrimitive dictionaryType { inherit name value; } // {
153       __toString = self: "@${self.type} {${name'},${value'}}";
154     };
156   /* Returns the GVariant maybe from the given element type.
158      Type:
159        mkMaybe :: gvariant.type -> Any -> gvariant
160   */
161   mkMaybe = elemType: elem:
162     mkPrimitive (type.maybeOf elemType) elem // {
163       __toString = self:
164         if self.value == null then
165           "@${self.type} nothing"
166         else
167           "just ${toString self.value}";
168     };
170   /* Returns the GVariant nothing from the given element type.
172      Type:
173        mkNothing :: gvariant.type -> gvariant
174   */
175   mkNothing = elemType: mkMaybe elemType null;
177   /* Returns the GVariant just from the given Nix value.
179      Type:
180        mkJust :: Any -> gvariant
181   */
182   mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem;
184   /* Returns the GVariant tuple from the given Nix list.
186      Type:
187        mkTuple :: [Any] -> gvariant
188   */
189   mkTuple = elems:
190     let
191       gvarElems = map mkValue elems;
192       tupleType = type.tupleOf (map (e: e.type) gvarElems);
193     in
194     mkPrimitive tupleType gvarElems // {
195       __toString = self:
196         "@${self.type} (${concatMapStringsSep "," toString self.value})";
197     };
199   /* Returns the GVariant boolean from the given Nix bool value.
201      Type:
202        mkBoolean :: Bool -> gvariant
203   */
204   mkBoolean = v:
205     mkPrimitive type.boolean v // {
206       __toString = self: if self.value then "true" else "false";
207     };
209   /* Returns the GVariant string from the given Nix string value.
211      Type:
212        mkString :: String -> gvariant
213   */
214   mkString = v:
215     let sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s);
216     in mkPrimitive type.string v // {
217       __toString = self: "'${sanitize self.value}'";
218     };
220   /* Returns the GVariant object path from the given Nix string value.
222      Type:
223        mkObjectpath :: String -> gvariant
224   */
225   mkObjectpath = v:
226     mkPrimitive type.string v // {
227       __toString = self: "objectpath '${escape [ "'" ] self.value}'";
228     };
230   /* Returns the GVariant uchar from the given Nix int value.
232      Type:
233        mkUchar :: Int -> gvariant
234   */
235   mkUchar = mkPrimitive type.uchar;
237   /* Returns the GVariant int16 from the given Nix int value.
239      Type:
240        mkInt16 :: Int -> gvariant
241   */
242   mkInt16 = mkPrimitive type.int16;
244   /* Returns the GVariant uint16 from the given Nix int value.
246      Type:
247        mkUint16 :: Int -> gvariant
248   */
249   mkUint16 = mkPrimitive type.uint16;
251   /* Returns the GVariant int32 from the given Nix int value.
253      Type:
254        mkInt32 :: Int -> gvariant
255   */
256   mkInt32 = v:
257     mkPrimitive type.int32 v // {
258       __toString = self: toString self.value;
259     };
261   /* Returns the GVariant uint32 from the given Nix int value.
263      Type:
264        mkUint32 :: Int -> gvariant
265   */
266   mkUint32 = mkPrimitive type.uint32;
268   /* Returns the GVariant int64 from the given Nix int value.
270      Type:
271        mkInt64 :: Int -> gvariant
272   */
273   mkInt64 = mkPrimitive type.int64;
275   /* Returns the GVariant uint64 from the given Nix int value.
277      Type:
278        mkUint64 :: Int -> gvariant
279   */
280   mkUint64 = mkPrimitive type.uint64;
282   /* Returns the GVariant double from the given Nix float value.
284      Type:
285        mkDouble :: Float -> gvariant
286   */
287   mkDouble = v:
288     mkPrimitive type.double v // {
289       __toString = self: toString self.value;
290     };