From eb312d499ca61639a2f73d7c8b46846527389dca Mon Sep 17 00:00:00 2001 From: lassulus Date: Tue, 12 Sep 2023 18:19:18 +0200 Subject: [PATCH] lib/types: init taggedSubmodules --- lib/types.nix | 17 +++++++ .../development/option-types.section.md | 51 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/lib/types.nix b/lib/types.nix index 5ffbecda5db39..9bf3fc4989908 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -710,6 +710,23 @@ rec { in mergedOption.type; }; + # A type that is one of several submodules, similiar to types.oneOf but is usable inside attrsOf or listOf + # submodules need an option with a type str which is used to find the corresponding type + taggedSubmodules = + { types + , specialArgs ? {} + }: mkOptionType rec { + name = "taggedSubmodules"; + description = "one of ${concatStringsSep "," (attrNames types)}"; + check = x: if x ? type then types.${x.type}.check x else throw "No type option set in:\n${lib.generators.toPretty {} x}"; + merge = loc: foldl' + (res: def: types.${def.value.type}.merge loc [ + (lib.recursiveUpdate { value._module.args = specialArgs; } def) + ]) + { }; + nestedTypes = types; + }; + submoduleWith = { modules , specialArgs ? {} diff --git a/nixos/doc/manual/development/option-types.section.md b/nixos/doc/manual/development/option-types.section.md index 44bb3b4782e19..1ef6711bf205d 100644 --- a/nixos/doc/manual/development/option-types.section.md +++ b/nixos/doc/manual/development/option-types.section.md @@ -213,6 +213,57 @@ Submodules are detailed in [Submodule](#section-option-types-submodule). options. This is equivalent to `types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }`. +`types.taggedSubmodules` { *`types`*, *`specialArgs`* ? {} } + +: Like `types.oneOf`, but takes an attrsSet of submodule in types. Those need to have a type option + which is used to find the correct submodule. + +::: {#ex-tagged-submodules .example} +### Tagged submodules +```nix +let + submoduleA = submodule { + options = { + type = mkOption { + type = str; + }; + foo = mkOption { + type = int; + }; + }; + }; + submoduleB = submodule { + options = { + type = mkOption { + type = str; + }; + bar = mkOption { + type = int; + }; + }; + }; +in +options.mod = mkOption { + type = attrsOf (taggedSubmodule { + types = { + a = submoduleA; + b = submoduleB; + }; + }); +}; +config.mod = { + someA = { + type = "a"; + foo = 123; + }; + someB = { + type = "b"; + foo = 456; + }; +}; +``` +::: + `types.submoduleWith` { *`modules`*, *`specialArgs`* ? {}, *`shorthandOnlyDefinesConfig`* ? false } : Like `types.submodule`, but more flexible and with better defaults.