Merge pull request #298967 from vbgl/ocaml-5.2.0
[NixPkgs.git] / lib / attrsets.nix
blobde5968b953485527fd197e52efddeef24fe9e67a
1 /**
2   Operations on attribute sets.
3 */
4 { lib }:
6 let
7   inherit (builtins) head length;
8   inherit (lib.trivial) mergeAttrs warn;
9   inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName;
10   inherit (lib.lists) foldr foldl' concatMap elemAt all partition groupBy take foldl;
13 rec {
14   inherit (builtins) attrNames listToAttrs hasAttr isAttrs getAttr removeAttrs;
17   /**
18     Return an attribute from nested attribute sets.
20     Nix has an [attribute selection operator `. or`](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example:
22     ```nix
23     (x.a.b or 6) == attrByPath ["a" "b"] 6 x
24     # and
25     (x.${f p}."example.com" or 6) == attrByPath [ (f p) "example.com" ] 6 x
26     ```
29     # Inputs
31     `attrPath`
33     : A list of strings representing the attribute path to return from `set`
35     `default`
37     : Default value if `attrPath` does not resolve to an existing value
39     `set`
41     : The nested attribute set to select values from
43     # Type
45     ```
46     attrByPath :: [String] -> Any -> AttrSet -> Any
47     ```
49     # Examples
50     :::{.example}
51     ## `lib.attrsets.attrByPath` usage example
53     ```nix
54     x = { a = { b = 3; }; }
55     # ["a" "b"] is equivalent to x.a.b
56     # 6 is a default value to return if the path does not exist in attrset
57     attrByPath ["a" "b"] 6 x
58     => 3
59     attrByPath ["z" "z"] 6 x
60     => 6
61     ```
63     :::
64   */
65   attrByPath =
66     attrPath:
67     default:
68     set:
69     let
70       lenAttrPath = length attrPath;
71       attrByPath' = n: s: (
72         if n == lenAttrPath then s
73         else (
74           let
75             attr = elemAt attrPath n;
76           in
77           if s ? ${attr} then attrByPath' (n + 1) s.${attr}
78           else default
79         )
80       );
81     in
82       attrByPath' 0 set;
84   /**
85     Return if an attribute from nested attribute set exists.
87     Nix has a [has attribute operator `?`](https://nixos.org/manual/nix/stable/language/operators#has-attribute), which is sufficient for such queries, as long as the number of attributes is static. For example:
89     ```nix
90     (x?a.b) == hasAttryByPath ["a" "b"] x
91     # and
92     (x?${f p}."example.com") == hasAttryByPath [ (f p) "example.com" ] x
93     ```
95     **Laws**:
96      1.  ```nix
97          hasAttrByPath [] x == true
98          ```
101     # Inputs
103     `attrPath`
105     : A list of strings representing the attribute path to check from `set`
107     `e`
109     : The nested attribute set to check
111     # Type
113     ```
114     hasAttrByPath :: [String] -> AttrSet -> Bool
115     ```
117     # Examples
118     :::{.example}
119     ## `lib.attrsets.hasAttrByPath` usage example
121     ```nix
122     x = { a = { b = 3; }; }
123     hasAttrByPath ["a" "b"] x
124     => true
125     hasAttrByPath ["z" "z"] x
126     => false
127     hasAttrByPath [] (throw "no need")
128     => true
129     ```
131     :::
132   */
133   hasAttrByPath =
134     attrPath:
135     e:
136     let
137       lenAttrPath = length attrPath;
138       hasAttrByPath' = n: s: (
139         n == lenAttrPath || (
140           let
141             attr = elemAt attrPath n;
142           in
143           if s ? ${attr} then hasAttrByPath' (n + 1) s.${attr}
144           else false
145         )
146       );
147     in
148       hasAttrByPath' 0 e;
150   /**
151     Return the longest prefix of an attribute path that refers to an existing attribute in a nesting of attribute sets.
153     Can be used after [`mapAttrsRecursiveCond`](#function-library-lib.attrsets.mapAttrsRecursiveCond) to apply a condition,
154     although this will evaluate the predicate function on sibling attributes as well.
156     Note that the empty attribute path is valid for all values, so this function only throws an exception if any of its inputs does.
158     **Laws**:
159     1.  ```nix
160         attrsets.longestValidPathPrefix [] x == []
161         ```
163     2.  ```nix
164         hasAttrByPath (attrsets.longestValidPathPrefix p x) x == true
165         ```
168     # Inputs
170     `attrPath`
172     : A list of strings representing the longest possible path that may be returned.
174     `v`
176     : The nested attribute set to check.
178     # Type
180     ```
181     attrsets.longestValidPathPrefix :: [String] -> Value -> [String]
182     ```
184     # Examples
185     :::{.example}
186     ## `lib.attrsets.longestValidPathPrefix` usage example
188     ```nix
189     x = { a = { b = 3; }; }
190     attrsets.longestValidPathPrefix ["a" "b" "c"] x
191     => ["a" "b"]
192     attrsets.longestValidPathPrefix ["a"] x
193     => ["a"]
194     attrsets.longestValidPathPrefix ["z" "z"] x
195     => []
196     attrsets.longestValidPathPrefix ["z" "z"] (throw "no need")
197     => []
198     ```
200     :::
201   */
202   longestValidPathPrefix =
203     attrPath:
204     v:
205     let
206       lenAttrPath = length attrPath;
207       getPrefixForSetAtIndex =
208         # The nested attribute set to check, if it is an attribute set, which
209         # is not a given.
210         remainingSet:
211         # The index of the attribute we're about to check, as well as
212         # the length of the prefix we've already checked.
213         remainingPathIndex:
215           if remainingPathIndex == lenAttrPath then
216             # All previously checked attributes exist, and no attr names left,
217             # so we return the whole path.
218             attrPath
219           else
220             let
221               attr = elemAt attrPath remainingPathIndex;
222             in
223             if remainingSet ? ${attr} then
224               getPrefixForSetAtIndex
225                 remainingSet.${attr}      # advance from the set to the attribute value
226                 (remainingPathIndex + 1)  # advance the path
227             else
228               # The attribute doesn't exist, so we return the prefix up to the
229               # previously checked length.
230               take remainingPathIndex attrPath;
231     in
232       getPrefixForSetAtIndex v 0;
234   /**
235     Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
238     # Inputs
240     `attrPath`
242     : A list of strings representing the attribute path to set
244     `value`
246     : The value to set at the location described by `attrPath`
248     # Type
250     ```
251     setAttrByPath :: [String] -> Any -> AttrSet
252     ```
254     # Examples
255     :::{.example}
256     ## `lib.attrsets.setAttrByPath` usage example
258     ```nix
259     setAttrByPath ["a" "b"] 3
260     => { a = { b = 3; }; }
261     ```
263     :::
264   */
265   setAttrByPath =
266     attrPath:
267     value:
268     let
269       len = length attrPath;
270       atDepth = n:
271         if n == len
272         then value
273         else { ${elemAt attrPath n} = atDepth (n + 1); };
274     in atDepth 0;
276   /**
277     Like `attrByPath`, but without a default value. If it doesn't find the
278     path it will throw an error.
280     Nix has an [attribute selection operator](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example:
282     ```nix
283     x.a.b == getAttrByPath ["a" "b"] x
284     # and
285     x.${f p}."example.com" == getAttrByPath [ (f p) "example.com" ] x
286     ```
289     # Inputs
291     `attrPath`
293     : A list of strings representing the attribute path to get from `set`
295     `set`
297     : The nested attribute set to find the value in.
299     # Type
301     ```
302     getAttrFromPath :: [String] -> AttrSet -> Any
303     ```
305     # Examples
306     :::{.example}
307     ## `lib.attrsets.getAttrFromPath` usage example
309     ```nix
310     x = { a = { b = 3; }; }
311     getAttrFromPath ["a" "b"] x
312     => 3
313     getAttrFromPath ["z" "z"] x
314     => error: cannot find attribute `z.z'
315     ```
317     :::
318   */
319   getAttrFromPath =
320     attrPath:
321     set:
322     attrByPath attrPath (abort ("cannot find attribute `" + concatStringsSep "." attrPath + "'")) set;
324   /**
325     Map each attribute in the given set and merge them into a new attribute set.
328     # Inputs
330     `f`
332     : 1\. Function argument
334     `v`
336     : 2\. Function argument
338     # Type
340     ```
341     concatMapAttrs :: (String -> a -> AttrSet) -> AttrSet -> AttrSet
342     ```
344     # Examples
345     :::{.example}
346     ## `lib.attrsets.concatMapAttrs` usage example
348     ```nix
349     concatMapAttrs
350       (name: value: {
351         ${name} = value;
352         ${name + value} = value;
353       })
354       { x = "a"; y = "b"; }
355     => { x = "a"; xa = "a"; y = "b"; yb = "b"; }
356     ```
358     :::
359   */
360   concatMapAttrs = f: v:
361     foldl' mergeAttrs { }
362       (attrValues
363         (mapAttrs f v)
364       );
367   /**
368     Update or set specific paths of an attribute set.
370     Takes a list of updates to apply and an attribute set to apply them to,
371     and returns the attribute set with the updates applied. Updates are
372     represented as `{ path = ...; update = ...; }` values, where `path` is a
373     list of strings representing the attribute path that should be updated,
374     and `update` is a function that takes the old value at that attribute path
375     as an argument and returns the new
376     value it should be.
378     Properties:
380     - Updates to deeper attribute paths are applied before updates to more
381       shallow attribute paths
383     - Multiple updates to the same attribute path are applied in the order
384       they appear in the update list
386     - If any but the last `path` element leads into a value that is not an
387       attribute set, an error is thrown
389     - If there is an update for an attribute path that doesn't exist,
390       accessing the argument in the update function causes an error, but
391       intermediate attribute sets are implicitly created as needed
393     # Type
395     ```
396     updateManyAttrsByPath :: [{ path :: [String]; update :: (Any -> Any); }] -> AttrSet -> AttrSet
397     ```
399     # Examples
400     :::{.example}
401     ## `lib.attrsets.updateManyAttrsByPath` usage example
403     ```nix
404     updateManyAttrsByPath [
405       {
406         path = [ "a" "b" ];
407         update = old: { d = old.c; };
408       }
409       {
410         path = [ "a" "b" "c" ];
411         update = old: old + 1;
412       }
413       {
414         path = [ "x" "y" ];
415         update = old: "xy";
416       }
417     ] { a.b.c = 0; }
418     => { a = { b = { d = 1; }; }; x = { y = "xy"; }; }
419     ```
421     :::
422   */
423   updateManyAttrsByPath = let
424     # When recursing into attributes, instead of updating the `path` of each
425     # update using `tail`, which needs to allocate an entirely new list,
426     # we just pass a prefix length to use and make sure to only look at the
427     # path without the prefix length, so that we can reuse the original list
428     # entries.
429     go = prefixLength: hasValue: value: updates:
430       let
431         # Splits updates into ones on this level (split.right)
432         # And ones on levels further down (split.wrong)
433         split = partition (el: length el.path == prefixLength) updates;
435         # Groups updates on further down levels into the attributes they modify
436         nested = groupBy (el: elemAt el.path prefixLength) split.wrong;
438         # Applies only nested modification to the input value
439         withNestedMods =
440           # Return the value directly if we don't have any nested modifications
441           if split.wrong == [] then
442             if hasValue then value
443             else
444               # Throw an error if there is no value. This `head` call here is
445               # safe, but only in this branch since `go` could only be called
446               # with `hasValue == false` for nested updates, in which case
447               # it's also always called with at least one update
448               let updatePath = (head split.right).path; in
449               throw
450               ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' does "
451               + "not exist in the given value, but the first update to this "
452               + "path tries to access the existing value.")
453           else
454             # If there are nested modifications, try to apply them to the value
455             if ! hasValue then
456               # But if we don't have a value, just use an empty attribute set
457               # as the value, but simplify the code a bit
458               mapAttrs (name: go (prefixLength + 1) false null) nested
459             else if isAttrs value then
460               # If we do have a value and it's an attribute set, override it
461               # with the nested modifications
462               value //
463               mapAttrs (name: go (prefixLength + 1) (value ? ${name}) value.${name}) nested
464             else
465               # However if it's not an attribute set, we can't apply the nested
466               # modifications, throw an error
467               let updatePath = (head split.wrong).path; in
468               throw
469               ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' needs to "
470               + "be updated, but path '${showAttrPath (take prefixLength updatePath)}' "
471               + "of the given value is not an attribute set, so we can't "
472               + "update an attribute inside of it.");
474         # We get the final result by applying all the updates on this level
475         # after having applied all the nested updates
476         # We use foldl instead of foldl' so that in case of multiple updates,
477         # intermediate values aren't evaluated if not needed
478       in foldl (acc: el: el.update acc) withNestedMods split.right;
480   in updates: value: go 0 true value updates;
482   /**
483     Return the specified attributes from a set.
486     # Inputs
488     `nameList`
490     : The list of attributes to fetch from `set`. Each attribute name must exist on the attrbitue set
492     `set`
494     : The set to get attribute values from
496     # Type
498     ```
499     attrVals :: [String] -> AttrSet -> [Any]
500     ```
502     # Examples
503     :::{.example}
504     ## `lib.attrsets.attrVals` usage example
506     ```nix
507     attrVals ["a" "b" "c"] as
508     => [as.a as.b as.c]
509     ```
511     :::
512   */
513   attrVals =
514     nameList:
515     set: map (x: set.${x}) nameList;
518   /**
519     Return the values of all attributes in the given set, sorted by
520     attribute name.
522     # Type
524     ```
525     attrValues :: AttrSet -> [Any]
526     ```
528     # Examples
529     :::{.example}
530     ## `lib.attrsets.attrValues` usage example
532     ```nix
533     attrValues {c = 3; a = 1; b = 2;}
534     => [1 2 3]
535     ```
537     :::
538   */
539   attrValues = builtins.attrValues;
542   /**
543     Given a set of attribute names, return the set of the corresponding
544     attributes from the given set.
547     # Inputs
549     `names`
551     : A list of attribute names to get out of `set`
553     `attrs`
555     : The set to get the named attributes from
557     # Type
559     ```
560     getAttrs :: [String] -> AttrSet -> AttrSet
561     ```
563     # Examples
564     :::{.example}
565     ## `lib.attrsets.getAttrs` usage example
567     ```nix
568     getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; }
569     => { a = 1; b = 2; }
570     ```
572     :::
573   */
574   getAttrs =
575     names:
576     attrs: genAttrs names (name: attrs.${name});
578   /**
579     Collect each attribute named `attr` from a list of attribute
580     sets.  Sets that don't contain the named attribute are ignored.
582     # Inputs
584     `attr`
586     : The attribute name to get out of the sets.
588     `list`
590     : The list of attribute sets to go through
592     # Type
594     ```
595     catAttrs :: String -> [AttrSet] -> [Any]
596     ```
598     # Examples
599     :::{.example}
600     ## `lib.attrsets.catAttrs` usage example
602     ```nix
603     catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
604     => [1 2]
605     ```
607     :::
608   */
609   catAttrs = builtins.catAttrs;
612   /**
613     Filter an attribute set by removing all attributes for which the
614     given predicate return false.
617     # Inputs
619     `pred`
621     : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
623     `set`
625     : The attribute set to filter
627     # Type
629     ```
630     filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet
631     ```
633     # Examples
634     :::{.example}
635     ## `lib.attrsets.filterAttrs` usage example
637     ```nix
638     filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; }
639     => { foo = 1; }
640     ```
642     :::
643   */
644   filterAttrs =
645     pred:
646     set:
647     listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set));
650   /**
651     Filter an attribute set recursively by removing all attributes for
652     which the given predicate return false.
655     # Inputs
657     `pred`
659     : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
661     `set`
663     : The attribute set to filter
665     # Type
667     ```
668     filterAttrsRecursive :: (String -> Any -> Bool) -> AttrSet -> AttrSet
669     ```
671     # Examples
672     :::{.example}
673     ## `lib.attrsets.filterAttrsRecursive` usage example
675     ```nix
676     filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; }
677     => { foo = {}; }
678     ```
680     :::
681   */
682   filterAttrsRecursive =
683     pred:
684     set:
685     listToAttrs (
686       concatMap (name:
687         let v = set.${name}; in
688         if pred name v then [
689           (nameValuePair name (
690             if isAttrs v then filterAttrsRecursive pred v
691             else v
692           ))
693         ] else []
694       ) (attrNames set)
695     );
697    /**
698     Like [`lib.lists.foldl'`](#function-library-lib.lists.foldl-prime) but for attribute sets.
699     Iterates over every name-value pair in the given attribute set.
700     The result of the callback function is often called `acc` for accumulator. It is passed between callbacks from left to right and the final `acc` is the return value of `foldlAttrs`.
702     Attention:
704     There is a completely different function `lib.foldAttrs`
705     which has nothing to do with this function, despite the similar name.
708     # Inputs
710     `f`
712     : 1\. Function argument
714     `init`
716     : 2\. Function argument
718     `set`
720     : 3\. Function argument
722     # Type
724     ```
725     foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a
726     ```
728     # Examples
729     :::{.example}
730     ## `lib.attrsets.foldlAttrs` usage example
732     ```nix
733     foldlAttrs
734       (acc: name: value: {
735         sum = acc.sum + value;
736         names = acc.names ++ [name];
737       })
738       { sum = 0; names = []; }
739       {
740         foo = 1;
741         bar = 10;
742       }
743     ->
744       {
745         sum = 11;
746         names = ["bar" "foo"];
747       }
749     foldlAttrs
750       (throw "function not needed")
751       123
752       {};
753     ->
754       123
756     foldlAttrs
757       (acc: _: _: acc)
758       3
759       { z = throw "value not needed"; a = throw "value not needed"; };
760     ->
761       3
763     The accumulator doesn't have to be an attrset.
764     It can be as simple as a number or string.
766     foldlAttrs
767       (acc: _: v: acc * 10 + v)
768       1
769       { z = 1; a = 2; };
770     ->
771       121
772     ```
774     :::
775   */
776   foldlAttrs = f: init: set:
777     foldl'
778       (acc: name: f acc name set.${name})
779       init
780       (attrNames set);
782   /**
783     Apply fold functions to values grouped by key.
786     # Inputs
788     `op`
790     : A function, given a value and a collector combines the two.
792     `nul`
794     : The starting value.
796     `list_of_attrs`
798     : A list of attribute sets to fold together by key.
800     # Type
802     ```
803     foldAttrs :: (Any -> Any -> Any) -> Any -> [AttrSets] -> Any
804     ```
806     # Examples
807     :::{.example}
808     ## `lib.attrsets.foldAttrs` usage example
810     ```nix
811     foldAttrs (item: acc: [item] ++ acc) [] [{ a = 2; } { a = 3; }]
812     => { a = [ 2 3 ]; }
813     ```
815     :::
816   */
817   foldAttrs =
818     op:
819     nul:
820     list_of_attrs:
821     foldr (n: a:
822         foldr (name: o:
823           o // { ${name} = op n.${name} (a.${name} or nul); }
824         ) a (attrNames n)
825     ) {} list_of_attrs;
828   /**
829     Recursively collect sets that verify a given predicate named `pred`
830     from the set `attrs`. The recursion is stopped when the predicate is
831     verified.
834     # Inputs
836     `pred`
838     : Given an attribute's value, determine if recursion should stop.
840     `attrs`
842     : The attribute set to recursively collect.
844     # Type
846     ```
847     collect :: (AttrSet -> Bool) -> AttrSet -> [x]
848     ```
850     # Examples
851     :::{.example}
852     ## `lib.attrsets.collect` usage example
854     ```nix
855     collect isList { a = { b = ["b"]; }; c = [1]; }
856     => [["b"] [1]]
858     collect (x: x ? outPath)
859        { a = { outPath = "a/"; }; b = { outPath = "b/"; }; }
860     => [{ outPath = "a/"; } { outPath = "b/"; }]
861     ```
863     :::
864   */
865   collect =
866     pred:
867     attrs:
868     if pred attrs then
869       [ attrs ]
870     else if isAttrs attrs then
871       concatMap (collect pred) (attrValues attrs)
872     else
873       [];
875   /**
876     Return the cartesian product of attribute set value combinations.
879     # Inputs
881     `attrsOfLists`
883     : Attribute set with attributes that are lists of values
885     # Type
887     ```
888     cartesianProductOfSets :: AttrSet -> [AttrSet]
889     ```
891     # Examples
892     :::{.example}
893     ## `lib.attrsets.cartesianProductOfSets` usage example
895     ```nix
896     cartesianProductOfSets { a = [ 1 2 ]; b = [ 10 20 ]; }
897     => [
898          { a = 1; b = 10; }
899          { a = 1; b = 20; }
900          { a = 2; b = 10; }
901          { a = 2; b = 20; }
902        ]
903     ```
905     :::
906   */
907   cartesianProductOfSets =
908     attrsOfLists:
909     foldl' (listOfAttrs: attrName:
910       concatMap (attrs:
911         map (listValue: attrs // { ${attrName} = listValue; }) attrsOfLists.${attrName}
912       ) listOfAttrs
913     ) [{}] (attrNames attrsOfLists);
916   /**
917     Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`.
920     # Inputs
922     `name`
924     : Attribute name
926     `value`
928     : Attribute value
930     # Type
932     ```
933     nameValuePair :: String -> Any -> { name :: String; value :: Any; }
934     ```
936     # Examples
937     :::{.example}
938     ## `lib.attrsets.nameValuePair` usage example
940     ```nix
941     nameValuePair "some" 6
942     => { name = "some"; value = 6; }
943     ```
945     :::
946   */
947   nameValuePair =
948     name:
949     value:
950     { inherit name value; };
953   /**
954     Apply a function to each element in an attribute set, creating a new attribute set.
956     # Inputs
958     `f`
960     : A function that takes an attribute name and its value, and returns the new value for the attribute.
962     `attrset`
964     : The attribute set to iterate through.
966     # Type
968     ```
969     mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet
970     ```
972     # Examples
973     :::{.example}
974     ## `lib.attrsets.mapAttrs` usage example
976     ```nix
977     mapAttrs (name: value: name + "-" + value)
978        { x = "foo"; y = "bar"; }
979     => { x = "x-foo"; y = "y-bar"; }
980     ```
982     :::
983   */
984   mapAttrs = builtins.mapAttrs;
987   /**
988     Like `mapAttrs`, but allows the name of each attribute to be
989     changed in addition to the value.  The applied function should
990     return both the new name and value as a `nameValuePair`.
993     # Inputs
995     `f`
997     : A function, given an attribute's name and value, returns a new `nameValuePair`.
999     `set`
1001     : Attribute set to map over.
1003     # Type
1005     ```
1006     mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet
1007     ```
1009     # Examples
1010     :::{.example}
1011     ## `lib.attrsets.mapAttrs'` usage example
1013     ```nix
1014     mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value))
1015        { x = "a"; y = "b"; }
1016     => { foo_x = "bar-a"; foo_y = "bar-b"; }
1017     ```
1019     :::
1020   */
1021   mapAttrs' =
1022     f:
1023     set:
1024     listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
1027   /**
1028     Call a function for each attribute in the given set and return
1029     the result in a list.
1031     # Inputs
1033     `f`
1035     : A function, given an attribute's name and value, returns a new value.
1037     `attrs`
1039     : Attribute set to map over.
1041     # Type
1043     ```
1044     mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b]
1045     ```
1047     # Examples
1048     :::{.example}
1049     ## `lib.attrsets.mapAttrsToList` usage example
1051     ```nix
1052     mapAttrsToList (name: value: name + value)
1053        { x = "a"; y = "b"; }
1054     => [ "xa" "yb" ]
1055     ```
1057     :::
1058   */
1059   mapAttrsToList =
1060     f:
1061     attrs:
1062     map (name: f name attrs.${name}) (attrNames attrs);
1064   /**
1065     Deconstruct an attrset to a list of name-value pairs as expected by [`builtins.listToAttrs`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs).
1066     Each element of the resulting list is an attribute set with these attributes:
1067     - `name` (string): The name of the attribute
1068     - `value` (any): The value of the attribute
1070     The following is always true:
1071     ```nix
1072     builtins.listToAttrs (attrsToList attrs) == attrs
1073     ```
1075     :::{.warning}
1076     The opposite is not always true. In general expect that
1077     ```nix
1078     attrsToList (builtins.listToAttrs list) != list
1079     ```
1081     This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
1082     :::
1084     # Inputs
1086     `set`
1088     : The attribute set to deconstruct.
1090     # Type
1092     ```
1093     attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
1094     ```
1096     # Examples
1097     :::{.example}
1098     ## `lib.attrsets.attrsToList` usage example
1100     ```nix
1101     attrsToList { foo = 1; bar = "asdf"; }
1102     => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
1103     ```
1105     :::
1106   */
1107   attrsToList = mapAttrsToList nameValuePair;
1110   /**
1111     Like `mapAttrs`, except that it recursively applies itself to the *leaf* attributes of a potentially-nested attribute set:
1112     the second argument of the function will never be an attrset.
1113     Also, the first argument of the mapping function is a *list* of the attribute names that form the path to the leaf attribute.
1115     For a function that gives you control over what counts as a leaf, see `mapAttrsRecursiveCond`.
1117     :::{#map-attrs-recursive-example .example}
1118     # Map over leaf attributes
1120     ```nix
1121     mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
1122       { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
1123     ```
1124     evaluates to
1125     ```nix
1126     { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
1127     ```
1128     :::
1130     # Type
1131     ```
1132     mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet
1133     ```
1134   */
1135   mapAttrsRecursive =
1136     f:
1137     set:
1138     mapAttrsRecursiveCond (as: true) f set;
1141   /**
1142     Like `mapAttrsRecursive`, but it takes an additional predicate that tells it whether to recurse into an attribute set.
1143     If the predicate returns false, `mapAttrsRecursiveCond` does not recurse, but instead applies the mapping function.
1144     If the predicate returns true, it does recurse, and does not apply the mapping function.
1146     :::{#map-attrs-recursive-cond-example .example}
1147     # Map over an leaf attributes defined by a condition
1149     Map derivations to their `name` attribute.
1150     Derivatons are identified as attribute sets that contain `{ type = "derivation"; }`.
1151     ```nix
1152     mapAttrsRecursiveCond
1153       (as: !(as ? "type" && as.type == "derivation"))
1154       (x: x.name)
1155       attrs
1156     ```
1157     :::
1159     # Type
1160     ```
1161     mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
1162     ```
1163   */
1164   mapAttrsRecursiveCond =
1165     cond:
1166     f:
1167     set:
1168     let
1169       recurse = path:
1170         mapAttrs
1171           (name: value:
1172             if isAttrs value && cond value
1173             then recurse (path ++ [ name ]) value
1174             else f (path ++ [ name ]) value);
1175     in
1176     recurse [ ] set;
1179   /**
1180     Generate an attribute set by mapping a function over a list of
1181     attribute names.
1184     # Inputs
1186     `names`
1188     : Names of values in the resulting attribute set.
1190     `f`
1192     : A function, given the name of the attribute, returns the attribute's value.
1194     # Type
1196     ```
1197     genAttrs :: [ String ] -> (String -> Any) -> AttrSet
1198     ```
1200     # Examples
1201     :::{.example}
1202     ## `lib.attrsets.genAttrs` usage example
1204     ```nix
1205     genAttrs [ "foo" "bar" ] (name: "x_" + name)
1206     => { foo = "x_foo"; bar = "x_bar"; }
1207     ```
1209     :::
1210   */
1211   genAttrs =
1212     names:
1213     f:
1214     listToAttrs (map (n: nameValuePair n (f n)) names);
1217   /**
1218     Check whether the argument is a derivation. Any set with
1219     `{ type = "derivation"; }` counts as a derivation.
1222     # Inputs
1224     `value`
1226     : Value to check.
1228     # Type
1230     ```
1231     isDerivation :: Any -> Bool
1232     ```
1234     # Examples
1235     :::{.example}
1236     ## `lib.attrsets.isDerivation` usage example
1238     ```nix
1239     nixpkgs = import <nixpkgs> {}
1240     isDerivation nixpkgs.ruby
1241     => true
1242     isDerivation "foobar"
1243     => false
1244     ```
1246     :::
1247   */
1248   isDerivation =
1249     value: value.type or null == "derivation";
1251    /**
1252     Converts a store path to a fake derivation.
1255     # Inputs
1257     `path`
1259     : A store path to convert to a derivation.
1261     # Type
1263     ```
1264     toDerivation :: Path -> Derivation
1265     ```
1266   */
1267    toDerivation =
1268      path:
1269      let
1270        path' = builtins.storePath path;
1271        res =
1272          { type = "derivation";
1273            name = sanitizeDerivationName (builtins.substring 33 (-1) (baseNameOf path'));
1274            outPath = path';
1275            outputs = [ "out" ];
1276            out = res;
1277            outputName = "out";
1278          };
1279     in res;
1282   /**
1283     If `cond` is true, return the attribute set `as`,
1284     otherwise an empty attribute set.
1287     # Inputs
1289     `cond`
1291     : Condition under which the `as` attribute set is returned.
1293     `as`
1295     : The attribute set to return if `cond` is `true`.
1297     # Type
1299     ```
1300     optionalAttrs :: Bool -> AttrSet -> AttrSet
1301     ```
1303     # Examples
1304     :::{.example}
1305     ## `lib.attrsets.optionalAttrs` usage example
1307     ```nix
1308     optionalAttrs (true) { my = "set"; }
1309     => { my = "set"; }
1310     optionalAttrs (false) { my = "set"; }
1311     => { }
1312     ```
1314     :::
1315   */
1316   optionalAttrs =
1317     cond:
1318     as:
1319     if cond then as else {};
1322   /**
1323     Merge sets of attributes and use the function `f` to merge attributes
1324     values.
1327     # Inputs
1329     `names`
1331     : List of attribute names to zip.
1333     `f`
1335     : A function, accepts an attribute name, all the values, and returns a combined value.
1337     `sets`
1339     : List of values from the list of attribute sets.
1341     # Type
1343     ```
1344     zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
1345     ```
1347     # Examples
1348     :::{.example}
1349     ## `lib.attrsets.zipAttrsWithNames` usage example
1351     ```nix
1352     zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
1353     => { a = ["x" "y"]; }
1354     ```
1356     :::
1357   */
1358   zipAttrsWithNames =
1359     names:
1360     f:
1361     sets:
1362     listToAttrs (map (name: {
1363       inherit name;
1364       value = f name (catAttrs name sets);
1365     }) names);
1368   /**
1369     Merge sets of attributes and use the function f to merge attribute values.
1370     Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`.
1372     Implementation note: Common names appear multiple times in the list of
1373     names, hopefully this does not affect the system because the maximal
1374     laziness avoid computing twice the same expression and `listToAttrs` does
1375     not care about duplicated attribute names.
1377     # Type
1379     ```
1380     zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
1381     ```
1383     # Examples
1384     :::{.example}
1385     ## `lib.attrsets.zipAttrsWith` usage example
1387     ```nix
1388     zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
1389     => { a = ["x" "y"]; b = ["z"]; }
1390     ```
1392     :::
1393   */
1394   zipAttrsWith =
1395     builtins.zipAttrsWith or (f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets);
1398   /**
1399     Merge sets of attributes and combine each attribute value in to a list.
1401     Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function.
1403     # Type
1405     ```
1406     zipAttrs :: [ AttrSet ] -> AttrSet
1407     ```
1409     # Examples
1410     :::{.example}
1411     ## `lib.attrsets.zipAttrs` usage example
1413     ```nix
1414     zipAttrs [{a = "x";} {a = "y"; b = "z";}]
1415     => { a = ["x" "y"]; b = ["z"]; }
1416     ```
1418     :::
1419   */
1420   zipAttrs = zipAttrsWith (name: values: values);
1422   /**
1423     Merge a list of attribute sets together using the `//` operator.
1424     In case of duplicate attributes, values from later list elements take precedence over earlier ones.
1425     The result is the same as `foldl mergeAttrs { }`, but the performance is better for large inputs.
1426     For n list elements, each with an attribute set containing m unique attributes, the complexity of this operation is O(nm log n).
1429     # Inputs
1431     `list`
1433     : 1\. Function argument
1435     # Type
1437     ```
1438     mergeAttrsList :: [ Attrs ] -> Attrs
1439     ```
1441     # Examples
1442     :::{.example}
1443     ## `lib.attrsets.mergeAttrsList` usage example
1445     ```nix
1446     mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ]
1447     => { a = 0; b = 1; c = 2; d = 3; }
1448     mergeAttrsList [ { a = 0; } { a = 1; } ]
1449     => { a = 1; }
1450     ```
1452     :::
1453   */
1454   mergeAttrsList = list:
1455     let
1456       # `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end`
1457       # Type: Int -> Int -> Attrs
1458       binaryMerge = start: end:
1459         # assert start < end; # Invariant
1460         if end - start >= 2 then
1461           # If there's at least 2 elements, split the range in two, recurse on each part and merge the result
1462           # The invariant is satisfied because each half will have at least 1 element
1463           binaryMerge start (start + (end - start) / 2)
1464           // binaryMerge (start + (end - start) / 2) end
1465         else
1466           # Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly
1467           elemAt list start;
1468     in
1469     if list == [ ] then
1470       # Calling binaryMerge as below would not satisfy its invariant
1471       { }
1472     else
1473       binaryMerge 0 (length list);
1476   /**
1477     Does the same as the update operator '//' except that attributes are
1478     merged until the given predicate is verified.  The predicate should
1479     accept 3 arguments which are the path to reach the attribute, a part of
1480     the first attribute set and a part of the second attribute set.  When
1481     the predicate is satisfied, the value of the first attribute set is
1482     replaced by the value of the second attribute set.
1485     # Inputs
1487     `pred`
1489     : Predicate, taking the path to the current attribute as a list of strings for attribute names, and the two values at that path from the original arguments.
1491     `lhs`
1493     : Left attribute set of the merge.
1495     `rhs`
1497     : Right attribute set of the merge.
1499     # Type
1501     ```
1502     recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet
1503     ```
1505     # Examples
1506     :::{.example}
1507     ## `lib.attrsets.recursiveUpdateUntil` usage example
1509     ```nix
1510     recursiveUpdateUntil (path: l: r: path == ["foo"]) {
1511       # first attribute set
1512       foo.bar = 1;
1513       foo.baz = 2;
1514       bar = 3;
1515     } {
1516       #second attribute set
1517       foo.bar = 1;
1518       foo.quz = 2;
1519       baz = 4;
1520     }
1522     => {
1523       foo.bar = 1; # 'foo.*' from the second set
1524       foo.quz = 2; #
1525       bar = 3;     # 'bar' from the first set
1526       baz = 4;     # 'baz' from the second set
1527     }
1528     ```
1530     :::
1531   */
1532   recursiveUpdateUntil =
1533     pred:
1534     lhs:
1535     rhs:
1536     let f = attrPath:
1537       zipAttrsWith (n: values:
1538         let here = attrPath ++ [n]; in
1539         if length values == 1
1540         || pred here (elemAt values 1) (head values) then
1541           head values
1542         else
1543           f here values
1544       );
1545     in f [] [rhs lhs];
1548   /**
1549     A recursive variant of the update operator â€˜//’.  The recursion
1550     stops when one of the attribute values is not an attribute set,
1551     in which case the right hand side value takes precedence over the
1552     left hand side value.
1555     # Inputs
1557     `lhs`
1559     : Left attribute set of the merge.
1561     `rhs`
1563     : Right attribute set of the merge.
1565     # Type
1567     ```
1568     recursiveUpdate :: AttrSet -> AttrSet -> AttrSet
1569     ```
1571     # Examples
1572     :::{.example}
1573     ## `lib.attrsets.recursiveUpdate` usage example
1575     ```nix
1576     recursiveUpdate {
1577       boot.loader.grub.enable = true;
1578       boot.loader.grub.device = "/dev/hda";
1579     } {
1580       boot.loader.grub.device = "";
1581     }
1583     returns: {
1584       boot.loader.grub.enable = true;
1585       boot.loader.grub.device = "";
1586     }
1587     ```
1589     :::
1590   */
1591   recursiveUpdate =
1592     lhs:
1593     rhs:
1594     recursiveUpdateUntil (path: lhs: rhs: !(isAttrs lhs && isAttrs rhs)) lhs rhs;
1597   /**
1598     Recurse into every attribute set of the first argument and check that:
1599     - Each attribute path also exists in the second argument.
1600     - If the attribute's value is not a nested attribute set, it must have the same value in the right argument.
1603     # Inputs
1605     `pattern`
1607     : Attribute set structure to match
1609     `attrs`
1611     : Attribute set to check
1613     # Type
1615     ```
1616     matchAttrs :: AttrSet -> AttrSet -> Bool
1617     ```
1619     # Examples
1620     :::{.example}
1621     ## `lib.attrsets.matchAttrs` usage example
1623     ```nix
1624     matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
1625     => true
1626     ```
1628     :::
1629   */
1630   matchAttrs =
1631     pattern:
1632     attrs:
1633     assert isAttrs pattern;
1634     all
1635     ( # Compare equality between `pattern` & `attrs`.
1636       attr:
1637       # Missing attr, not equal.
1638       attrs ? ${attr} && (
1639         let
1640           lhs = pattern.${attr};
1641           rhs = attrs.${attr};
1642         in
1643         # If attrset check recursively
1644         if isAttrs lhs then isAttrs rhs && matchAttrs lhs rhs
1645         else lhs == rhs
1646       )
1647     )
1648     (attrNames pattern);
1650   /**
1651     Override only the attributes that are already present in the old set
1652     useful for deep-overriding.
1655     # Inputs
1657     `old`
1659     : Original attribute set
1661     `new`
1663     : Attribute set with attributes to override in `old`.
1665     # Type
1667     ```
1668     overrideExisting :: AttrSet -> AttrSet -> AttrSet
1669     ```
1671     # Examples
1672     :::{.example}
1673     ## `lib.attrsets.overrideExisting` usage example
1675     ```nix
1676     overrideExisting {} { a = 1; }
1677     => {}
1678     overrideExisting { b = 2; } { a = 1; }
1679     => { b = 2; }
1680     overrideExisting { a = 3; b = 2; } { a = 1; }
1681     => { a = 1; b = 2; }
1682     ```
1684     :::
1685   */
1686   overrideExisting =
1687     old:
1688     new:
1689     mapAttrs (name: value: new.${name} or value) old;
1692   /**
1693     Turns a list of strings into a human-readable description of those
1694     strings represented as an attribute path. The result of this function is
1695     not intended to be machine-readable.
1696     Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
1699     # Inputs
1701     `path`
1703     : Attribute path to render to a string
1705     # Type
1707     ```
1708     showAttrPath :: [String] -> String
1709     ```
1711     # Examples
1712     :::{.example}
1713     ## `lib.attrsets.showAttrPath` usage example
1715     ```nix
1716     showAttrPath [ "foo" "10" "bar" ]
1717     => "foo.\"10\".bar"
1718     showAttrPath []
1719     => "<root attribute path>"
1720     ```
1722     :::
1723   */
1724   showAttrPath =
1725     path:
1726     if path == [] then "<root attribute path>"
1727     else concatMapStringsSep "." escapeNixIdentifier path;
1730   /**
1731     Get a package output.
1732     If no output is found, fallback to `.out` and then to the default.
1735     # Inputs
1737     `output`
1739     : 1\. Function argument
1741     `pkg`
1743     : 2\. Function argument
1745     # Type
1747     ```
1748     getOutput :: String -> Derivation -> String
1749     ```
1751     # Examples
1752     :::{.example}
1753     ## `lib.attrsets.getOutput` usage example
1755     ```nix
1756     getOutput "dev" pkgs.openssl
1757     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1758     ```
1760     :::
1761   */
1762   getOutput = output: pkg:
1763     if ! pkg ? outputSpecified || ! pkg.outputSpecified
1764       then pkg.${output} or pkg.out or pkg
1765       else pkg;
1767   /**
1768     Get a package's `bin` output.
1769     If the output does not exist, fallback to `.out` and then to the default.
1771     # Inputs
1773     `pkg`
1775     : The package whose `bin` output will be retrieved.
1777     # Type
1779     ```
1780     getBin :: Derivation -> String
1781     ```
1783     # Examples
1784     :::{.example}
1785     ## `lib.attrsets.getBin` usage example
1787     ```nix
1788     getBin pkgs.openssl
1789     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r"
1790     ```
1792     :::
1793   */
1794   getBin = getOutput "bin";
1797   /**
1798     Get a package's `lib` output.
1799     If the output does not exist, fallback to `.out` and then to the default.
1801     # Inputs
1803     `pkg`
1805     : The package whose `lib` output will be retrieved.
1807     # Type
1809     ```
1810     getLib :: Derivation -> String
1811     ```
1813     # Examples
1814     :::{.example}
1815     ## `lib.attrsets.getLib` usage example
1817     ```nix
1818     getLib pkgs.openssl
1819     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib"
1820     ```
1822     :::
1823   */
1824   getLib = getOutput "lib";
1827   /**
1828     Get a package's `dev` output.
1829     If the output does not exist, fallback to `.out` and then to the default.
1831     # Inputs
1833     `pkg`
1835     : The package whose `dev` output will be retrieved.
1837     # Type
1839     ```
1840     getDev :: Derivation -> String
1841     ```
1843     # Examples
1844     :::{.example}
1845     ## `lib.attrsets.getDev` usage example
1847     ```nix
1848     getDev pkgs.openssl
1849     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1850     ```
1852     :::
1853   */
1854   getDev = getOutput "dev";
1857   /**
1858     Get a package's `man` output.
1859     If the output does not exist, fallback to `.out` and then to the default.
1861     # Inputs
1863     `pkg`
1865     : The package whose `man` output will be retrieved.
1867     # Type
1869     ```
1870     getMan :: Derivation -> String
1871     ```
1873     # Examples
1874     :::{.example}
1875     ## `lib.attrsets.getMan` usage example
1877     ```nix
1878     getMan pkgs.openssl
1879     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man"
1880     ```
1882     :::
1883   */
1884   getMan = getOutput "man";
1886   /**
1887     Pick the outputs of packages to place in `buildInputs`
1889     # Inputs
1891     `pkgs`
1893     : List of packages.
1895     # Type
1897     ```
1898     chooseDevOutputs :: [Derivation] -> [String]
1899     ```
1900   */
1901   chooseDevOutputs = builtins.map getDev;
1903   /**
1904     Make various Nix tools consider the contents of the resulting
1905     attribute set when looking for what to build, find, etc.
1907     This function only affects a single attribute set; it does not
1908     apply itself recursively for nested attribute sets.
1911     # Inputs
1913     `attrs`
1915     : An attribute set to scan for derivations.
1917     # Type
1919     ```
1920     recurseIntoAttrs :: AttrSet -> AttrSet
1921     ```
1923     # Examples
1924     :::{.example}
1925     ## `lib.attrsets.recurseIntoAttrs` usage example
1927     ```nix
1928     { pkgs ? import <nixpkgs> {} }:
1929     {
1930       myTools = pkgs.lib.recurseIntoAttrs {
1931         inherit (pkgs) hello figlet;
1932       };
1933     }
1934     ```
1936     :::
1937   */
1938   recurseIntoAttrs =
1939     attrs:
1940     attrs // { recurseForDerivations = true; };
1942   /**
1943     Undo the effect of recurseIntoAttrs.
1946     # Inputs
1948     `attrs`
1950     : An attribute set to not scan for derivations.
1952     # Type
1954     ```
1955     dontRecurseIntoAttrs :: AttrSet -> AttrSet
1956     ```
1957   */
1958   dontRecurseIntoAttrs =
1959     attrs:
1960     attrs // { recurseForDerivations = false; };
1962   /**
1963     `unionOfDisjoint x y` is equal to `x // y // z` where the
1964     attrnames in `z` are the intersection of the attrnames in `x` and
1965     `y`, and all values `assert` with an error message.  This
1966      operator is commutative, unlike (//).
1969     # Inputs
1971     `x`
1973     : 1\. Function argument
1975     `y`
1977     : 2\. Function argument
1979     # Type
1981     ```
1982     unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet
1983     ```
1984   */
1985   unionOfDisjoint = x: y:
1986     let
1987       intersection = builtins.intersectAttrs x y;
1988       collisions = lib.concatStringsSep " " (builtins.attrNames intersection);
1989       mask = builtins.mapAttrs (name: value: builtins.throw
1990         "unionOfDisjoint: collision on ${name}; complete list: ${collisions}")
1991         intersection;
1992     in
1993       (x // y) // mask;
1995   # DEPRECATED
1996   zipWithNames = warn
1997     "lib.zipWithNames is a deprecated alias of lib.zipAttrsWithNames." zipAttrsWithNames;
1999   # DEPRECATED
2000   zip = warn
2001     "lib.zip is a deprecated alias of lib.zipAttrsWith." zipAttrsWith;