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.

Changed files
+49
lib
nixos
doc
manual
development
+24
lib/types.nix
···
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 ++ ["<name>"]);
+
getSubModules = elemType.getSubModules;
+
substSubModules = m: lazyAttrsOf (elemType.substSubModules m);
+
functor = (defaultFunctor name) // { wrapped = elemType; };
+
};
+
# List or attribute set of ...
loaOf = elemType:
let
+25
nixos/doc/manual/development/option-types.xml
···
</varlistentry>
<varlistentry>
<term>
+
<varname>types.lazyAttrsOf</varname> <replaceable>t</replaceable>
+
</term>
+
<listitem>
+
<para>
+
An attribute set of where all the values are of
+
<replaceable>t</replaceable> type. Multiple definitions result in the
+
joined attribute set. This is the lazy version of <varname>types.attrsOf
+
</varname>, allowing attributes to depend on each other.
+
<warning><para>
+
This version does not fully support conditional definitions! With an
+
option <varname>foo</varname> of this type and a definition
+
<literal>foo.attr = lib.mkIf false 10</literal>, evaluating
+
<literal>foo ? attr</literal> will return <literal>true</literal>
+
even though it should be false. Accessing the value will then throw
+
an error. For types <replaceable>t</replaceable> that have an
+
<literal>emptyValue</literal> defined, that value will be returned
+
instead of throwing an error. So if the type of <literal>foo.attr</literal>
+
was <literal>lazyAttrsOf (nullOr int)</literal>, <literal>null</literal>
+
would be returned instead for the same <literal>mkIf false</literal> definition.
+
</para></warning>
+
</para>
+
</listitem>
+
</varlistentry>
+
<varlistentry>
+
<term>
<varname>types.loaOf</varname> <replaceable>t</replaceable>
</term>
<listitem>