about summary refs log tree commit diff
path: root/nixpkgs/lib/attrsets.nix
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2023-12-01 19:00:09 +0100
committerAlyssa Ross <hi@alyssa.is>2023-12-01 19:00:09 +0100
commit9e9b07490d5bab5d115c66b80bdb10ff0c11ed8d (patch)
tree4368f9e4cb2d5b93a956c085337e45cb70f1e331 /nixpkgs/lib/attrsets.nix
parenta9cbfb6941b47d6f50129e6e36927882392daed7 (diff)
parent2344fe1da14cb08b0c18743b207995f9b8597915 (diff)
downloadnixlib-9e9b07490d5bab5d115c66b80bdb10ff0c11ed8d.tar
nixlib-9e9b07490d5bab5d115c66b80bdb10ff0c11ed8d.tar.gz
nixlib-9e9b07490d5bab5d115c66b80bdb10ff0c11ed8d.tar.bz2
nixlib-9e9b07490d5bab5d115c66b80bdb10ff0c11ed8d.tar.lz
nixlib-9e9b07490d5bab5d115c66b80bdb10ff0c11ed8d.tar.xz
nixlib-9e9b07490d5bab5d115c66b80bdb10ff0c11ed8d.tar.zst
nixlib-9e9b07490d5bab5d115c66b80bdb10ff0c11ed8d.zip
Merge https://github.com/NixOS/nixpkgs
Diffstat (limited to 'nixpkgs/lib/attrsets.nix')
-rw-r--r--nixpkgs/lib/attrsets.nix67
1 files changed, 46 insertions, 21 deletions
diff --git a/nixpkgs/lib/attrsets.nix b/nixpkgs/lib/attrsets.nix
index b0460ab139e8..3d4366ce1814 100644
--- a/nixpkgs/lib/attrsets.nix
+++ b/nixpkgs/lib/attrsets.nix
@@ -1,5 +1,5 @@
+/* Operations on attribute sets. */
 { lib }:
-# Operations on attribute sets.
 
 let
   inherit (builtins) head tail length;
@@ -34,12 +34,20 @@ rec {
     default:
     # The nested attribute set to select values from
     set:
-    let attr = head attrPath;
+    let
+      lenAttrPath = length attrPath;
+      attrByPath' = n: s: (
+        if n == lenAttrPath then s
+        else (
+          let
+            attr = elemAt attrPath n;
+          in
+          if s ? ${attr} then attrByPath' (n + 1) s.${attr}
+          else default
+        )
+      );
     in
-      if attrPath == [] then set
-      else if set ? ${attr}
-      then attrByPath (tail attrPath) default set.${attr}
-      else default;
+      attrByPath' 0 set;
 
   /* Return if an attribute from nested attribute set exists.
 
@@ -58,13 +66,19 @@ rec {
     attrPath:
     # The nested attribute set to check
     e:
-    let attr = head attrPath;
+    let
+      lenAttrPath = length attrPath;
+      hasAttrByPath' = n: s: (
+        n == lenAttrPath || (
+          let
+            attr = elemAt attrPath n;
+          in
+          if s ? ${attr} then hasAttrByPath' (n + 1) s.${attr}
+          else false
+        )
+      );
     in
-      if attrPath == [] then true
-      else if e ? ${attr}
-      then hasAttrByPath (tail attrPath) e.${attr}
-      else false;
-
+      hasAttrByPath' 0 e;
 
   /* Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
 
@@ -883,7 +897,10 @@ rec {
     recursiveUpdateUntil (path: lhs: rhs: !(isAttrs lhs && isAttrs rhs)) lhs rhs;
 
 
-  /* Returns true if the pattern is contained in the set. False otherwise.
+  /*
+    Recurse into every attribute set of the first argument and check that:
+    - Each attribute path also exists in the second argument.
+    - If the attribute's value is not a nested attribute set, it must have the same value in the right argument.
 
      Example:
        matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
@@ -895,16 +912,24 @@ rec {
   matchAttrs =
     # Attribute set structure to match
     pattern:
-    # Attribute set to find patterns in
+    # Attribute set to check
     attrs:
     assert isAttrs pattern;
-    all id (attrValues (zipAttrsWithNames (attrNames pattern) (n: values:
-      let pat = head values; val = elemAt values 1; in
-      if length values == 1 then false
-      else if isAttrs pat then isAttrs val && matchAttrs pat val
-      else pat == val
-    ) [pattern attrs]));
-
+    all
+    ( # Compare equality between `pattern` & `attrs`.
+      attr:
+      # Missing attr, not equal.
+      attrs ? ${attr} && (
+        let
+          lhs = pattern.${attr};
+          rhs = attrs.${attr};
+        in
+        # If attrset check recursively
+        if isAttrs lhs then isAttrs rhs && matchAttrs lhs rhs
+        else lhs == rhs
+      )
+    )
+    (attrNames pattern);
 
   /* Override only the attributes that are already present in the old set
     useful for deep-overriding.