Merge pull request #312830 from r-ryantm/auto-update/pandoc-include
[NixPkgs.git] / lib / attrsets.nix
blob83f8d0f34186ed068468cfb82f1362b3964721ba
1 /**
2   Operations on attribute sets.
3 */
4 { lib }:
6 let
7   inherit (builtins) head length;
8   inherit (lib.trivial) isInOldestRelease mergeAttrs warn warnIf;
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) == hasAttrByPath ["a" "b"] x
91     # and
92     (x?${f p}."example.com") == hasAttrByPath [ (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     cartesianProduct :: AttrSet -> [AttrSet]
889     ```
891     # Examples
892     :::{.example}
893     ## `lib.attrsets.cartesianProduct` usage example
895     ```nix
896     cartesianProduct { 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   cartesianProduct =
908     attrsOfLists:
909     foldl' (listOfAttrs: attrName:
910       concatMap (attrs:
911         map (listValue: attrs // { ${attrName} = listValue; }) attrsOfLists.${attrName}
912       ) listOfAttrs
913     ) [{}] (attrNames attrsOfLists);
916   /**
917     Return the result of function f applied to the cartesian product of attribute set value combinations.
918     Equivalent to using cartesianProduct followed by map.
920     # Inputs
922     `f`
924     : A function, given an attribute set, it returns a new value.
926     `attrsOfLists`
928     : Attribute set with attributes that are lists of values
930     # Type
932     ```
933     mapCartesianProduct :: (AttrSet -> a) -> AttrSet -> [a]
934     ```
936     # Examples
937     :::{.example}
938     ## `lib.attrsets.mapCartesianProduct` usage example
940     ```nix
941     mapCartesianProduct ({a, b}: "${a}-${b}") { a = [ "1" "2" ]; b = [ "3" "4" ]; }
942     => [ "1-3" "1-4" "2-3" "2-4" ]
943     ```
945     :::
947   */
948   mapCartesianProduct = f: attrsOfLists: map f (cartesianProduct attrsOfLists);
950   /**
951     Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`.
954     # Inputs
956     `name`
958     : Attribute name
960     `value`
962     : Attribute value
964     # Type
966     ```
967     nameValuePair :: String -> Any -> { name :: String; value :: Any; }
968     ```
970     # Examples
971     :::{.example}
972     ## `lib.attrsets.nameValuePair` usage example
974     ```nix
975     nameValuePair "some" 6
976     => { name = "some"; value = 6; }
977     ```
979     :::
980   */
981   nameValuePair =
982     name:
983     value:
984     { inherit name value; };
987   /**
988     Apply a function to each element in an attribute set, creating a new attribute set.
990     # Inputs
992     `f`
994     : A function that takes an attribute name and its value, and returns the new value for the attribute.
996     `attrset`
998     : The attribute set to iterate through.
1000     # Type
1002     ```
1003     mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet
1004     ```
1006     # Examples
1007     :::{.example}
1008     ## `lib.attrsets.mapAttrs` usage example
1010     ```nix
1011     mapAttrs (name: value: name + "-" + value)
1012        { x = "foo"; y = "bar"; }
1013     => { x = "x-foo"; y = "y-bar"; }
1014     ```
1016     :::
1017   */
1018   mapAttrs = builtins.mapAttrs;
1021   /**
1022     Like `mapAttrs`, but allows the name of each attribute to be
1023     changed in addition to the value.  The applied function should
1024     return both the new name and value as a `nameValuePair`.
1027     # Inputs
1029     `f`
1031     : A function, given an attribute's name and value, returns a new `nameValuePair`.
1033     `set`
1035     : Attribute set to map over.
1037     # Type
1039     ```
1040     mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet
1041     ```
1043     # Examples
1044     :::{.example}
1045     ## `lib.attrsets.mapAttrs'` usage example
1047     ```nix
1048     mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value))
1049        { x = "a"; y = "b"; }
1050     => { foo_x = "bar-a"; foo_y = "bar-b"; }
1051     ```
1053     :::
1054   */
1055   mapAttrs' =
1056     f:
1057     set:
1058     listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
1061   /**
1062     Call a function for each attribute in the given set and return
1063     the result in a list.
1065     # Inputs
1067     `f`
1069     : A function, given an attribute's name and value, returns a new value.
1071     `attrs`
1073     : Attribute set to map over.
1075     # Type
1077     ```
1078     mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b]
1079     ```
1081     # Examples
1082     :::{.example}
1083     ## `lib.attrsets.mapAttrsToList` usage example
1085     ```nix
1086     mapAttrsToList (name: value: name + value)
1087        { x = "a"; y = "b"; }
1088     => [ "xa" "yb" ]
1089     ```
1091     :::
1092   */
1093   mapAttrsToList =
1094     f:
1095     attrs:
1096     map (name: f name attrs.${name}) (attrNames attrs);
1098   /**
1099     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).
1100     Each element of the resulting list is an attribute set with these attributes:
1101     - `name` (string): The name of the attribute
1102     - `value` (any): The value of the attribute
1104     The following is always true:
1105     ```nix
1106     builtins.listToAttrs (attrsToList attrs) == attrs
1107     ```
1109     :::{.warning}
1110     The opposite is not always true. In general expect that
1111     ```nix
1112     attrsToList (builtins.listToAttrs list) != list
1113     ```
1115     This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
1116     :::
1118     # Inputs
1120     `set`
1122     : The attribute set to deconstruct.
1124     # Type
1126     ```
1127     attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
1128     ```
1130     # Examples
1131     :::{.example}
1132     ## `lib.attrsets.attrsToList` usage example
1134     ```nix
1135     attrsToList { foo = 1; bar = "asdf"; }
1136     => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
1137     ```
1139     :::
1140   */
1141   attrsToList = mapAttrsToList nameValuePair;
1144   /**
1145     Like `mapAttrs`, except that it recursively applies itself to the *leaf* attributes of a potentially-nested attribute set:
1146     the second argument of the function will never be an attrset.
1147     Also, the first argument of the mapping function is a *list* of the attribute names that form the path to the leaf attribute.
1149     For a function that gives you control over what counts as a leaf, see `mapAttrsRecursiveCond`.
1151     :::{#map-attrs-recursive-example .example}
1152     # Map over leaf attributes
1154     ```nix
1155     mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
1156       { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
1157     ```
1158     evaluates to
1159     ```nix
1160     { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
1161     ```
1162     :::
1164     # Type
1165     ```
1166     mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet
1167     ```
1168   */
1169   mapAttrsRecursive =
1170     f:
1171     set:
1172     mapAttrsRecursiveCond (as: true) f set;
1175   /**
1176     Like `mapAttrsRecursive`, but it takes an additional predicate that tells it whether to recurse into an attribute set.
1177     If the predicate returns false, `mapAttrsRecursiveCond` does not recurse, but instead applies the mapping function.
1178     If the predicate returns true, it does recurse, and does not apply the mapping function.
1180     :::{#map-attrs-recursive-cond-example .example}
1181     # Map over an leaf attributes defined by a condition
1183     Map derivations to their `name` attribute.
1184     Derivatons are identified as attribute sets that contain `{ type = "derivation"; }`.
1185     ```nix
1186     mapAttrsRecursiveCond
1187       (as: !(as ? "type" && as.type == "derivation"))
1188       (x: x.name)
1189       attrs
1190     ```
1191     :::
1193     # Type
1194     ```
1195     mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
1196     ```
1197   */
1198   mapAttrsRecursiveCond =
1199     cond:
1200     f:
1201     set:
1202     let
1203       recurse = path:
1204         mapAttrs
1205           (name: value:
1206             if isAttrs value && cond value
1207             then recurse (path ++ [ name ]) value
1208             else f (path ++ [ name ]) value);
1209     in
1210     recurse [ ] set;
1213   /**
1214     Generate an attribute set by mapping a function over a list of
1215     attribute names.
1218     # Inputs
1220     `names`
1222     : Names of values in the resulting attribute set.
1224     `f`
1226     : A function, given the name of the attribute, returns the attribute's value.
1228     # Type
1230     ```
1231     genAttrs :: [ String ] -> (String -> Any) -> AttrSet
1232     ```
1234     # Examples
1235     :::{.example}
1236     ## `lib.attrsets.genAttrs` usage example
1238     ```nix
1239     genAttrs [ "foo" "bar" ] (name: "x_" + name)
1240     => { foo = "x_foo"; bar = "x_bar"; }
1241     ```
1243     :::
1244   */
1245   genAttrs =
1246     names:
1247     f:
1248     listToAttrs (map (n: nameValuePair n (f n)) names);
1251   /**
1252     Check whether the argument is a derivation. Any set with
1253     `{ type = "derivation"; }` counts as a derivation.
1256     # Inputs
1258     `value`
1260     : Value to check.
1262     # Type
1264     ```
1265     isDerivation :: Any -> Bool
1266     ```
1268     # Examples
1269     :::{.example}
1270     ## `lib.attrsets.isDerivation` usage example
1272     ```nix
1273     nixpkgs = import <nixpkgs> {}
1274     isDerivation nixpkgs.ruby
1275     => true
1276     isDerivation "foobar"
1277     => false
1278     ```
1280     :::
1281   */
1282   isDerivation =
1283     value: value.type or null == "derivation";
1285    /**
1286     Converts a store path to a fake derivation.
1289     # Inputs
1291     `path`
1293     : A store path to convert to a derivation.
1295     # Type
1297     ```
1298     toDerivation :: Path -> Derivation
1299     ```
1300   */
1301    toDerivation =
1302      path:
1303      let
1304        path' = builtins.storePath path;
1305        res =
1306          { type = "derivation";
1307            name = sanitizeDerivationName (builtins.substring 33 (-1) (baseNameOf path'));
1308            outPath = path';
1309            outputs = [ "out" ];
1310            out = res;
1311            outputName = "out";
1312          };
1313     in res;
1316   /**
1317     If `cond` is true, return the attribute set `as`,
1318     otherwise an empty attribute set.
1321     # Inputs
1323     `cond`
1325     : Condition under which the `as` attribute set is returned.
1327     `as`
1329     : The attribute set to return if `cond` is `true`.
1331     # Type
1333     ```
1334     optionalAttrs :: Bool -> AttrSet -> AttrSet
1335     ```
1337     # Examples
1338     :::{.example}
1339     ## `lib.attrsets.optionalAttrs` usage example
1341     ```nix
1342     optionalAttrs (true) { my = "set"; }
1343     => { my = "set"; }
1344     optionalAttrs (false) { my = "set"; }
1345     => { }
1346     ```
1348     :::
1349   */
1350   optionalAttrs =
1351     cond:
1352     as:
1353     if cond then as else {};
1356   /**
1357     Merge sets of attributes and use the function `f` to merge attributes
1358     values.
1361     # Inputs
1363     `names`
1365     : List of attribute names to zip.
1367     `f`
1369     : A function, accepts an attribute name, all the values, and returns a combined value.
1371     `sets`
1373     : List of values from the list of attribute sets.
1375     # Type
1377     ```
1378     zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
1379     ```
1381     # Examples
1382     :::{.example}
1383     ## `lib.attrsets.zipAttrsWithNames` usage example
1385     ```nix
1386     zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
1387     => { a = ["x" "y"]; }
1388     ```
1390     :::
1391   */
1392   zipAttrsWithNames =
1393     names:
1394     f:
1395     sets:
1396     listToAttrs (map (name: {
1397       inherit name;
1398       value = f name (catAttrs name sets);
1399     }) names);
1402   /**
1403     Merge sets of attributes and use the function f to merge attribute values.
1404     Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`.
1406     Implementation note: Common names appear multiple times in the list of
1407     names, hopefully this does not affect the system because the maximal
1408     laziness avoid computing twice the same expression and `listToAttrs` does
1409     not care about duplicated attribute names.
1411     # Type
1413     ```
1414     zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
1415     ```
1417     # Examples
1418     :::{.example}
1419     ## `lib.attrsets.zipAttrsWith` usage example
1421     ```nix
1422     zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
1423     => { a = ["x" "y"]; b = ["z"]; }
1424     ```
1426     :::
1427   */
1428   zipAttrsWith =
1429     builtins.zipAttrsWith or (f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets);
1432   /**
1433     Merge sets of attributes and combine each attribute value in to a list.
1435     Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function.
1437     # Type
1439     ```
1440     zipAttrs :: [ AttrSet ] -> AttrSet
1441     ```
1443     # Examples
1444     :::{.example}
1445     ## `lib.attrsets.zipAttrs` usage example
1447     ```nix
1448     zipAttrs [{a = "x";} {a = "y"; b = "z";}]
1449     => { a = ["x" "y"]; b = ["z"]; }
1450     ```
1452     :::
1453   */
1454   zipAttrs = zipAttrsWith (name: values: values);
1456   /**
1457     Merge a list of attribute sets together using the `//` operator.
1458     In case of duplicate attributes, values from later list elements take precedence over earlier ones.
1459     The result is the same as `foldl mergeAttrs { }`, but the performance is better for large inputs.
1460     For n list elements, each with an attribute set containing m unique attributes, the complexity of this operation is O(nm log n).
1463     # Inputs
1465     `list`
1467     : 1\. Function argument
1469     # Type
1471     ```
1472     mergeAttrsList :: [ Attrs ] -> Attrs
1473     ```
1475     # Examples
1476     :::{.example}
1477     ## `lib.attrsets.mergeAttrsList` usage example
1479     ```nix
1480     mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ]
1481     => { a = 0; b = 1; c = 2; d = 3; }
1482     mergeAttrsList [ { a = 0; } { a = 1; } ]
1483     => { a = 1; }
1484     ```
1486     :::
1487   */
1488   mergeAttrsList = list:
1489     let
1490       # `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end`
1491       # Type: Int -> Int -> Attrs
1492       binaryMerge = start: end:
1493         # assert start < end; # Invariant
1494         if end - start >= 2 then
1495           # If there's at least 2 elements, split the range in two, recurse on each part and merge the result
1496           # The invariant is satisfied because each half will have at least 1 element
1497           binaryMerge start (start + (end - start) / 2)
1498           // binaryMerge (start + (end - start) / 2) end
1499         else
1500           # Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly
1501           elemAt list start;
1502     in
1503     if list == [ ] then
1504       # Calling binaryMerge as below would not satisfy its invariant
1505       { }
1506     else
1507       binaryMerge 0 (length list);
1510   /**
1511     Does the same as the update operator '//' except that attributes are
1512     merged until the given predicate is verified.  The predicate should
1513     accept 3 arguments which are the path to reach the attribute, a part of
1514     the first attribute set and a part of the second attribute set.  When
1515     the predicate is satisfied, the value of the first attribute set is
1516     replaced by the value of the second attribute set.
1519     # Inputs
1521     `pred`
1523     : 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.
1525     `lhs`
1527     : Left attribute set of the merge.
1529     `rhs`
1531     : Right attribute set of the merge.
1533     # Type
1535     ```
1536     recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet
1537     ```
1539     # Examples
1540     :::{.example}
1541     ## `lib.attrsets.recursiveUpdateUntil` usage example
1543     ```nix
1544     recursiveUpdateUntil (path: l: r: path == ["foo"]) {
1545       # first attribute set
1546       foo.bar = 1;
1547       foo.baz = 2;
1548       bar = 3;
1549     } {
1550       #second attribute set
1551       foo.bar = 1;
1552       foo.quz = 2;
1553       baz = 4;
1554     }
1556     => {
1557       foo.bar = 1; # 'foo.*' from the second set
1558       foo.quz = 2; #
1559       bar = 3;     # 'bar' from the first set
1560       baz = 4;     # 'baz' from the second set
1561     }
1562     ```
1564     :::
1565   */
1566   recursiveUpdateUntil =
1567     pred:
1568     lhs:
1569     rhs:
1570     let f = attrPath:
1571       zipAttrsWith (n: values:
1572         let here = attrPath ++ [n]; in
1573         if length values == 1
1574         || pred here (elemAt values 1) (head values) then
1575           head values
1576         else
1577           f here values
1578       );
1579     in f [] [rhs lhs];
1582   /**
1583     A recursive variant of the update operator â€˜//’.  The recursion
1584     stops when one of the attribute values is not an attribute set,
1585     in which case the right hand side value takes precedence over the
1586     left hand side value.
1589     # Inputs
1591     `lhs`
1593     : Left attribute set of the merge.
1595     `rhs`
1597     : Right attribute set of the merge.
1599     # Type
1601     ```
1602     recursiveUpdate :: AttrSet -> AttrSet -> AttrSet
1603     ```
1605     # Examples
1606     :::{.example}
1607     ## `lib.attrsets.recursiveUpdate` usage example
1609     ```nix
1610     recursiveUpdate {
1611       boot.loader.grub.enable = true;
1612       boot.loader.grub.device = "/dev/hda";
1613     } {
1614       boot.loader.grub.device = "";
1615     }
1617     returns: {
1618       boot.loader.grub.enable = true;
1619       boot.loader.grub.device = "";
1620     }
1621     ```
1623     :::
1624   */
1625   recursiveUpdate =
1626     lhs:
1627     rhs:
1628     recursiveUpdateUntil (path: lhs: rhs: !(isAttrs lhs && isAttrs rhs)) lhs rhs;
1631   /**
1632     Recurse into every attribute set of the first argument and check that:
1633     - Each attribute path also exists in the second argument.
1634     - If the attribute's value is not a nested attribute set, it must have the same value in the right argument.
1637     # Inputs
1639     `pattern`
1641     : Attribute set structure to match
1643     `attrs`
1645     : Attribute set to check
1647     # Type
1649     ```
1650     matchAttrs :: AttrSet -> AttrSet -> Bool
1651     ```
1653     # Examples
1654     :::{.example}
1655     ## `lib.attrsets.matchAttrs` usage example
1657     ```nix
1658     matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
1659     => true
1660     ```
1662     :::
1663   */
1664   matchAttrs =
1665     pattern:
1666     attrs:
1667     assert isAttrs pattern;
1668     all
1669     ( # Compare equality between `pattern` & `attrs`.
1670       attr:
1671       # Missing attr, not equal.
1672       attrs ? ${attr} && (
1673         let
1674           lhs = pattern.${attr};
1675           rhs = attrs.${attr};
1676         in
1677         # If attrset check recursively
1678         if isAttrs lhs then isAttrs rhs && matchAttrs lhs rhs
1679         else lhs == rhs
1680       )
1681     )
1682     (attrNames pattern);
1684   /**
1685     Override only the attributes that are already present in the old set
1686     useful for deep-overriding.
1689     # Inputs
1691     `old`
1693     : Original attribute set
1695     `new`
1697     : Attribute set with attributes to override in `old`.
1699     # Type
1701     ```
1702     overrideExisting :: AttrSet -> AttrSet -> AttrSet
1703     ```
1705     # Examples
1706     :::{.example}
1707     ## `lib.attrsets.overrideExisting` usage example
1709     ```nix
1710     overrideExisting {} { a = 1; }
1711     => {}
1712     overrideExisting { b = 2; } { a = 1; }
1713     => { b = 2; }
1714     overrideExisting { a = 3; b = 2; } { a = 1; }
1715     => { a = 1; b = 2; }
1716     ```
1718     :::
1719   */
1720   overrideExisting =
1721     old:
1722     new:
1723     mapAttrs (name: value: new.${name} or value) old;
1726   /**
1727     Turns a list of strings into a human-readable description of those
1728     strings represented as an attribute path. The result of this function is
1729     not intended to be machine-readable.
1730     Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
1733     # Inputs
1735     `path`
1737     : Attribute path to render to a string
1739     # Type
1741     ```
1742     showAttrPath :: [String] -> String
1743     ```
1745     # Examples
1746     :::{.example}
1747     ## `lib.attrsets.showAttrPath` usage example
1749     ```nix
1750     showAttrPath [ "foo" "10" "bar" ]
1751     => "foo.\"10\".bar"
1752     showAttrPath []
1753     => "<root attribute path>"
1754     ```
1756     :::
1757   */
1758   showAttrPath =
1759     path:
1760     if path == [] then "<root attribute path>"
1761     else concatMapStringsSep "." escapeNixIdentifier path;
1764   /**
1765     Get a package output.
1766     If no output is found, fallback to `.out` and then to the default.
1769     # Inputs
1771     `output`
1773     : 1\. Function argument
1775     `pkg`
1777     : 2\. Function argument
1779     # Type
1781     ```
1782     getOutput :: String -> Derivation -> String
1783     ```
1785     # Examples
1786     :::{.example}
1787     ## `lib.attrsets.getOutput` usage example
1789     ```nix
1790     getOutput "dev" pkgs.openssl
1791     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1792     ```
1794     :::
1795   */
1796   getOutput = output: pkg:
1797     if ! pkg ? outputSpecified || ! pkg.outputSpecified
1798       then pkg.${output} or pkg.out or pkg
1799       else pkg;
1801   /**
1802     Get a package's `bin` output.
1803     If the output does not exist, fallback to `.out` and then to the default.
1805     # Inputs
1807     `pkg`
1809     : The package whose `bin` output will be retrieved.
1811     # Type
1813     ```
1814     getBin :: Derivation -> String
1815     ```
1817     # Examples
1818     :::{.example}
1819     ## `lib.attrsets.getBin` usage example
1821     ```nix
1822     getBin pkgs.openssl
1823     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r"
1824     ```
1826     :::
1827   */
1828   getBin = getOutput "bin";
1831   /**
1832     Get a package's `lib` output.
1833     If the output does not exist, fallback to `.out` and then to the default.
1835     # Inputs
1837     `pkg`
1839     : The package whose `lib` output will be retrieved.
1841     # Type
1843     ```
1844     getLib :: Derivation -> String
1845     ```
1847     # Examples
1848     :::{.example}
1849     ## `lib.attrsets.getLib` usage example
1851     ```nix
1852     getLib pkgs.openssl
1853     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib"
1854     ```
1856     :::
1857   */
1858   getLib = getOutput "lib";
1861   /**
1862     Get a package's `dev` output.
1863     If the output does not exist, fallback to `.out` and then to the default.
1865     # Inputs
1867     `pkg`
1869     : The package whose `dev` output will be retrieved.
1871     # Type
1873     ```
1874     getDev :: Derivation -> String
1875     ```
1877     # Examples
1878     :::{.example}
1879     ## `lib.attrsets.getDev` usage example
1881     ```nix
1882     getDev pkgs.openssl
1883     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1884     ```
1886     :::
1887   */
1888   getDev = getOutput "dev";
1891   /**
1892     Get a package's `man` output.
1893     If the output does not exist, fallback to `.out` and then to the default.
1895     # Inputs
1897     `pkg`
1899     : The package whose `man` output will be retrieved.
1901     # Type
1903     ```
1904     getMan :: Derivation -> String
1905     ```
1907     # Examples
1908     :::{.example}
1909     ## `lib.attrsets.getMan` usage example
1911     ```nix
1912     getMan pkgs.openssl
1913     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man"
1914     ```
1916     :::
1917   */
1918   getMan = getOutput "man";
1920   /**
1921     Pick the outputs of packages to place in `buildInputs`
1923     # Inputs
1925     `pkgs`
1927     : List of packages.
1929     # Type
1931     ```
1932     chooseDevOutputs :: [Derivation] -> [String]
1933     ```
1934   */
1935   chooseDevOutputs = builtins.map getDev;
1937   /**
1938     Make various Nix tools consider the contents of the resulting
1939     attribute set when looking for what to build, find, etc.
1941     This function only affects a single attribute set; it does not
1942     apply itself recursively for nested attribute sets.
1945     # Inputs
1947     `attrs`
1949     : An attribute set to scan for derivations.
1951     # Type
1953     ```
1954     recurseIntoAttrs :: AttrSet -> AttrSet
1955     ```
1957     # Examples
1958     :::{.example}
1959     ## `lib.attrsets.recurseIntoAttrs` usage example
1961     ```nix
1962     { pkgs ? import <nixpkgs> {} }:
1963     {
1964       myTools = pkgs.lib.recurseIntoAttrs {
1965         inherit (pkgs) hello figlet;
1966       };
1967     }
1968     ```
1970     :::
1971   */
1972   recurseIntoAttrs =
1973     attrs:
1974     attrs // { recurseForDerivations = true; };
1976   /**
1977     Undo the effect of recurseIntoAttrs.
1980     # Inputs
1982     `attrs`
1984     : An attribute set to not scan for derivations.
1986     # Type
1988     ```
1989     dontRecurseIntoAttrs :: AttrSet -> AttrSet
1990     ```
1991   */
1992   dontRecurseIntoAttrs =
1993     attrs:
1994     attrs // { recurseForDerivations = false; };
1996   /**
1997     `unionOfDisjoint x y` is equal to `x // y // z` where the
1998     attrnames in `z` are the intersection of the attrnames in `x` and
1999     `y`, and all values `assert` with an error message.  This
2000      operator is commutative, unlike (//).
2003     # Inputs
2005     `x`
2007     : 1\. Function argument
2009     `y`
2011     : 2\. Function argument
2013     # Type
2015     ```
2016     unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet
2017     ```
2018   */
2019   unionOfDisjoint = x: y:
2020     let
2021       intersection = builtins.intersectAttrs x y;
2022       collisions = lib.concatStringsSep " " (builtins.attrNames intersection);
2023       mask = builtins.mapAttrs (name: value: builtins.throw
2024         "unionOfDisjoint: collision on ${name}; complete list: ${collisions}")
2025         intersection;
2026     in
2027       (x // y) // mask;
2029   # DEPRECATED
2030   zipWithNames = warn
2031     "lib.zipWithNames is a deprecated alias of lib.zipAttrsWithNames." zipAttrsWithNames;
2033   # DEPRECATED
2034   zip = warn
2035     "lib.zip is a deprecated alias of lib.zipAttrsWith." zipAttrsWith;
2037   # DEPRECATED
2038   cartesianProductOfSets = warnIf (isInOldestRelease 2405)
2039     "lib.cartesianProductOfSets is a deprecated alias of lib.cartesianProduct." cartesianProduct;