lib.types.unique: Check inner type deeply

This doesn't change uniq. Why not?

- In NixOS it seems that uniq is only used with
  simple types that are fully checked by t.check.

- It exists for much longer and is used more widely.

- I believe we should deprecate it, because unique was
  already better.

- unique can be a proving ground.
This commit is contained in:
Robert Hensing 2024-01-28 14:09:27 +01:00
parent 0e756e65d5
commit b78ba9bc68
4 changed files with 66 additions and 6 deletions

View file

@ -254,13 +254,36 @@ rec {
else if all isInt list && all (x: x == head list) list then head list
else throw "Cannot merge definitions of `${showOption loc}'. Definition values:${showDefs defs}";
/*
Require a single definition.
WARNING: Does not perform nested checks, as this does not run the merge function!
*/
mergeOneOption = mergeUniqueOption { message = ""; };
mergeUniqueOption = { message }: loc: defs:
if length defs == 1
then (head defs).value
else assert length defs > 1;
throw "The option `${showOption loc}' is defined multiple times while it's expected to be unique.\n${message}\nDefinition values:${showDefs defs}\n${prioritySuggestion}";
/*
Require a single definition.
NOTE: When the type is not checked completely by check, pass a merge function for further checking (of sub-attributes, etc).
*/
mergeUniqueOption = args@{ message, merge ? null }:
let
notUnique = loc: defs:
assert length defs > 1;
throw "The option `${showOption loc}' is defined multiple times while it's expected to be unique.\n${message}\nDefinition values:${showDefs defs}\n${prioritySuggestion}";
in
if merge == null
# The inner conditional could be factored out, but this way we take advantage of partial application.
then
loc: defs:
if length defs == 1
then (head defs).value
else notUnique loc defs
else
loc: defs:
if length defs == 1
then merge loc defs
else notUnique loc defs;
/* "Merge" option definitions by checking that they all have the same value. */
mergeEqualOption = loc: defs: