From b48717d1eb9d4d9d60f3460274e7d9a961a402df Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Sat, 12 Oct 2019 21:18:53 +0200 Subject: lib/types: Introduce lazyAttrsOf The standard attrsOf is strict in its *values*, meaning it's impossible to access only one attribute value without evaluating all others as well. lazyAttrsOf is a version that doesn't have that problem, at the expense of conditional definitions not properly working anymore. --- lib/types.nix | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'lib/types.nix') diff --git a/lib/types.nix b/lib/types.nix index f406cb9204b..e86f6d36476 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -302,6 +302,30 @@ rec { functor = (defaultFunctor name) // { wrapped = elemType; }; }; + # A version of attrsOf that's lazy in its values at the expense of + # conditional definitions not working properly. E.g. defining a value with + # `foo.attr = mkIf false 10`, then `foo ? attr == true`, whereas with + # attrsOf it would correctly be `false`. Accessing `foo.attr` would throw an + # error that it's not defined. Use only if conditional definitions don't make sense. + lazyAttrsOf = elemType: mkOptionType rec { + name = "lazyAttrsOf"; + description = "lazy attribute set of ${elemType.description}s"; + check = isAttrs; + merge = loc: defs: + zipAttrsWith (name: defs: + let merged = mergeDefinitions (loc ++ [name]) elemType defs; + # mergedValue will trigger an appropriate error when accessed + in merged.optionalValue.value or elemType.emptyValue.value or merged.mergedValue + ) + # Push down position info. + (map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value) defs); + emptyValue = { value = {}; }; + getSubOptions = prefix: elemType.getSubOptions (prefix ++ [""]); + getSubModules = elemType.getSubModules; + substSubModules = m: lazyAttrsOf (elemType.substSubModules m); + functor = (defaultFunctor name) // { wrapped = elemType; }; + }; + # List or attribute set of ... loaOf = elemType: let -- cgit 1.4.1