labs/lib/src/default.nix

83 lines
2 KiB
Nix

let
files = [
./attrs
./bools
./dag
./errors
./fp
./generators
./importers
./licenses
./lists
./math
./modules
./numbers
./options
./packages
./paths
./points
./strings
./types
./versions
];
libs = builtins.map (f: import f) files;
## Calculate the fixed point of a function. This will evaluate the function `f`
## until its result settles (or Nix's recursion limit is reached). This allows
## us to define recursive functions without worrying about the order of their
## definitions.
##
## @type (a -> a) -> a
fix =
f:
let
x = f x;
in
x;
## Merge two attribute sets recursively until a given predicate returns true.
## Any values that are _not_ attribute sets will be overridden with the value
## from `y` first if it exists and then `x` otherwise.
##
## @type Attrs a b c => (String -> Any -> Any -> Bool) -> a -> b -> c
mergeAttrsRecursiveUntil =
predicate: x: y:
let
process =
path:
builtins.zipAttrsWith (
name: values:
let
currentPath = path ++ [ name ];
isSingleValue = builtins.length values == 1;
isComplete = predicate currentPath (builtins.elemAt values 1) (builtins.elemAt values 0);
in
if isSingleValue || isComplete then builtins.elemAt values 0 else process currentPath values
);
in
process [ ] [
x
y
];
## Merge two attribute sets recursively. Any values that are _not_ attribute sets
## will be overridden with the value from `y` first if it exists and then `x`
## otherwise.
##
## @type Attrs a b c => a -> b -> c
mergeAttrsRecursive = mergeAttrsRecursiveUntil (
path: x: y:
!(builtins.isAttrs x && builtins.isAttrs y)
);
lib = fix (
self:
let
merge = acc: create: mergeAttrsRecursive acc (create self);
in
builtins.foldl' merge { } libs
);
in
lib.points.withExtend (lib.fp.const lib)