at master 23 kB view raw
1{ lib }: 2 3let 4 inherit (lib.trivial) 5 isFunction 6 isInt 7 functionArgs 8 pathExists 9 release 10 setFunctionArgs 11 toBaseDigits 12 version 13 versionSuffix 14 warn 15 ; 16 inherit (lib) 17 isString 18 ; 19in 20{ 21 22 ## Simple (higher order) functions 23 24 /** 25 The identity function 26 For when you need a function that does nothing. 27 28 # Inputs 29 30 `x` 31 32 : The value to return 33 34 # Type 35 36 ``` 37 id :: a -> a 38 ``` 39 */ 40 id = x: x; 41 42 /** 43 The constant function 44 45 Ignores the second argument. If called with only one argument, 46 constructs a function that always returns a static value. 47 48 # Inputs 49 50 `x` 51 52 : Value to return 53 54 `y` 55 56 : Value to ignore 57 58 # Type 59 60 ``` 61 const :: a -> b -> a 62 ``` 63 64 # Examples 65 :::{.example} 66 ## `lib.trivial.const` usage example 67 68 ```nix 69 let f = const 5; in f 10 70 => 5 71 ``` 72 73 ::: 74 */ 75 const = x: y: x; 76 77 /** 78 Pipes a value through a list of functions, left to right. 79 80 # Inputs 81 82 `value` 83 84 : Value to start piping. 85 86 `fns` 87 88 : List of functions to apply sequentially. 89 90 # Type 91 92 ``` 93 pipe :: a -> [<functions>] -> <return type of last function> 94 ``` 95 96 # Examples 97 :::{.example} 98 ## `lib.trivial.pipe` usage example 99 100 ```nix 101 pipe 2 [ 102 (x: x + 2) # 2 + 2 = 4 103 (x: x * 2) # 4 * 2 = 8 104 ] 105 => 8 106 107 # ideal to do text transformations 108 pipe [ "a/b" "a/c" ] [ 109 110 # create the cp command 111 (map (file: ''cp "${src}/${file}" $out\n'')) 112 113 # concatenate all commands into one string 114 lib.concatStrings 115 116 # make that string into a nix derivation 117 (pkgs.runCommand "copy-to-out" {}) 118 119 ] 120 => <drv which copies all files to $out> 121 122 The output type of each function has to be the input type 123 of the next function, and the last function returns the 124 final value. 125 ``` 126 127 ::: 128 */ 129 pipe = builtins.foldl' (x: f: f x); 130 131 # note please don’t add a function like `compose = flip pipe`. 132 # This would confuse users, because the order of the functions 133 # in the list is not clear. With pipe, it’s obvious that it 134 # goes first-to-last. With `compose`, not so much. 135 136 ## Named versions corresponding to some builtin operators. 137 138 /** 139 Concatenate two lists 140 141 # Inputs 142 143 `x` 144 145 : 1\. Function argument 146 147 `y` 148 149 : 2\. Function argument 150 151 # Type 152 153 ``` 154 concat :: [a] -> [a] -> [a] 155 ``` 156 157 # Examples 158 :::{.example} 159 ## `lib.trivial.concat` usage example 160 161 ```nix 162 concat [ 1 2 ] [ 3 4 ] 163 => [ 1 2 3 4 ] 164 ``` 165 166 ::: 167 */ 168 concat = x: y: x ++ y; 169 170 /** 171 boolean or 172 173 # Inputs 174 175 `x` 176 177 : 1\. Function argument 178 179 `y` 180 181 : 2\. Function argument 182 */ 183 or = x: y: x || y; 184 185 /** 186 boolean and 187 188 # Inputs 189 190 `x` 191 192 : 1\. Function argument 193 194 `y` 195 196 : 2\. Function argument 197 */ 198 and = x: y: x && y; 199 200 /** 201 boolean exclusive or 202 203 # Inputs 204 205 `x` 206 207 : 1\. Function argument 208 209 `y` 210 211 : 2\. Function argument 212 */ 213 # We explicitly invert the arguments purely as a type assertion. 214 # This is invariant under XOR, so it does not affect the result. 215 xor = x: y: (!x) != (!y); 216 217 /** 218 bitwise not 219 */ 220 bitNot = builtins.sub (-1); 221 222 /** 223 Convert a boolean to a string. 224 225 This function uses the strings "true" and "false" to represent 226 boolean values. Calling `toString` on a bool instead returns "1" 227 and "" (sic!). 228 229 # Inputs 230 231 `b` 232 233 : 1\. Function argument 234 235 # Type 236 237 ``` 238 boolToString :: bool -> string 239 ``` 240 */ 241 boolToString = b: if b then "true" else "false"; 242 243 /** 244 Converts a boolean to a string. 245 246 This function uses the strings "yes" and "no" to represent 247 boolean values. 248 249 # Inputs 250 251 `b` 252 253 : The boolean to convert 254 255 # Type 256 257 ``` 258 boolToYesNo :: bool -> string 259 ``` 260 */ 261 boolToYesNo = b: if b then "yes" else "no"; 262 263 /** 264 Merge two attribute sets shallowly, right side trumps left 265 266 mergeAttrs :: attrs -> attrs -> attrs 267 268 # Inputs 269 270 `x` 271 272 : Left attribute set 273 274 `y` 275 276 : Right attribute set (higher precedence for equal keys) 277 278 # Examples 279 :::{.example} 280 ## `lib.trivial.mergeAttrs` usage example 281 282 ```nix 283 mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; } 284 => { a = 1; b = 3; c = 4; } 285 ``` 286 287 ::: 288 */ 289 mergeAttrs = x: y: x // y; 290 291 /** 292 Flip the order of the arguments of a binary function. 293 294 # Inputs 295 296 `f` 297 298 : 1\. Function argument 299 300 `a` 301 302 : 2\. Function argument 303 304 `b` 305 306 : 3\. Function argument 307 308 # Type 309 310 ``` 311 flip :: (a -> b -> c) -> (b -> a -> c) 312 ``` 313 314 # Examples 315 :::{.example} 316 ## `lib.trivial.flip` usage example 317 318 ```nix 319 flip concat [1] [2] 320 => [ 2 1 ] 321 ``` 322 323 ::: 324 */ 325 flip = 326 f: a: b: 327 f b a; 328 329 /** 330 Return `maybeValue` if not null, otherwise return `default`. 331 332 # Inputs 333 334 `default` 335 336 : 1\. Function argument 337 338 `maybeValue` 339 340 : 2\. Function argument 341 342 # Examples 343 :::{.example} 344 ## `lib.trivial.defaultTo` usage example 345 346 ```nix 347 defaultTo "default" null 348 => "default" 349 defaultTo "default" "foo" 350 => "foo" 351 defaultTo "default" false 352 => false 353 ``` 354 355 ::: 356 */ 357 defaultTo = default: maybeValue: if maybeValue != null then maybeValue else default; 358 359 /** 360 Apply function if the supplied argument is non-null. 361 362 # Inputs 363 364 `f` 365 366 : Function to call 367 368 `a` 369 370 : Argument to check for null before passing it to `f` 371 372 # Examples 373 :::{.example} 374 ## `lib.trivial.mapNullable` usage example 375 376 ```nix 377 mapNullable (x: x+1) null 378 => null 379 mapNullable (x: x+1) 22 380 => 23 381 ``` 382 383 ::: 384 */ 385 mapNullable = f: a: if a == null then a else f a; 386 387 # Pull in some builtins not included elsewhere. 388 inherit (builtins) 389 pathExists 390 readFile 391 isBool 392 isInt 393 isFloat 394 add 395 sub 396 lessThan 397 seq 398 deepSeq 399 genericClosure 400 bitAnd 401 bitOr 402 bitXor 403 ; 404 405 ## nixpkgs version strings 406 407 /** 408 Returns the current full nixpkgs version number. 409 */ 410 version = release + versionSuffix; 411 412 /** 413 Returns the current nixpkgs release number as string. 414 */ 415 release = lib.strings.fileContents ./.version; 416 417 /** 418 The latest release that is supported, at the time of release branch-off, 419 if applicable. 420 421 Ideally, out-of-tree modules should be able to evaluate cleanly with all 422 supported Nixpkgs versions (master, release and old release until EOL). 423 So if possible, deprecation warnings should take effect only when all 424 out-of-tree expressions/libs/modules can upgrade to the new way without 425 losing support for supported Nixpkgs versions. 426 427 This release number allows deprecation warnings to be implemented such that 428 they take effect as soon as the oldest release reaches end of life. 429 */ 430 oldestSupportedRelease = 431 # Update on master only. Do not backport. 432 2505; 433 434 /** 435 Whether a feature is supported in all supported releases (at the time of 436 release branch-off, if applicable). See `oldestSupportedRelease`. 437 438 # Inputs 439 440 `release` 441 442 : Release number of feature introduction as an integer, e.g. 2111 for 21.11. 443 Set it to the upcoming release, matching the nixpkgs/.version file. 444 */ 445 isInOldestRelease = 446 lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2411) 447 "lib.isInOldestRelease is deprecated. Use lib.oldestSupportedReleaseIsAtLeast instead." 448 lib.oldestSupportedReleaseIsAtLeast; 449 450 /** 451 Alias for `isInOldestRelease` introduced in 24.11. 452 Use `isInOldestRelease` in expressions outside of Nixpkgs for greater compatibility. 453 */ 454 oldestSupportedReleaseIsAtLeast = release: release <= lib.trivial.oldestSupportedRelease; 455 456 /** 457 Returns the current nixpkgs release code name. 458 459 On each release the first letter is bumped and a new animal is chosen 460 starting with that new letter. 461 */ 462 codeName = "Xantusia"; 463 464 /** 465 Returns the current nixpkgs version suffix as string. 466 */ 467 versionSuffix = 468 let 469 suffixFile = ../.version-suffix; 470 in 471 if pathExists suffixFile then lib.strings.fileContents suffixFile else "pre-git"; 472 473 /** 474 Attempts to return the the current revision of nixpkgs and 475 returns the supplied default value otherwise. 476 477 # Inputs 478 479 `default` 480 481 : Default value to return if revision can not be determined 482 483 # Type 484 485 ``` 486 revisionWithDefault :: string -> string 487 ``` 488 */ 489 revisionWithDefault = 490 default: 491 let 492 revisionFile = "${toString ./..}/.git-revision"; 493 gitRepo = "${toString ./..}/.git"; 494 in 495 if lib.pathIsGitRepo gitRepo then 496 lib.commitIdFromGitRepo gitRepo 497 else if lib.pathExists revisionFile then 498 lib.fileContents revisionFile 499 else 500 default; 501 502 nixpkgsVersion = warn "lib.nixpkgsVersion is a deprecated alias of lib.version." version; 503 504 /** 505 Determine whether the function is being called from inside a Nix 506 shell. 507 508 # Type 509 510 ``` 511 inNixShell :: bool 512 ``` 513 */ 514 inNixShell = builtins.getEnv "IN_NIX_SHELL" != ""; 515 516 /** 517 Determine whether the function is being called from inside pure-eval mode 518 by seeing whether `builtins` contains `currentSystem`. If not, we must be in 519 pure-eval mode. 520 521 # Type 522 523 ``` 524 inPureEvalMode :: bool 525 ``` 526 */ 527 inPureEvalMode = !builtins ? currentSystem; 528 529 ## Integer operations 530 531 /** 532 Return minimum of two numbers. 533 534 # Inputs 535 536 `x` 537 538 : 1\. Function argument 539 540 `y` 541 542 : 2\. Function argument 543 */ 544 min = x: y: if x < y then x else y; 545 546 /** 547 Return maximum of two numbers. 548 549 # Inputs 550 551 `x` 552 553 : 1\. Function argument 554 555 `y` 556 557 : 2\. Function argument 558 */ 559 max = x: y: if x > y then x else y; 560 561 /** 562 Integer modulus 563 564 # Inputs 565 566 `base` 567 568 : 1\. Function argument 569 570 `int` 571 572 : 2\. Function argument 573 574 # Examples 575 :::{.example} 576 ## `lib.trivial.mod` usage example 577 578 ```nix 579 mod 11 10 580 => 1 581 mod 1 10 582 => 1 583 ``` 584 585 ::: 586 */ 587 mod = base: int: base - (int * (builtins.div base int)); 588 589 ## Comparisons 590 591 /** 592 C-style comparisons 593 594 a < b, compare a b => -1 595 a == b, compare a b => 0 596 a > b, compare a b => 1 597 598 # Inputs 599 600 `a` 601 602 : 1\. Function argument 603 604 `b` 605 606 : 2\. Function argument 607 */ 608 compare = 609 a: b: 610 if a < b then 611 -1 612 else if a > b then 613 1 614 else 615 0; 616 617 /** 618 Split type into two subtypes by predicate `p`, take all elements 619 of the first subtype to be less than all the elements of the 620 second subtype, compare elements of a single subtype with `yes` 621 and `no` respectively. 622 623 # Inputs 624 625 `p` 626 627 : Predicate 628 629 `yes` 630 631 : Comparison function if predicate holds for both values 632 633 `no` 634 635 : Comparison function if predicate holds for neither value 636 637 `a` 638 639 : First value to compare 640 641 `b` 642 643 : Second value to compare 644 645 # Type 646 647 ``` 648 (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int) 649 ``` 650 651 # Examples 652 :::{.example} 653 ## `lib.trivial.splitByAndCompare` usage example 654 655 ```nix 656 let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in 657 658 cmp "a" "z" => -1 659 cmp "fooa" "fooz" => -1 660 661 cmp "f" "a" => 1 662 cmp "fooa" "a" => -1 663 # while 664 compare "fooa" "a" => 1 665 ``` 666 667 ::: 668 */ 669 splitByAndCompare = 670 p: yes: no: a: b: 671 if p a then 672 if p b then yes a b else -1 673 else if p b then 674 1 675 else 676 no a b; 677 678 /** 679 Reads a JSON file. 680 681 # Examples 682 :::{.example} 683 ## `lib.trivial.importJSON` usage example 684 685 example.json 686 ```json 687 { 688 "title": "Example JSON", 689 "hello": { 690 "world": "foo", 691 "bar": { 692 "foobar": true 693 } 694 } 695 } 696 ``` 697 698 ```nix 699 importJSON ./example.json 700 => { 701 title = "Example JSON"; 702 hello = { 703 world = "foo"; 704 bar = { 705 foobar = true; 706 }; 707 }; 708 } 709 ``` 710 711 ::: 712 713 # Inputs 714 715 `path` 716 717 : 1\. Function argument 718 719 # Type 720 721 ``` 722 importJSON :: path -> any 723 ``` 724 */ 725 importJSON = path: builtins.fromJSON (builtins.readFile path); 726 727 /** 728 Reads a TOML file. 729 730 # Examples 731 :::{.example} 732 ## `lib.trivial.importTOML` usage example 733 734 example.toml 735 ```toml 736 title = "TOML Example" 737 738 [hello] 739 world = "foo" 740 741 [hello.bar] 742 foobar = true 743 ``` 744 745 ```nix 746 importTOML ./example.toml 747 => { 748 title = "TOML Example"; 749 hello = { 750 world = "foo"; 751 bar = { 752 foobar = true; 753 }; 754 }; 755 } 756 ``` 757 758 ::: 759 760 # Inputs 761 762 `path` 763 764 : 1\. Function argument 765 766 # Type 767 768 ``` 769 importTOML :: path -> any 770 ``` 771 */ 772 importTOML = path: fromTOML (builtins.readFile path); 773 774 /** 775 `warn` *`message`* *`value`* 776 777 Print a warning before returning the second argument. 778 779 See [`builtins.warn`](https://nix.dev/manual/nix/latest/language/builtins.html#builtins-warn) (Nix >= 2.23). 780 On older versions, the Nix 2.23 behavior is emulated with [`builtins.trace`](https://nix.dev/manual/nix/latest/language/builtins.html#builtins-warn), including the [`NIX_ABORT_ON_WARN`](https://nix.dev/manual/nix/latest/command-ref/conf-file#conf-abort-on-warn) behavior, but not the `nix.conf` setting or command line option. 781 782 # Inputs 783 784 *`message`* (String) 785 786 : Warning message to print before evaluating *`value`*. 787 788 *`value`* (any value) 789 790 : Value to return as-is. 791 792 # Type 793 794 ``` 795 String -> a -> a 796 ``` 797 */ 798 warn = 799 # Since Nix 2.23, https://github.com/NixOS/nix/pull/10592 800 builtins.warn or ( 801 let 802 mustAbort = lib.elem (builtins.getEnv "NIX_ABORT_ON_WARN") [ 803 "1" 804 "true" 805 "yes" 806 ]; 807 in 808 # Do not eta reduce v, so that we have the same strictness as `builtins.warn`. 809 msg: v: 810 # `builtins.warn` requires a string message, so we enforce that in our implementation, so that callers aren't accidentally incompatible with newer Nix versions. 811 assert isString msg; 812 if mustAbort then 813 builtins.trace "evaluation warning: ${msg}" ( 814 abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors." 815 ) 816 else 817 builtins.trace "evaluation warning: ${msg}" v 818 ); 819 820 /** 821 `warnIf` *`condition`* *`message`* *`value`* 822 823 Like `warn`, but only warn when the first argument is `true`. 824 825 # Inputs 826 827 *`condition`* (Boolean) 828 829 : `true` to trigger the warning before continuing with *`value`*. 830 831 *`message`* (String) 832 833 : Warning message to print before evaluating 834 835 *`value`* (any value) 836 837 : Value to return as-is. 838 839 # Type 840 841 ``` 842 Bool -> String -> a -> a 843 ``` 844 */ 845 warnIf = cond: msg: if cond then warn msg else x: x; 846 847 /** 848 `warnIfNot` *`condition`* *`message`* *`value`* 849 850 Like `warnIf`, but negated: warn if the first argument is `false`. 851 852 # Inputs 853 854 *`condition`* 855 856 : `false` to trigger the warning before continuing with `val`. 857 858 *`message`* 859 860 : Warning message to print before evaluating *`value`*. 861 862 *`value`* 863 864 : Value to return as-is. 865 866 # Type 867 868 ``` 869 Boolean -> String -> a -> a 870 ``` 871 */ 872 warnIfNot = cond: msg: if cond then x: x else warn msg; 873 874 /** 875 Like the `assert b; e` expression, but with a custom error message and 876 without the semicolon. 877 878 If true, return the identity function, `r: r`. 879 880 If false, throw the error message. 881 882 Calls can be juxtaposed using function application, as `(r: r) a = a`, so 883 `(r: r) (r: r) a = a`, and so forth. 884 885 # Inputs 886 887 `cond` 888 889 : 1\. Function argument 890 891 `msg` 892 893 : 2\. Function argument 894 895 # Type 896 897 ``` 898 bool -> string -> a -> a 899 ``` 900 901 # Examples 902 :::{.example} 903 ## `lib.trivial.throwIfNot` usage example 904 905 ```nix 906 throwIfNot (lib.isList overlays) "The overlays argument to nixpkgs must be a list." 907 lib.foldr (x: throwIfNot (lib.isFunction x) "All overlays passed to nixpkgs must be functions.") (r: r) overlays 908 pkgs 909 ``` 910 911 ::: 912 */ 913 throwIfNot = cond: msg: if cond then x: x else throw msg; 914 915 /** 916 Like throwIfNot, but negated (throw if the first argument is `true`). 917 918 # Inputs 919 920 `cond` 921 922 : 1\. Function argument 923 924 `msg` 925 926 : 2\. Function argument 927 928 # Type 929 930 ``` 931 bool -> string -> a -> a 932 ``` 933 */ 934 throwIf = cond: msg: if cond then throw msg else x: x; 935 936 /** 937 Check if the elements in a list are valid values from a enum, returning the identity function, or throwing an error message otherwise. 938 939 # Inputs 940 941 `msg` 942 943 : 1\. Function argument 944 945 `valid` 946 947 : 2\. Function argument 948 949 `given` 950 951 : 3\. Function argument 952 953 # Type 954 955 ``` 956 String -> List ComparableVal -> List ComparableVal -> a -> a 957 ``` 958 959 # Examples 960 :::{.example} 961 ## `lib.trivial.checkListOfEnum` usage example 962 963 ```nix 964 let colorVariants = ["bright" "dark" "black"] 965 in checkListOfEnum "color variants" [ "standard" "light" "dark" ] colorVariants; 966 => 967 error: color variants: bright, black unexpected; valid ones: standard, light, dark 968 ``` 969 970 ::: 971 */ 972 checkListOfEnum = 973 msg: valid: given: 974 let 975 unexpected = lib.subtractLists valid given; 976 in 977 lib.throwIfNot (unexpected == [ ]) 978 "${msg}: ${builtins.concatStringsSep ", " (map toString unexpected)} unexpected; valid ones: ${builtins.concatStringsSep ", " (map toString valid)}"; 979 980 info = msg: builtins.trace "INFO: ${msg}"; 981 982 showWarnings = warnings: res: lib.foldr (w: x: warn w x) res warnings; 983 984 ## Function annotations 985 986 /** 987 Add metadata about expected function arguments to a function. 988 The metadata should match the format given by 989 builtins.functionArgs, i.e. a set from expected argument to a bool 990 representing whether that argument has a default or not. 991 setFunctionArgs : (a b) Map String Bool (a b) 992 993 This function is necessary because you can't dynamically create a 994 function of the { a, b ? foo, ... }: format, but some facilities 995 like callPackage expect to be able to query expected arguments. 996 997 # Inputs 998 999 `f` 1000 1001 : 1\. Function argument 1002 1003 `args` 1004 1005 : 2\. Function argument 1006 */ 1007 setFunctionArgs = f: args: { 1008 # TODO: Should we add call-time "type" checking like built in? 1009 __functor = self: f; 1010 __functionArgs = args; 1011 }; 1012 1013 /** 1014 Extract the expected function arguments from a function. 1015 This works both with nix-native { a, b ? foo, ... }: style 1016 functions and functions with args set with 'setFunctionArgs'. It 1017 has the same return type and semantics as builtins.functionArgs. 1018 setFunctionArgs : (a b) Map String Bool. 1019 1020 # Inputs 1021 1022 `f` 1023 1024 : 1\. Function argument 1025 */ 1026 functionArgs = 1027 f: 1028 if f ? __functor then 1029 f.__functionArgs or (functionArgs (f.__functor f)) 1030 else 1031 builtins.functionArgs f; 1032 1033 /** 1034 Check whether something is a function or something 1035 annotated with function args. 1036 1037 # Inputs 1038 1039 `f` 1040 1041 : 1\. Function argument 1042 */ 1043 isFunction = f: builtins.isFunction f || (f ? __functor && isFunction (f.__functor f)); 1044 1045 /** 1046 `mirrorFunctionArgs f g` creates a new function `g'` with the same behavior as `g` (`g' x == g x`) 1047 but its function arguments mirroring `f` (`lib.functionArgs g' == lib.functionArgs f`). 1048 1049 # Inputs 1050 1051 `f` 1052 1053 : Function to provide the argument metadata 1054 1055 `g` 1056 1057 : Function to set the argument metadata to 1058 1059 # Type 1060 1061 ``` 1062 mirrorFunctionArgs :: (a -> b) -> (a -> c) -> (a -> c) 1063 ``` 1064 1065 # Examples 1066 :::{.example} 1067 ## `lib.trivial.mirrorFunctionArgs` usage example 1068 1069 ```nix 1070 addab = {a, b}: a + b 1071 addab { a = 2; b = 4; } 1072 => 6 1073 lib.functionArgs addab 1074 => { a = false; b = false; } 1075 addab1 = attrs: addab attrs + 1 1076 addab1 { a = 2; b = 4; } 1077 => 7 1078 lib.functionArgs addab1 1079 => { } 1080 addab1' = lib.mirrorFunctionArgs addab addab1 1081 addab1' { a = 2; b = 4; } 1082 => 7 1083 lib.functionArgs addab1' 1084 => { a = false; b = false; } 1085 ``` 1086 1087 ::: 1088 */ 1089 mirrorFunctionArgs = 1090 f: 1091 let 1092 fArgs = functionArgs f; 1093 in 1094 g: setFunctionArgs g fArgs; 1095 1096 /** 1097 Turns any non-callable values into constant functions. 1098 Returns callable values as is. 1099 1100 # Inputs 1101 1102 `v` 1103 1104 : Any value 1105 1106 # Examples 1107 :::{.example} 1108 ## `lib.trivial.toFunction` usage example 1109 1110 ```nix 1111 nix-repl> lib.toFunction 1 2 1112 1 1113 1114 nix-repl> lib.toFunction (x: x + 1) 2 1115 3 1116 ``` 1117 1118 ::: 1119 */ 1120 toFunction = v: if isFunction v then v else k: v; 1121 1122 /** 1123 Convert a hexadecimal string to it's integer representation. 1124 1125 # Type 1126 1127 ``` 1128 fromHexString :: String -> [ String ] 1129 ``` 1130 1131 # Examples 1132 1133 ```nix 1134 fromHexString "FF" 1135 => 255 1136 1137 fromHexString "0x7fffffffffffffff" 1138 => 9223372036854775807 1139 ``` 1140 */ 1141 fromHexString = 1142 str: 1143 let 1144 match = builtins.match "(0x)?([0-7]?[0-9A-Fa-f]{1,15})" str; 1145 in 1146 if match != null then 1147 (fromTOML "v=0x${builtins.elemAt match 1}").v 1148 else 1149 # TODO: Turn this into a `throw` in 26.05. 1150 assert lib.warn "fromHexString: ${ 1151 lib.generators.toPretty { } str 1152 } is not a valid input and will be rejected in 26.05" true; 1153 let 1154 noPrefix = lib.strings.removePrefix "0x" (lib.strings.toLower str); 1155 in 1156 (fromTOML "v=0x${noPrefix}").v; 1157 1158 /** 1159 Convert the given positive integer to a string of its hexadecimal 1160 representation. For example: 1161 1162 toHexString 0 => "0" 1163 1164 toHexString 16 => "10" 1165 1166 toHexString 250 => "FA" 1167 */ 1168 toHexString = 1169 let 1170 hexDigits = { 1171 "10" = "A"; 1172 "11" = "B"; 1173 "12" = "C"; 1174 "13" = "D"; 1175 "14" = "E"; 1176 "15" = "F"; 1177 }; 1178 toHexDigit = d: if d < 10 then toString d else hexDigits.${toString d}; 1179 in 1180 i: lib.concatMapStrings toHexDigit (toBaseDigits 16 i); 1181 1182 /** 1183 `toBaseDigits base i` converts the positive integer i to a list of its 1184 digits in the given base. For example: 1185 1186 toBaseDigits 10 123 => [ 1 2 3 ] 1187 1188 toBaseDigits 2 6 => [ 1 1 0 ] 1189 1190 toBaseDigits 16 250 => [ 15 10 ] 1191 1192 # Inputs 1193 1194 `base` 1195 1196 : 1\. Function argument 1197 1198 `i` 1199 1200 : 2\. Function argument 1201 */ 1202 toBaseDigits = 1203 base: i: 1204 let 1205 go = 1206 i: 1207 if i < base then 1208 [ i ] 1209 else 1210 let 1211 r = i - ((i / base) * base); 1212 q = (i - r) / base; 1213 in 1214 [ r ] ++ go q; 1215 in 1216 assert (isInt base); 1217 assert (isInt i); 1218 assert (base >= 2); 1219 assert (i >= 0); 1220 lib.reverseList (go i); 1221}