diff --git a/nib/default.nix b/nib/default.nix index 0a7507f..2c61cb5 100644 --- a/nib/default.nix +++ b/nib/default.nix @@ -5,7 +5,7 @@ result = std.result; }; in - builtins.listToAttrs [ + std.attrs.mergeAttrsList [ # submodule content is accessible first by submodule name # then by the name of the content (ie self.submodule.myFunc) {inherit parse;} diff --git a/nib/parse/default.nix b/nib/parse/default.nix index 41d6241..91f3473 100644 --- a/nib/parse/default.nix +++ b/nib/parse/default.nix @@ -4,7 +4,7 @@ }: let struct = import ./struct.nix {inherit attrs result;}; in - builtins.listToAttrs [ + attrs.mergeAttrsList [ # submodule is included directly to this module (ie self.myFunc) struct diff --git a/nib/std/attrs.nix b/nib/std/attrs.nix index 863f2ae..79bc103 100644 --- a/nib/std/attrs.nix +++ b/nib/std/attrs.nix @@ -95,4 +95,24 @@ if l != null && builtins.hasAttr r l then l.${r} else null); + + mergeAttrsList = list: let + # `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end` + # Type: Int -> Int -> Attrs + binaryMerge = start: end: + # assert start < end; # Invariant + if end - start >= 2 + then + # If there's at least 2 elements, split the range in two, recurse on each part and merge the result + # The invariant is satisfied because each half will have at least 1 element + binaryMerge start (start + (end - start) / 2) // binaryMerge (start + (end - start) / 2) end + else + # Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly + builtins.elemAt list start; + in + if list == [] + then + # Calling binaryMerge as below would not satisfy its invariant + {} + else binaryMerge 0 (builtins.length list); } diff --git a/nib/std/default.nix b/nib/std/default.nix index ec2d502..6208eea 100644 --- a/nib/std/default.nix +++ b/nib/std/default.nix @@ -3,7 +3,7 @@ lists = import ./lists.nix {}; result = import ./lists.nix {inherit lists;}; in - builtins.listToAttrs [ + attrs.mergeAttrsList [ # submodule is included directly to this module (ie self.myFunc) # submodule content is accessible first by submodule name