about summary refs log tree commit diff
path: root/pkgs/sternenseemann/lib/default.nix
blob: 7bd630c0c727ed1c27439542e1f92319b404c288 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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;
}