Skip to content

Instantly share code, notes, and snippets.

@GrafBlutwurst
Created February 8, 2022 16:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GrafBlutwurst/2d6156321d6b89cb21a1d0702f5d853e to your computer and use it in GitHub Desktop.
Save GrafBlutwurst/2d6156321d6b89cb21a1d0702f5d853e to your computer and use it in GitHub Desktop.
A hacky fix for the either submodule problem
{ lib }: with lib; with lib.types; let
addTag = typeTag: module:
let
tagModule = {
_tpe = mkOption {
type = types.enum [ typeTag ];
description = ''Type Tag (${typeTag})'';
};
};
imports = if module ? imports then { inherit (module) imports; } else { };
config = if module ? config then { inherit (module) config; } else { };
in
(
assert (builtins.isAttrs module) || abort "Module passed to oneOfTagged must be a Record";
assert (builtins.isString typeTag) || abort "TypeTag passed to oneOfTagged must be a String";
assert !(module ? option._tpe) || abort "Module passed to oneOfTagged canno't have an option called _tpe (reserved for typetag)";
imports // config // {
options = module.options // tagModule;
}
);
taggedSubmodule = typeTag: module:
let
taggedModule = addTag typeTag module;
baseSubmodule = submodule taggedModule;
check = v: (baseSubmodule.check v) && (v._tpe == typeTag);
description = "Submodule[${typeTag}]";
in
baseSubmodule // { inherit check; inherit description; };
mapAttrDefs = definitions: attrValues (mapAttrs taggedSubmodule definitions);
oneOfTagged = definitions:
types.oneOf (mapAttrDefs definitions);
mkTaggers = definition:
let
tagger = tag: record: { _tpe = tag; } // record;
in
(
assert (builtins.isAttrs definition) || abort "Definition passed to mkTaggers must be a record";
mapAttrs (name: value: tagger name) definition
);
in
rec {
inherit oneOfTagged;
inherit mkTaggers;
#Use it e.g like this at your use site.
#put your choices into a record
choices = {
left.options.foo = mkOption {type = string;};
right.options.bar = mkOption {type = string;};
};
#This will generate a one of with overridden `check` for the underlying submodules that now have a field `_tpe
taggedChoices = oneOfTagged choices;
#you can get taggers to add the type tag to your records like this
taggers = mkTaggers choices;
#mkTaggers just maps over the attrset so you can do
leftValue = taggers.left {
foo = "asdf";
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment