diff options
-rw-r--r-- | lib/types.nix | 24 | ||||
-rw-r--r-- | nixos/doc/manual/development/option-types.xml | 25 |
2 files changed, 49 insertions, 0 deletions
diff --git a/lib/types.nix b/lib/types.nix index f406cb9204b72..e86f6d3647611 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 ++ ["<name>"]); + getSubModules = elemType.getSubModules; + substSubModules = m: lazyAttrsOf (elemType.substSubModules m); + functor = (defaultFunctor name) // { wrapped = elemType; }; + }; + # List or attribute set of ... loaOf = elemType: let diff --git a/nixos/doc/manual/development/option-types.xml b/nixos/doc/manual/development/option-types.xml index e4f8396a4bdc7..55d9c123e3f11 100644 --- a/nixos/doc/manual/development/option-types.xml +++ b/nixos/doc/manual/development/option-types.xml @@ -362,6 +362,31 @@ </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> |