nt/nib/parse/struct.nix

84 lines
2 KiB
Nix
Raw Normal View History

{nib, ...}:
with nib.types; let
attrs = nib.attrs;
in rec {
2025-12-13 22:01:54 +10:00
cmpStructErr' = errBadKeys: errBadValues: path: S: T:
if builtins.isAttrs S && builtins.isAttrs T
2025-12-13 22:01:54 +10:00
then let
keysS = builtins.attrNames S;
keysT = builtins.attrNames T;
in
# ensure all key names match, then recurse
if !(keysS == keysT)
then errBadKeys path keysS keysT
else
(firstErr
2025-12-13 22:01:54 +10:00
(builtins.map
(k: cmpStructErr' errBadKeys errBadValues (path ++ [k]) (keysS.${k}) (keysT.${k}))
keysS))
else
# terminating leaf in recursion tree reached
# ensure values' types match
(builtins.typeOf S == builtins.typeOf T)
|| errBadValues path S T;
cmpStructErr = errBadKeys: errBadValues: cmpStructErr' errBadKeys errBadValues [];
cmpStruct =
cmpStructErr
(path: _: _:
Err {
2025-12-13 22:01:54 +10:00
reason = "keys";
inherit path;
})
(_: _: _: Ok');
2025-12-13 22:01:54 +10:00
cmpTypedStruct =
cmpStructErr
(path: _: _:
Err {
2025-12-13 22:01:54 +10:00
reason = "keys";
inherit path;
})
(path: _: _:
Err {
2025-12-13 22:01:54 +10:00
reason = "values";
inherit path;
});
cmpTypedPartialStruct =
2025-12-13 22:01:54 +10:00
cmpStructErr
(_: _: _: Ok')
(path: _: _:
Err {
2025-12-13 22:01:54 +10:00
reason = "values";
inherit path;
});
2025-12-13 22:01:54 +10:00
# check is a function taking two structs
# and returning a result monad.
mergeStruct' = check: template: S: let
R = check template S;
in
errOr ({...}:
Ok (
attrs.mapAttrsRecursive (
path: value: let
valueS = attrs.attrValueAt S path;
in
if valueS != null
then valueS
else value
)
template
))
R;
# mergeStruct ensures no properties are evaluated (entirely lazy)
mergeStruct = mergeStruct' (_: _: Ok');
2025-12-13 22:01:54 +10:00
# mergeTypedPartialStruct must evaluate properties (not lazy)
# for lazy evaluation use mergeStruct instead!
mergeTypedPartialStruct = mergeStruct' cmpTypedPartialStruct;
2025-12-13 22:01:54 +10:00
}