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 "[1;31mevaluation warning:[0m ${msg}" (
814 abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors."
815 )
816 else
817 builtins.trace "[1;35mevaluation warning:[0m ${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}