about summary refs log tree commit diff
path: root/pkgs/sternenseemann/lib
diff options
context:
space:
mode:
authorsternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org>2021-02-06 02:24:48 +0100
committersternenseemann <sternenseemann@systemli.org>2021-02-07 17:04:41 +0100
commit696c8bacb364ea515de1664a7667318ec625014e (patch)
treeba962d0e08749e1ffbb6ae496801e381ddb5f03b /pkgs/sternenseemann/lib
parentffee17ca376ef6ea1f71dfc28552cc7c7f0260e1 (diff)
pkgs/sternenseemann/lib: init with mapAttrsByAttrs
Diffstat (limited to 'pkgs/sternenseemann/lib')
-rw-r--r--pkgs/sternenseemann/lib/default.nix78
1 files changed, 78 insertions, 0 deletions
diff --git a/pkgs/sternenseemann/lib/default.nix b/pkgs/sternenseemann/lib/default.nix
new file mode 100644
index 00000000..7bd630c0
--- /dev/null
+++ b/pkgs/sternenseemann/lib/default.nix
@@ -0,0 +1,78 @@
+{ lib }:
+
+{
+  # TODO(sterni): recurse into fset instead of set,
+  #               should improve performance, but
+  #               is a bit more annoying to implement
+  #
+  # Alter specific values of a nested attribute set
+  # using functions specified in another attrset.
+  #
+  # mapAttrsByAttrs recurses into the first given attribute
+  # set and checks if an attribute at the same location
+  # exists in the other one. If yes, the function at that
+  # location in the second attribute set is called with
+  # the current path in the attribute set and the value
+  # at that location in the first attribute set. If
+  # no equivalent function is found in the second set,
+  # the value is unchanged.
+  #
+  # The set returned is the first set with all values
+  # altered in the described manner.
+  #
+  # Type:
+  #
+  #  mapAttrsByAttrs :: AttrSet -> AttrSet_f -> AttrSet
+  #
+  #    where AttrSet_f = either ([String] -> a -> a) AttrSet_f
+  #
+  # Example:
+  #
+  #  x = {
+  #    ints = {
+  #      hello = 13;
+  #      world = 12;
+  #    };
+  #    strs = {
+  #      hello = "hello";
+  #      world = "world!";
+  #    };
+  #  };
+  #  mapAttrsByAttrs x {
+  #    ints = {
+  #      hello = path: value: builtins.toString value;
+  #    };
+  #    strs = {
+  #      hello = path: value: "${value}!";
+  #    };
+  #  }
+  #  => {
+  #    ints = {
+  #      hello = "13";
+  #      world = 12;
+  #    };
+  #    strs = {
+  #      hello = "hello!";
+  #      world = "world!";
+  #    };
+  #  }
+  mapAttrsByAttrs = set: fset:
+    let
+      havef = path: builtins.length path > 0
+        && lib.hasAttrByPath path fset;
+      apply = path: val:
+        let
+          id = p: v: v;
+        in
+          (lib.attrByPath path id fset) path val;
+      recurse = path: rset:
+        let
+          g = name: value:
+            if builtins.isAttrs value && !(havef path)
+            then recurse (path ++ [ name ]) value
+            else apply (path ++ [ name ]) value;
+      in
+        lib.mapAttrs g rset;
+    in
+      recurse [] set;
+}