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