nt/nib/parse/struct.nix

112 lines
2.6 KiB
Nix
Raw Normal View History

{nib, ...}: let
2026-01-15 11:43:20 +10:00
inherit
(nib.types)
Err
Ok'
firstErr
unwrapSome
isTerminal
unwrapTerminal
;
2026-01-15 11:43:20 +10:00
inherit
(nib.std)
attrValueAt
;
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;
2025-12-13 22:01:54 +10:00
in
# ensure all key names match, then recurse
if !(keysS == keysT)
then errBadKeys path keysS keysT
else
(firstErr
2025-12-14 12:59:31 +10:00
(map
2025-12-13 22:01:54 +10:00
(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)
2025-12-13 22:01:54 +10:00
|| 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
2025-12-18 11:27:10 +10:00
# Alternative to mapAttrsRecursiveCond
# Allows mapping directly from a child path
2025-12-18 11:27:10 +10:00
recmapCondFrom = path: cond: f: T: let
delegate = path': recmapCondFrom path' cond f;
in
if builtins.isAttrs T && cond path T
then builtins.mapAttrs (attr: leaf: delegate (path ++ [attr]) leaf) T
# else if builtins.isList T
# then map (leaf: delegate leaf)
else f path T;
2025-12-18 11:27:10 +10:00
recmapCond = recmapCondFrom [];
2025-12-14 18:56:07 +10:00
2025-12-18 11:27:10 +10:00
# Alternative to mapAttrsRecursive
# NOTE: refuses to go beyond Terminal types
2025-12-18 12:22:49 +10:00
recmap = recmapCond (_: leaf: !(isTerminal leaf));
2025-12-14 18:56:07 +10:00
overrideStructCond = cond: f: S: ext:
2025-12-18 11:27:10 +10:00
recmapCond
cond
(path: leaf:
attrValueAt path ext
|> unwrapSome (_: f leaf))
S;
2025-12-18 11:27:10 +10:00
# overrideStruct ensures no properties are evaluated (entirely lazy)
# TODO: should this be called "overlayStructs" or something? (its not exactly a override...)
2025-12-18 11:27:10 +10:00
# NOTE: respects Terminal types
2026-01-15 13:16:59 +10:00
overrideStruct =
overrideStructCond
2025-12-18 12:22:49 +10:00
(_: leaf: !(isTerminal leaf))
2025-12-18 11:27:10 +10:00
(leaf:
if isTerminal leaf
then unwrapTerminal leaf
else leaf);
2025-12-13 22:01:54 +10:00
# # overrideTypedPartialStruct must evaluate properties (not lazy)
# # for lazy evaluation use overrideStruct instead!
# overrideTypedPartialStruct = overrideStructs' cmpTypedPartialStruct;
overrideAttrs = A: B: A // B;
2025-12-13 22:01:54 +10:00
}