Merge pull request #270774 from emilytrau/libbacktrace-musl
[NixPkgs.git] / lib / attrsets.nix
blob3d4366ce18141227aab78cb18b30095eed12d8f4
1 /* Operations on attribute sets. */
2 { lib }:
4 let
5   inherit (builtins) head tail length;
6   inherit (lib.trivial) id mergeAttrs;
7   inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName;
8   inherit (lib.lists) foldr foldl' concatMap concatLists elemAt all partition groupBy take foldl;
9 in
11 rec {
12   inherit (builtins) attrNames listToAttrs hasAttr isAttrs getAttr removeAttrs;
15   /* Return an attribute from nested attribute sets.
17      Example:
18        x = { a = { b = 3; }; }
19        # ["a" "b"] is equivalent to x.a.b
20        # 6 is a default value to return if the path does not exist in attrset
21        attrByPath ["a" "b"] 6 x
22        => 3
23        attrByPath ["z" "z"] 6 x
24        => 6
26      Type:
27        attrByPath :: [String] -> Any -> AttrSet -> Any
29   */
30   attrByPath =
31     # A list of strings representing the attribute path to return from `set`
32     attrPath:
33     # Default value if `attrPath` does not resolve to an existing value
34     default:
35     # The nested attribute set to select values from
36     set:
37     let
38       lenAttrPath = length attrPath;
39       attrByPath' = n: s: (
40         if n == lenAttrPath then s
41         else (
42           let
43             attr = elemAt attrPath n;
44           in
45           if s ? ${attr} then attrByPath' (n + 1) s.${attr}
46           else default
47         )
48       );
49     in
50       attrByPath' 0 set;
52   /* Return if an attribute from nested attribute set exists.
54      Example:
55        x = { a = { b = 3; }; }
56        hasAttrByPath ["a" "b"] x
57        => true
58        hasAttrByPath ["z" "z"] x
59        => false
61     Type:
62       hasAttrByPath :: [String] -> AttrSet -> Bool
63   */
64   hasAttrByPath =
65     # A list of strings representing the attribute path to check from `set`
66     attrPath:
67     # The nested attribute set to check
68     e:
69     let
70       lenAttrPath = length attrPath;
71       hasAttrByPath' = n: s: (
72         n == lenAttrPath || (
73           let
74             attr = elemAt attrPath n;
75           in
76           if s ? ${attr} then hasAttrByPath' (n + 1) s.${attr}
77           else false
78         )
79       );
80     in
81       hasAttrByPath' 0 e;
83   /* Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
85      Example:
86        setAttrByPath ["a" "b"] 3
87        => { a = { b = 3; }; }
89      Type:
90        setAttrByPath :: [String] -> Any -> AttrSet
91   */
92   setAttrByPath =
93     # A list of strings representing the attribute path to set
94     attrPath:
95     # The value to set at the location described by `attrPath`
96     value:
97     let
98       len = length attrPath;
99       atDepth = n:
100         if n == len
101         then value
102         else { ${elemAt attrPath n} = atDepth (n + 1); };
103     in atDepth 0;
105   /* Like `attrByPath`, but without a default value. If it doesn't find the
106      path it will throw an error.
108      Example:
109        x = { a = { b = 3; }; }
110        getAttrFromPath ["a" "b"] x
111        => 3
112        getAttrFromPath ["z" "z"] x
113        => error: cannot find attribute `z.z'
115      Type:
116        getAttrFromPath :: [String] -> AttrSet -> Any
117   */
118   getAttrFromPath =
119     # A list of strings representing the attribute path to get from `set`
120     attrPath:
121     # The nested attribute set to find the value in.
122     set:
123     let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
124     in attrByPath attrPath (abort errorMsg) set;
126   /* Map each attribute in the given set and merge them into a new attribute set.
128      Type:
129        concatMapAttrs :: (String -> a -> AttrSet) -> AttrSet -> AttrSet
131      Example:
132        concatMapAttrs
133          (name: value: {
134            ${name} = value;
135            ${name + value} = value;
136          })
137          { x = "a"; y = "b"; }
138        => { x = "a"; xa = "a"; y = "b"; yb = "b"; }
139   */
140   concatMapAttrs = f: v:
141     foldl' mergeAttrs { }
142       (attrValues
143         (mapAttrs f v)
144       );
147   /* Update or set specific paths of an attribute set.
149      Takes a list of updates to apply and an attribute set to apply them to,
150      and returns the attribute set with the updates applied. Updates are
151      represented as `{ path = ...; update = ...; }` values, where `path` is a
152      list of strings representing the attribute path that should be updated,
153      and `update` is a function that takes the old value at that attribute path
154      as an argument and returns the new
155      value it should be.
157      Properties:
159      - Updates to deeper attribute paths are applied before updates to more
160        shallow attribute paths
162      - Multiple updates to the same attribute path are applied in the order
163        they appear in the update list
165      - If any but the last `path` element leads into a value that is not an
166        attribute set, an error is thrown
168      - If there is an update for an attribute path that doesn't exist,
169        accessing the argument in the update function causes an error, but
170        intermediate attribute sets are implicitly created as needed
172      Example:
173        updateManyAttrsByPath [
174          {
175            path = [ "a" "b" ];
176            update = old: { d = old.c; };
177          }
178          {
179            path = [ "a" "b" "c" ];
180            update = old: old + 1;
181          }
182          {
183            path = [ "x" "y" ];
184            update = old: "xy";
185          }
186        ] { a.b.c = 0; }
187        => { a = { b = { d = 1; }; }; x = { y = "xy"; }; }
189     Type: updateManyAttrsByPath :: [{ path :: [String]; update :: (Any -> Any); }] -> AttrSet -> AttrSet
190   */
191   updateManyAttrsByPath = let
192     # When recursing into attributes, instead of updating the `path` of each
193     # update using `tail`, which needs to allocate an entirely new list,
194     # we just pass a prefix length to use and make sure to only look at the
195     # path without the prefix length, so that we can reuse the original list
196     # entries.
197     go = prefixLength: hasValue: value: updates:
198       let
199         # Splits updates into ones on this level (split.right)
200         # And ones on levels further down (split.wrong)
201         split = partition (el: length el.path == prefixLength) updates;
203         # Groups updates on further down levels into the attributes they modify
204         nested = groupBy (el: elemAt el.path prefixLength) split.wrong;
206         # Applies only nested modification to the input value
207         withNestedMods =
208           # Return the value directly if we don't have any nested modifications
209           if split.wrong == [] then
210             if hasValue then value
211             else
212               # Throw an error if there is no value. This `head` call here is
213               # safe, but only in this branch since `go` could only be called
214               # with `hasValue == false` for nested updates, in which case
215               # it's also always called with at least one update
216               let updatePath = (head split.right).path; in
217               throw
218               ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' does "
219               + "not exist in the given value, but the first update to this "
220               + "path tries to access the existing value.")
221           else
222             # If there are nested modifications, try to apply them to the value
223             if ! hasValue then
224               # But if we don't have a value, just use an empty attribute set
225               # as the value, but simplify the code a bit
226               mapAttrs (name: go (prefixLength + 1) false null) nested
227             else if isAttrs value then
228               # If we do have a value and it's an attribute set, override it
229               # with the nested modifications
230               value //
231               mapAttrs (name: go (prefixLength + 1) (value ? ${name}) value.${name}) nested
232             else
233               # However if it's not an attribute set, we can't apply the nested
234               # modifications, throw an error
235               let updatePath = (head split.wrong).path; in
236               throw
237               ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' needs to "
238               + "be updated, but path '${showAttrPath (take prefixLength updatePath)}' "
239               + "of the given value is not an attribute set, so we can't "
240               + "update an attribute inside of it.");
242         # We get the final result by applying all the updates on this level
243         # after having applied all the nested updates
244         # We use foldl instead of foldl' so that in case of multiple updates,
245         # intermediate values aren't evaluated if not needed
246       in foldl (acc: el: el.update acc) withNestedMods split.right;
248   in updates: value: go 0 true value updates;
250   /* Return the specified attributes from a set.
252      Example:
253        attrVals ["a" "b" "c"] as
254        => [as.a as.b as.c]
256      Type:
257        attrVals :: [String] -> AttrSet -> [Any]
258   */
259   attrVals =
260     # The list of attributes to fetch from `set`. Each attribute name must exist on the attrbitue set
261     nameList:
262     # The set to get attribute values from
263     set: map (x: set.${x}) nameList;
266   /* Return the values of all attributes in the given set, sorted by
267      attribute name.
269      Example:
270        attrValues {c = 3; a = 1; b = 2;}
271        => [1 2 3]
273      Type:
274        attrValues :: AttrSet -> [Any]
275   */
276   attrValues = builtins.attrValues or (attrs: attrVals (attrNames attrs) attrs);
279   /* Given a set of attribute names, return the set of the corresponding
280      attributes from the given set.
282      Example:
283        getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; }
284        => { a = 1; b = 2; }
286      Type:
287        getAttrs :: [String] -> AttrSet -> AttrSet
288   */
289   getAttrs =
290     # A list of attribute names to get out of `set`
291     names:
292     # The set to get the named attributes from
293     attrs: genAttrs names (name: attrs.${name});
295   /* Collect each attribute named `attr` from a list of attribute
296      sets.  Sets that don't contain the named attribute are ignored.
298      Example:
299        catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
300        => [1 2]
302      Type:
303        catAttrs :: String -> [AttrSet] -> [Any]
304   */
305   catAttrs = builtins.catAttrs or
306     (attr: l: concatLists (map (s: if s ? ${attr} then [s.${attr}] else []) l));
309   /* Filter an attribute set by removing all attributes for which the
310      given predicate return false.
312      Example:
313        filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; }
314        => { foo = 1; }
316      Type:
317        filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet
318   */
319   filterAttrs =
320     # Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
321     pred:
322     # The attribute set to filter
323     set:
324     listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set));
327   /* Filter an attribute set recursively by removing all attributes for
328      which the given predicate return false.
330      Example:
331        filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; }
332        => { foo = {}; }
334      Type:
335        filterAttrsRecursive :: (String -> Any -> Bool) -> AttrSet -> AttrSet
336   */
337   filterAttrsRecursive =
338     # Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
339     pred:
340     # The attribute set to filter
341     set:
342     listToAttrs (
343       concatMap (name:
344         let v = set.${name}; in
345         if pred name v then [
346           (nameValuePair name (
347             if isAttrs v then filterAttrsRecursive pred v
348             else v
349           ))
350         ] else []
351       ) (attrNames set)
352     );
354    /*
355     Like [`lib.lists.foldl'`](#function-library-lib.lists.foldl-prime) but for attribute sets.
356     Iterates over every name-value pair in the given attribute set.
357     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`.
359     Attention:
360       There is a completely different function
361       `lib.foldAttrs`
362       which has nothing to do with this function, despite the similar name.
364     Example:
365       foldlAttrs
366         (acc: name: value: {
367           sum = acc.sum + value;
368           names = acc.names ++ [name];
369         })
370         { sum = 0; names = []; }
371         {
372           foo = 1;
373           bar = 10;
374         }
375       ->
376         {
377           sum = 11;
378           names = ["bar" "foo"];
379         }
381       foldlAttrs
382         (throw "function not needed")
383         123
384         {};
385       ->
386         123
388       foldlAttrs
389         (acc: _: _: acc)
390         3
391         { z = throw "value not needed"; a = throw "value not needed"; };
392       ->
393         3
395       The accumulator doesn't have to be an attrset.
396       It can be as simple as a number or string.
398       foldlAttrs
399         (acc: _: v: acc * 10 + v)
400         1
401         { z = 1; a = 2; };
402       ->
403         121
405     Type:
406       foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a
407   */
408   foldlAttrs = f: init: set:
409     foldl'
410       (acc: name: f acc name set.${name})
411       init
412       (attrNames set);
414   /* Apply fold functions to values grouped by key.
416      Example:
417        foldAttrs (item: acc: [item] ++ acc) [] [{ a = 2; } { a = 3; }]
418        => { a = [ 2 3 ]; }
420      Type:
421        foldAttrs :: (Any -> Any -> Any) -> Any -> [AttrSets] -> Any
423   */
424   foldAttrs =
425     # A function, given a value and a collector combines the two.
426     op:
427     # The starting value.
428     nul:
429     # A list of attribute sets to fold together by key.
430     list_of_attrs:
431     foldr (n: a:
432         foldr (name: o:
433           o // { ${name} = op n.${name} (a.${name} or nul); }
434         ) a (attrNames n)
435     ) {} list_of_attrs;
438   /* Recursively collect sets that verify a given predicate named `pred`
439      from the set `attrs`.  The recursion is stopped when the predicate is
440      verified.
442      Example:
443        collect isList { a = { b = ["b"]; }; c = [1]; }
444        => [["b"] [1]]
446        collect (x: x ? outPath)
447           { a = { outPath = "a/"; }; b = { outPath = "b/"; }; }
448        => [{ outPath = "a/"; } { outPath = "b/"; }]
450      Type:
451        collect :: (AttrSet -> Bool) -> AttrSet -> [x]
452   */
453   collect =
454   # Given an attribute's value, determine if recursion should stop.
455   pred:
456   # The attribute set to recursively collect.
457   attrs:
458     if pred attrs then
459       [ attrs ]
460     else if isAttrs attrs then
461       concatMap (collect pred) (attrValues attrs)
462     else
463       [];
465   /* Return the cartesian product of attribute set value combinations.
467     Example:
468       cartesianProductOfSets { a = [ 1 2 ]; b = [ 10 20 ]; }
469       => [
470            { a = 1; b = 10; }
471            { a = 1; b = 20; }
472            { a = 2; b = 10; }
473            { a = 2; b = 20; }
474          ]
475      Type:
476        cartesianProductOfSets :: AttrSet -> [AttrSet]
477   */
478   cartesianProductOfSets =
479     # Attribute set with attributes that are lists of values
480     attrsOfLists:
481     foldl' (listOfAttrs: attrName:
482       concatMap (attrs:
483         map (listValue: attrs // { ${attrName} = listValue; }) attrsOfLists.${attrName}
484       ) listOfAttrs
485     ) [{}] (attrNames attrsOfLists);
488   /* Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`.
490      Example:
491        nameValuePair "some" 6
492        => { name = "some"; value = 6; }
494      Type:
495        nameValuePair :: String -> Any -> { name :: String; value :: Any; }
496   */
497   nameValuePair =
498     # Attribute name
499     name:
500     # Attribute value
501     value:
502     { inherit name value; };
505   /* Apply a function to each element in an attribute set, creating a new attribute set.
507      Example:
508        mapAttrs (name: value: name + "-" + value)
509           { x = "foo"; y = "bar"; }
510        => { x = "x-foo"; y = "y-bar"; }
512      Type:
513        mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet
514   */
515   mapAttrs = builtins.mapAttrs or
516     (f: set:
517       listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)));
520   /* Like `mapAttrs`, but allows the name of each attribute to be
521      changed in addition to the value.  The applied function should
522      return both the new name and value as a `nameValuePair`.
524      Example:
525        mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value))
526           { x = "a"; y = "b"; }
527        => { foo_x = "bar-a"; foo_y = "bar-b"; }
529      Type:
530        mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet
531   */
532   mapAttrs' =
533     # A function, given an attribute's name and value, returns a new `nameValuePair`.
534     f:
535     # Attribute set to map over.
536     set:
537     listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
540   /* Call a function for each attribute in the given set and return
541      the result in a list.
543      Example:
544        mapAttrsToList (name: value: name + value)
545           { x = "a"; y = "b"; }
546        => [ "xa" "yb" ]
548      Type:
549        mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b]
551   */
552   mapAttrsToList =
553     # A function, given an attribute's name and value, returns a new value.
554     f:
555     # Attribute set to map over.
556     attrs:
557     map (name: f name attrs.${name}) (attrNames attrs);
559   /*
560     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).
561     Each element of the resulting list is an attribute set with these attributes:
562     - `name` (string): The name of the attribute
563     - `value` (any): The value of the attribute
565     The following is always true:
566     ```nix
567     builtins.listToAttrs (attrsToList attrs) == attrs
568     ```
570     :::{.warning}
571     The opposite is not always true. In general expect that
572     ```nix
573     attrsToList (builtins.listToAttrs list) != list
574     ```
576     This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
577     :::
579     Example:
580       attrsToList { foo = 1; bar = "asdf"; }
581       => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
583     Type:
584       attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
586   */
587   attrsToList = mapAttrsToList nameValuePair;
590   /* Like `mapAttrs`, except that it recursively applies itself to
591      the *leaf* attributes of a potentially-nested attribute set:
592      the second argument of the function will never be an attrset.
593      Also, the first argument of the argument function is a *list*
594      of the attribute names that form the path to the leaf attribute.
596      For a function that gives you control over what counts as a leaf,
597      see `mapAttrsRecursiveCond`.
599      Example:
600        mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
601          { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
602        => { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
604      Type:
605        mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet
606   */
607   mapAttrsRecursive =
608     # A function, given a list of attribute names and a value, returns a new value.
609     f:
610     # Set to recursively map over.
611     set:
612     mapAttrsRecursiveCond (as: true) f set;
615   /* Like `mapAttrsRecursive`, but it takes an additional predicate
616      function that tells it whether to recurse into an attribute
617      set.  If it returns false, `mapAttrsRecursiveCond` does not
618      recurse, but does apply the map function.  If it returns true, it
619      does recurse, and does not apply the map function.
621      Example:
622        # To prevent recursing into derivations (which are attribute
623        # sets with the attribute "type" equal to "derivation"):
624        mapAttrsRecursiveCond
625          (as: !(as ? "type" && as.type == "derivation"))
626          (x: ... do something ...)
627          attrs
629      Type:
630        mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
631   */
632   mapAttrsRecursiveCond =
633     # A function, given the attribute set the recursion is currently at, determine if to recurse deeper into that attribute set.
634     cond:
635     # A function, given a list of attribute names and a value, returns a new value.
636     f:
637     # Attribute set to recursively map over.
638     set:
639     let
640       recurse = path:
641         let
642           g =
643             name: value:
644             if isAttrs value && cond value
645               then recurse (path ++ [name]) value
646               else f (path ++ [name]) value;
647         in mapAttrs g;
648     in recurse [] set;
651   /* Generate an attribute set by mapping a function over a list of
652      attribute names.
654      Example:
655        genAttrs [ "foo" "bar" ] (name: "x_" + name)
656        => { foo = "x_foo"; bar = "x_bar"; }
658      Type:
659        genAttrs :: [ String ] -> (String -> Any) -> AttrSet
660   */
661   genAttrs =
662     # Names of values in the resulting attribute set.
663     names:
664     # A function, given the name of the attribute, returns the attribute's value.
665     f:
666     listToAttrs (map (n: nameValuePair n (f n)) names);
669   /* Check whether the argument is a derivation. Any set with
670      `{ type = "derivation"; }` counts as a derivation.
672      Example:
673        nixpkgs = import <nixpkgs> {}
674        isDerivation nixpkgs.ruby
675        => true
676        isDerivation "foobar"
677        => false
679      Type:
680        isDerivation :: Any -> Bool
681   */
682   isDerivation =
683     # Value to check.
684     value: value.type or null == "derivation";
686    /* Converts a store path to a fake derivation.
688       Type:
689         toDerivation :: Path -> Derivation
690    */
691    toDerivation =
692      # A store path to convert to a derivation.
693      path:
694      let
695        path' = builtins.storePath path;
696        res =
697          { type = "derivation";
698            name = sanitizeDerivationName (builtins.substring 33 (-1) (baseNameOf path'));
699            outPath = path';
700            outputs = [ "out" ];
701            out = res;
702            outputName = "out";
703          };
704     in res;
707   /* If `cond` is true, return the attribute set `as`,
708      otherwise an empty attribute set.
710      Example:
711        optionalAttrs (true) { my = "set"; }
712        => { my = "set"; }
713        optionalAttrs (false) { my = "set"; }
714        => { }
716      Type:
717        optionalAttrs :: Bool -> AttrSet -> AttrSet
718   */
719   optionalAttrs =
720     # Condition under which the `as` attribute set is returned.
721     cond:
722     # The attribute set to return if `cond` is `true`.
723     as:
724     if cond then as else {};
727   /* Merge sets of attributes and use the function `f` to merge attributes
728      values.
730      Example:
731        zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
732        => { a = ["x" "y"]; }
734      Type:
735        zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
736   */
737   zipAttrsWithNames =
738     # List of attribute names to zip.
739     names:
740     # A function, accepts an attribute name, all the values, and returns a combined value.
741     f:
742     # List of values from the list of attribute sets.
743     sets:
744     listToAttrs (map (name: {
745       inherit name;
746       value = f name (catAttrs name sets);
747     }) names);
750   /* Merge sets of attributes and use the function f to merge attribute values.
751      Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`.
753      Implementation note: Common names appear multiple times in the list of
754      names, hopefully this does not affect the system because the maximal
755      laziness avoid computing twice the same expression and `listToAttrs` does
756      not care about duplicated attribute names.
758      Example:
759        zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
760        => { a = ["x" "y"]; b = ["z"]; }
762      Type:
763        zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
764   */
765   zipAttrsWith =
766     builtins.zipAttrsWith or (f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets);
769   /* Merge sets of attributes and combine each attribute value in to a list.
771      Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function.
773      Example:
774        zipAttrs [{a = "x";} {a = "y"; b = "z";}]
775        => { a = ["x" "y"]; b = ["z"]; }
777      Type:
778        zipAttrs :: [ AttrSet ] -> AttrSet
779   */
780   zipAttrs =
781     # List of attribute sets to zip together.
782     sets:
783     zipAttrsWith (name: values: values) sets;
785   /*
786     Merge a list of attribute sets together using the `//` operator.
787     In case of duplicate attributes, values from later list elements take precedence over earlier ones.
788     The result is the same as `foldl mergeAttrs { }`, but the performance is better for large inputs.
789     For n list elements, each with an attribute set containing m unique attributes, the complexity of this operation is O(nm log n).
791     Type:
792       mergeAttrsList :: [ Attrs ] -> Attrs
794     Example:
795       mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ]
796       => { a = 0; b = 1; c = 2; d = 3; }
797       mergeAttrsList [ { a = 0; } { a = 1; } ]
798       => { a = 1; }
799   */
800   mergeAttrsList = list:
801     let
802       # `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end`
803       # Type: Int -> Int -> Attrs
804       binaryMerge = start: end:
805         # assert start < end; # Invariant
806         if end - start >= 2 then
807           # If there's at least 2 elements, split the range in two, recurse on each part and merge the result
808           # The invariant is satisfied because each half will have at least 1 element
809           binaryMerge start (start + (end - start) / 2)
810           // binaryMerge (start + (end - start) / 2) end
811         else
812           # Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly
813           elemAt list start;
814     in
815     if list == [ ] then
816       # Calling binaryMerge as below would not satisfy its invariant
817       { }
818     else
819       binaryMerge 0 (length list);
822   /* Does the same as the update operator '//' except that attributes are
823      merged until the given predicate is verified.  The predicate should
824      accept 3 arguments which are the path to reach the attribute, a part of
825      the first attribute set and a part of the second attribute set.  When
826      the predicate is satisfied, the value of the first attribute set is
827      replaced by the value of the second attribute set.
829      Example:
830        recursiveUpdateUntil (path: l: r: path == ["foo"]) {
831          # first attribute set
832          foo.bar = 1;
833          foo.baz = 2;
834          bar = 3;
835        } {
836          #second attribute set
837          foo.bar = 1;
838          foo.quz = 2;
839          baz = 4;
840        }
842        => {
843          foo.bar = 1; # 'foo.*' from the second set
844          foo.quz = 2; #
845          bar = 3;     # 'bar' from the first set
846          baz = 4;     # 'baz' from the second set
847        }
849      Type:
850        recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet
851   */
852   recursiveUpdateUntil =
853     # 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.
854     pred:
855     # Left attribute set of the merge.
856     lhs:
857     # Right attribute set of the merge.
858     rhs:
859     let f = attrPath:
860       zipAttrsWith (n: values:
861         let here = attrPath ++ [n]; in
862         if length values == 1
863         || pred here (elemAt values 1) (head values) then
864           head values
865         else
866           f here values
867       );
868     in f [] [rhs lhs];
871   /* A recursive variant of the update operator ‘//’.  The recursion
872      stops when one of the attribute values is not an attribute set,
873      in which case the right hand side value takes precedence over the
874      left hand side value.
876      Example:
877        recursiveUpdate {
878          boot.loader.grub.enable = true;
879          boot.loader.grub.device = "/dev/hda";
880        } {
881          boot.loader.grub.device = "";
882        }
884        returns: {
885          boot.loader.grub.enable = true;
886          boot.loader.grub.device = "";
887        }
889      Type:
890        recursiveUpdate :: AttrSet -> AttrSet -> AttrSet
891   */
892   recursiveUpdate =
893     # Left attribute set of the merge.
894     lhs:
895     # Right attribute set of the merge.
896     rhs:
897     recursiveUpdateUntil (path: lhs: rhs: !(isAttrs lhs && isAttrs rhs)) lhs rhs;
900   /*
901     Recurse into every attribute set of the first argument and check that:
902     - Each attribute path also exists in the second argument.
903     - If the attribute's value is not a nested attribute set, it must have the same value in the right argument.
905      Example:
906        matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
907        => true
909      Type:
910        matchAttrs :: AttrSet -> AttrSet -> Bool
911   */
912   matchAttrs =
913     # Attribute set structure to match
914     pattern:
915     # Attribute set to check
916     attrs:
917     assert isAttrs pattern;
918     all
919     ( # Compare equality between `pattern` & `attrs`.
920       attr:
921       # Missing attr, not equal.
922       attrs ? ${attr} && (
923         let
924           lhs = pattern.${attr};
925           rhs = attrs.${attr};
926         in
927         # If attrset check recursively
928         if isAttrs lhs then isAttrs rhs && matchAttrs lhs rhs
929         else lhs == rhs
930       )
931     )
932     (attrNames pattern);
934   /* Override only the attributes that are already present in the old set
935     useful for deep-overriding.
937     Example:
938       overrideExisting {} { a = 1; }
939       => {}
940       overrideExisting { b = 2; } { a = 1; }
941       => { b = 2; }
942       overrideExisting { a = 3; b = 2; } { a = 1; }
943       => { a = 1; b = 2; }
945     Type:
946       overrideExisting :: AttrSet -> AttrSet -> AttrSet
947   */
948   overrideExisting =
949     # Original attribute set
950     old:
951     # Attribute set with attributes to override in `old`.
952     new:
953     mapAttrs (name: value: new.${name} or value) old;
956   /* Turns a list of strings into a human-readable description of those
957     strings represented as an attribute path. The result of this function is
958     not intended to be machine-readable.
959     Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
961     Example:
962       showAttrPath [ "foo" "10" "bar" ]
963       => "foo.\"10\".bar"
964       showAttrPath []
965       => "<root attribute path>"
967     Type:
968       showAttrPath :: [String] -> String
969   */
970   showAttrPath =
971     # Attribute path to render to a string
972     path:
973     if path == [] then "<root attribute path>"
974     else concatMapStringsSep "." escapeNixIdentifier path;
977   /* Get a package output.
978      If no output is found, fallback to `.out` and then to the default.
980      Example:
981        getOutput "dev" pkgs.openssl
982        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
984      Type:
985        getOutput :: String -> Derivation -> String
986   */
987   getOutput = output: pkg:
988     if ! pkg ? outputSpecified || ! pkg.outputSpecified
989       then pkg.${output} or pkg.out or pkg
990       else pkg;
992   /* Get a package's `bin` output.
993      If the output does not exist, fallback to `.out` and then to the default.
995      Example:
996        getBin pkgs.openssl
997        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r"
999      Type:
1000        getBin :: Derivation -> String
1001   */
1002   getBin = getOutput "bin";
1005   /* Get a package's `lib` output.
1006      If the output does not exist, fallback to `.out` and then to the default.
1008      Example:
1009        getLib pkgs.openssl
1010        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib"
1012      Type:
1013        getLib :: Derivation -> String
1014   */
1015   getLib = getOutput "lib";
1018   /* Get a package's `dev` output.
1019      If the output does not exist, fallback to `.out` and then to the default.
1021      Example:
1022        getDev pkgs.openssl
1023        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1025      Type:
1026        getDev :: Derivation -> String
1027   */
1028   getDev = getOutput "dev";
1031   /* Get a package's `man` output.
1032      If the output does not exist, fallback to `.out` and then to the default.
1034      Example:
1035        getMan pkgs.openssl
1036        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man"
1038      Type:
1039        getMan :: Derivation -> String
1040   */
1041   getMan = getOutput "man";
1043   /* Pick the outputs of packages to place in `buildInputs`
1045    Type: chooseDevOutputs :: [Derivation] -> [String]
1047   */
1048   chooseDevOutputs =
1049     # List of packages to pick `dev` outputs from
1050     drvs:
1051     builtins.map getDev drvs;
1053   /* Make various Nix tools consider the contents of the resulting
1054      attribute set when looking for what to build, find, etc.
1056      This function only affects a single attribute set; it does not
1057      apply itself recursively for nested attribute sets.
1059      Example:
1060        { pkgs ? import <nixpkgs> {} }:
1061        {
1062          myTools = pkgs.lib.recurseIntoAttrs {
1063            inherit (pkgs) hello figlet;
1064          };
1065        }
1067      Type:
1068        recurseIntoAttrs :: AttrSet -> AttrSet
1070    */
1071   recurseIntoAttrs =
1072     # An attribute set to scan for derivations.
1073     attrs:
1074     attrs // { recurseForDerivations = true; };
1076   /* Undo the effect of recurseIntoAttrs.
1078      Type:
1079        dontRecurseIntoAttrs :: AttrSet -> AttrSet
1080    */
1081   dontRecurseIntoAttrs =
1082     # An attribute set to not scan for derivations.
1083     attrs:
1084     attrs // { recurseForDerivations = false; };
1086   /* `unionOfDisjoint x y` is equal to `x // y // z` where the
1087      attrnames in `z` are the intersection of the attrnames in `x` and
1088      `y`, and all values `assert` with an error message.  This
1089       operator is commutative, unlike (//).
1091      Type: unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet
1092   */
1093   unionOfDisjoint = x: y:
1094     let
1095       intersection = builtins.intersectAttrs x y;
1096       collisions = lib.concatStringsSep " " (builtins.attrNames intersection);
1097       mask = builtins.mapAttrs (name: value: builtins.throw
1098         "unionOfDisjoint: collision on ${name}; complete list: ${collisions}")
1099         intersection;
1100     in
1101       (x // y) // mask;
1103   # DEPRECATED
1104   zipWithNames = zipAttrsWithNames;
1106   # DEPRECATED
1107   zip = builtins.trace
1108     "lib.zip is deprecated, use lib.zipAttrsWith instead" zipAttrsWith;