at 25.11-pre 11 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 18 concatStrings 19 escape 20 head 21 replaceStrings 22 ; 23 24 mkPrimitive = t: v: { 25 _type = "gvariant"; 26 type = t; 27 value = v; 28 __toString = self: "@${self.type} ${toString self.value}"; # https://docs.gtk.org/glib/gvariant-text.html 29 }; 30 31 type = { 32 arrayOf = t: "a${t}"; 33 maybeOf = t: "m${t}"; 34 tupleOf = ts: "(${concatStrings ts})"; 35 dictionaryEntryOf = nameType: valueType: "{${nameType}${valueType}}"; 36 string = "s"; 37 boolean = "b"; 38 uchar = "y"; 39 int16 = "n"; 40 uint16 = "q"; 41 int32 = "i"; 42 uint32 = "u"; 43 int64 = "x"; 44 uint64 = "t"; 45 double = "d"; 46 variant = "v"; 47 }; 48 49in 50rec { 51 52 inherit type; 53 54 /** 55 Check if a value is a GVariant value 56 57 # Inputs 58 59 `v` 60 61 : value to check 62 63 # Type 64 65 ``` 66 isGVariant :: Any -> Bool 67 ``` 68 */ 69 isGVariant = v: v._type or "" == "gvariant"; 70 71 intConstructors = [ 72 { 73 name = "mkInt32"; 74 type = type.int32; 75 min = -2147483648; 76 max = 2147483647; 77 } 78 { 79 name = "mkUint32"; 80 type = type.uint32; 81 min = 0; 82 max = 4294967295; 83 } 84 { 85 name = "mkInt64"; 86 type = type.int64; 87 # Nix does not support such large numbers. 88 min = null; 89 max = null; 90 } 91 { 92 name = "mkUint64"; 93 type = type.uint64; 94 min = 0; 95 # Nix does not support such large numbers. 96 max = null; 97 } 98 { 99 name = "mkInt16"; 100 type = type.int16; 101 min = -32768; 102 max = 32767; 103 } 104 { 105 name = "mkUint16"; 106 type = type.uint16; 107 min = 0; 108 max = 65535; 109 } 110 { 111 name = "mkUchar"; 112 type = type.uchar; 113 min = 0; 114 max = 255; 115 } 116 ]; 117 118 /** 119 Returns the GVariant value that most closely matches the given Nix value. 120 If no GVariant value can be found unambiguously then error is thrown. 121 122 # Inputs 123 124 `v` 125 126 : 1\. Function argument 127 128 # Type 129 130 ``` 131 mkValue :: Any -> gvariant 132 ``` 133 */ 134 mkValue = 135 v: 136 if builtins.isBool v then 137 mkBoolean v 138 else if builtins.isFloat v then 139 mkDouble v 140 else if builtins.isString v then 141 mkString v 142 else if builtins.isList v then 143 mkArray v 144 else if isGVariant v then 145 v 146 else if builtins.isInt v then 147 let 148 validConstructors = builtins.filter ( 149 { min, max, ... }: (min == null || min <= v) && (max == null || v <= max) 150 ) intConstructors; 151 in 152 throw '' 153 The GVariant type for number ${builtins.toString v} is unclear. 154 Please wrap the value with one of the following, depending on the value type in GSettings schema: 155 156 ${lib.concatMapStringsSep "\n" ( 157 { name, type, ... }: "- `lib.gvariant.${name}` for `${type}`" 158 ) validConstructors} 159 '' 160 else if builtins.isAttrs v then 161 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`." 162 else 163 throw "The GVariant type of ${builtins.typeOf v} can't be inferred."; 164 165 /** 166 Returns the GVariant array from the given type of the elements and a Nix list. 167 168 # Inputs 169 170 `elems` 171 172 : 1\. Function argument 173 174 # Type 175 176 ``` 177 mkArray :: [Any] -> gvariant 178 ``` 179 180 # Examples 181 :::{.example} 182 ## `lib.gvariant.mkArray` usage example 183 184 ```nix 185 # Creating a string array 186 lib.gvariant.mkArray [ "a" "b" "c" ] 187 ``` 188 189 ::: 190 */ 191 mkArray = 192 elems: 193 let 194 vs = map mkValue (lib.throwIf (elems == [ ]) "Please create empty array with mkEmptyArray." elems); 195 elemType = lib.throwIfNot (lib.all (t: (head vs).type == t) ( 196 map (v: v.type) vs 197 )) "Elements in a list should have same type." (head vs).type; 198 in 199 mkPrimitive (type.arrayOf elemType) vs 200 // { 201 __toString = self: "@${self.type} [${concatMapStringsSep "," toString self.value}]"; 202 }; 203 204 /** 205 Returns the GVariant array from the given empty Nix list. 206 207 # Inputs 208 209 `elemType` 210 211 : 1\. Function argument 212 213 # Type 214 215 ``` 216 mkEmptyArray :: gvariant.type -> gvariant 217 ``` 218 219 # Examples 220 :::{.example} 221 ## `lib.gvariant.mkEmptyArray` usage example 222 223 ```nix 224 # Creating an empty string array 225 lib.gvariant.mkEmptyArray (lib.gvariant.type.string) 226 ``` 227 228 ::: 229 */ 230 mkEmptyArray = 231 elemType: 232 mkPrimitive (type.arrayOf elemType) [ ] 233 // { 234 __toString = self: "@${self.type} []"; 235 }; 236 237 /** 238 Returns the GVariant variant from the given Nix value. Variants are containers 239 of different GVariant type. 240 241 # Inputs 242 243 `elem` 244 245 : 1\. Function argument 246 247 # Type 248 249 ``` 250 mkVariant :: Any -> gvariant 251 ``` 252 253 # Examples 254 :::{.example} 255 ## `lib.gvariant.mkVariant` usage example 256 257 ```nix 258 lib.gvariant.mkArray [ 259 (lib.gvariant.mkVariant "a string") 260 (lib.gvariant.mkVariant (lib.gvariant.mkInt32 1)) 261 ] 262 ``` 263 264 ::: 265 */ 266 mkVariant = 267 elem: 268 let 269 gvarElem = mkValue elem; 270 in 271 mkPrimitive type.variant gvarElem 272 // { 273 __toString = self: "<${toString self.value}>"; 274 }; 275 276 /** 277 Returns the GVariant dictionary entry from the given key and value. 278 279 # Inputs 280 281 `name` 282 283 : The key of the entry 284 285 `value` 286 287 : The value of the entry 288 289 # Type 290 291 ``` 292 mkDictionaryEntry :: String -> Any -> gvariant 293 ``` 294 295 # Examples 296 :::{.example} 297 ## `lib.gvariant.mkDictionaryEntry` usage example 298 299 ```nix 300 # A dictionary describing an Epiphanys search provider 301 [ 302 (lib.gvariant.mkDictionaryEntry "url" (lib.gvariant.mkVariant "https://duckduckgo.com/?q=%s&t=epiphany")) 303 (lib.gvariant.mkDictionaryEntry "bang" (lib.gvariant.mkVariant "!d")) 304 (lib.gvariant.mkDictionaryEntry "name" (lib.gvariant.mkVariant "DuckDuckGo")) 305 ] 306 ``` 307 308 ::: 309 */ 310 mkDictionaryEntry = 311 name: value: 312 let 313 name' = mkValue name; 314 value' = mkValue value; 315 dictionaryType = type.dictionaryEntryOf name'.type value'.type; 316 in 317 mkPrimitive dictionaryType { inherit name value; } 318 // { 319 __toString = self: "@${self.type} {${name'},${value'}}"; 320 }; 321 322 /** 323 Returns the GVariant maybe from the given element type. 324 325 # Inputs 326 327 `elemType` 328 329 : 1\. Function argument 330 331 `elem` 332 333 : 2\. Function argument 334 335 # Type 336 337 ``` 338 mkMaybe :: gvariant.type -> Any -> gvariant 339 ``` 340 */ 341 mkMaybe = 342 elemType: elem: 343 mkPrimitive (type.maybeOf elemType) elem 344 // { 345 __toString = 346 self: if self.value == null then "@${self.type} nothing" else "just ${toString self.value}"; 347 }; 348 349 /** 350 Returns the GVariant nothing from the given element type. 351 352 # Inputs 353 354 `elemType` 355 356 : 1\. Function argument 357 358 # Type 359 360 ``` 361 mkNothing :: gvariant.type -> gvariant 362 ``` 363 */ 364 mkNothing = elemType: mkMaybe elemType null; 365 366 /** 367 Returns the GVariant just from the given Nix value. 368 369 # Inputs 370 371 `elem` 372 373 : 1\. Function argument 374 375 # Type 376 377 ``` 378 mkJust :: Any -> gvariant 379 ``` 380 */ 381 mkJust = 382 elem: 383 let 384 gvarElem = mkValue elem; 385 in 386 mkMaybe gvarElem.type gvarElem; 387 388 /** 389 Returns the GVariant tuple from the given Nix list. 390 391 # Inputs 392 393 `elems` 394 395 : 1\. Function argument 396 397 # Type 398 399 ``` 400 mkTuple :: [Any] -> gvariant 401 ``` 402 */ 403 mkTuple = 404 elems: 405 let 406 gvarElems = map mkValue elems; 407 tupleType = type.tupleOf (map (e: e.type) gvarElems); 408 in 409 mkPrimitive tupleType gvarElems 410 // { 411 __toString = self: "@${self.type} (${concatMapStringsSep "," toString self.value})"; 412 }; 413 414 /** 415 Returns the GVariant boolean from the given Nix bool value. 416 417 # Inputs 418 419 `v` 420 421 : 1\. Function argument 422 423 # Type 424 425 ``` 426 mkBoolean :: Bool -> gvariant 427 ``` 428 */ 429 mkBoolean = 430 v: 431 mkPrimitive type.boolean v 432 // { 433 __toString = self: if self.value then "true" else "false"; 434 }; 435 436 /** 437 Returns the GVariant string from the given Nix string value. 438 439 # Inputs 440 441 `v` 442 443 : 1\. Function argument 444 445 # Type 446 447 ``` 448 mkString :: String -> gvariant 449 ``` 450 */ 451 mkString = 452 v: 453 let 454 sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s); 455 in 456 mkPrimitive type.string v 457 // { 458 __toString = self: "'${sanitize self.value}'"; 459 }; 460 461 /** 462 Returns the GVariant object path from the given Nix string value. 463 464 # Inputs 465 466 `v` 467 468 : 1\. Function argument 469 470 # Type 471 472 ``` 473 mkObjectpath :: String -> gvariant 474 ``` 475 */ 476 mkObjectpath = 477 v: 478 mkPrimitive type.string v 479 // { 480 __toString = self: "objectpath '${escape [ "'" ] self.value}'"; 481 }; 482 483 /** 484 Returns the GVariant uchar from the given Nix int value. 485 486 # Type 487 488 ``` 489 mkUchar :: Int -> gvariant 490 ``` 491 */ 492 mkUchar = mkPrimitive type.uchar; 493 494 /** 495 Returns the GVariant int16 from the given Nix int value. 496 497 # Type 498 499 ``` 500 mkInt16 :: Int -> gvariant 501 ``` 502 */ 503 mkInt16 = mkPrimitive type.int16; 504 505 /** 506 Returns the GVariant uint16 from the given Nix int value. 507 508 # Type 509 510 ``` 511 mkUint16 :: Int -> gvariant 512 ``` 513 */ 514 mkUint16 = mkPrimitive type.uint16; 515 516 /** 517 Returns the GVariant int32 from the given Nix int value. 518 519 # Inputs 520 521 `v` 522 523 : 1\. Function argument 524 525 # Type 526 527 ``` 528 mkInt32 :: Int -> gvariant 529 ``` 530 */ 531 mkInt32 = 532 v: 533 mkPrimitive type.int32 v 534 // { 535 __toString = self: toString self.value; 536 }; 537 538 /** 539 Returns the GVariant uint32 from the given Nix int value. 540 541 # Type 542 543 ``` 544 mkUint32 :: Int -> gvariant 545 ``` 546 */ 547 mkUint32 = mkPrimitive type.uint32; 548 549 /** 550 Returns the GVariant int64 from the given Nix int value. 551 552 # Type 553 554 ``` 555 mkInt64 :: Int -> gvariant 556 ``` 557 */ 558 mkInt64 = mkPrimitive type.int64; 559 560 /** 561 Returns the GVariant uint64 from the given Nix int value. 562 563 # Type 564 565 ``` 566 mkUint64 :: Int -> gvariant 567 ``` 568 */ 569 mkUint64 = mkPrimitive type.uint64; 570 571 /** 572 Returns the GVariant double from the given Nix float value. 573 574 # Inputs 575 576 `v` 577 578 : 1\. Function argument 579 580 # Type 581 582 ``` 583 mkDouble :: Float -> gvariant 584 ``` 585 */ 586 mkDouble = 587 v: 588 mkPrimitive type.double v 589 // { 590 __toString = self: toString self.value; 591 }; 592}