at 23.11-beta 7.6 kB view raw
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. 4 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*/ 10 11# This file is based on https://github.com/nix-community/home-manager 12# Copyright (c) 2017-2022 Home Manager contributors 13{ lib }: 14 15let 16 inherit (lib) 17 concatMapStringsSep concatStrings escape head replaceStrings; 18 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 }; 25 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 }; 43 44 /* Check if a value is a GVariant value 45 46 Type: 47 isGVariant :: Any -> Bool 48 */ 49 isGVariant = v: v._type or "" == "gvariant"; 50 51in 52rec { 53 54 inherit type isGVariant; 55 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. 58 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."; 75 76 /* Returns the GVariant array from the given type of the elements and a Nix list. 77 78 Type: 79 mkArray :: [Any] -> gvariant 80 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 }; 96 97 /* Returns the GVariant array from the given empty Nix list. 98 99 Type: 100 mkEmptyArray :: gvariant.type -> gvariant 101 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 }; 109 110 111 /* Returns the GVariant variant from the given Nix value. Variants are containers 112 of different GVariant type. 113 114 Type: 115 mkVariant :: Any -> gvariant 116 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 }; 128 129 /* Returns the GVariant dictionary entry from the given key and value. 130 131 Type: 132 mkDictionaryEntry :: String -> Any -> gvariant 133 134 Example: 135 # A dictionary describing an Epiphanys 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 }; 155 156 /* Returns the GVariant maybe from the given element type. 157 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 }; 169 170 /* Returns the GVariant nothing from the given element type. 171 172 Type: 173 mkNothing :: gvariant.type -> gvariant 174 */ 175 mkNothing = elemType: mkMaybe elemType null; 176 177 /* Returns the GVariant just from the given Nix value. 178 179 Type: 180 mkJust :: Any -> gvariant 181 */ 182 mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem; 183 184 /* Returns the GVariant tuple from the given Nix list. 185 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 }; 198 199 /* Returns the GVariant boolean from the given Nix bool value. 200 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 }; 208 209 /* Returns the GVariant string from the given Nix string value. 210 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 }; 219 220 /* Returns the GVariant object path from the given Nix string value. 221 222 Type: 223 mkObjectpath :: String -> gvariant 224 */ 225 mkObjectpath = v: 226 mkPrimitive type.string v // { 227 __toString = self: "objectpath '${escape [ "'" ] self.value}'"; 228 }; 229 230 /* Returns the GVariant uchar from the given Nix int value. 231 232 Type: 233 mkUchar :: Int -> gvariant 234 */ 235 mkUchar = mkPrimitive type.uchar; 236 237 /* Returns the GVariant int16 from the given Nix int value. 238 239 Type: 240 mkInt16 :: Int -> gvariant 241 */ 242 mkInt16 = mkPrimitive type.int16; 243 244 /* Returns the GVariant uint16 from the given Nix int value. 245 246 Type: 247 mkUint16 :: Int -> gvariant 248 */ 249 mkUint16 = mkPrimitive type.uint16; 250 251 /* Returns the GVariant int32 from the given Nix int value. 252 253 Type: 254 mkInt32 :: Int -> gvariant 255 */ 256 mkInt32 = v: 257 mkPrimitive type.int32 v // { 258 __toString = self: toString self.value; 259 }; 260 261 /* Returns the GVariant uint32 from the given Nix int value. 262 263 Type: 264 mkUint32 :: Int -> gvariant 265 */ 266 mkUint32 = mkPrimitive type.uint32; 267 268 /* Returns the GVariant int64 from the given Nix int value. 269 270 Type: 271 mkInt64 :: Int -> gvariant 272 */ 273 mkInt64 = mkPrimitive type.int64; 274 275 /* Returns the GVariant uint64 from the given Nix int value. 276 277 Type: 278 mkUint64 :: Int -> gvariant 279 */ 280 mkUint64 = mkPrimitive type.uint64; 281 282 /* Returns the GVariant double from the given Nix float value. 283 284 Type: 285 mkDouble :: Float -> gvariant 286 */ 287 mkDouble = v: 288 mkPrimitive type.double v // { 289 __toString = self: toString self.value; 290 }; 291}