From 18d6ec40d94934141e743d763ba2d33b9045f3e9 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Sun, 22 Jan 2023 15:12:05 -0800 Subject: [PATCH 1/2] lib/lists: add cartesianProductOfLists --- lib/lists.nix | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/lists.nix b/lib/lists.nix index 8b2c2d12801bb..1317bf011087c 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -631,9 +631,15 @@ rec { => [ "13" "14" "23" "24" ] */ crossLists = builtins.trace - "lib.crossLists is deprecated, use lib.cartesianProductOfSets instead" + "lib.crossLists is deprecated, use lib.cartesianProductOfLists instead" (f: foldl (fs: args: concatMap (f: map f args) fs) [f]); + cartesianProductOfLists = lists: + let + inherit (lib) cartesianProductOfSets toString nameValuePair genAttrs attrValues; + attrs = builtins.listToAttrs (imap0 (i: nameValuePair (builtins.toString i)) lists); + cross = cartesianProductOfSets attrs; + in map attrValues cross; /* Remove duplicate elements from the list. O(n^2) complexity. From 4bafa5ec46bd4cff3c1fbe50606d658840fe3683 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Sun, 22 Jan 2023 15:13:04 -0800 Subject: [PATCH 2/2] lib/attrsets.nix: add intersectPatterns --- lib/attrsets.nix | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 1a7b90593b1d7..a197e4ca879f8 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -771,6 +771,33 @@ rec { ) [pattern attrs])); + /* Pattern intersection. Specifically, the following is true + if it does not `throw`: + + forall patternList, + forall arg, + matchAttrs (intersectPatterns patternList) arg + == all (matchAttrs patternList) arg + + Type: + intersectPatterns :: [ AttrSet ] -> AttrSet + */ + intersectPatterns = let + inherit (lib) any unique isFunction elem; + inherit (lib.strings) concatStringsSep; + mergeLeaves = path: list: + let list' = unique list; in + # avoid introducing any new dependencies on function equality + assert any isFunction list -> throw "function found in pattern list at path '${concatStringsSep "." path}'"; + assert length list == 0 -> throw "this should not happen; path '${concatStringsSep "." path}'"; + assert length list' != 1 -> throw "disjoint patterns intersected at path '${concatStringsSep "." path}', values=${builtins.toString list'}"; + elemAt list' 0; + intersectPatterns' = path: list: + if !(any isAttrs list) then mergeLeaves path list + else if all isAttrs list then mapAttrs (k: v: intersectPatterns' (path++[k]) v) (zipAttrs list) + else throw "mix of attrsets and non-attrsets at path '${concatStringsSep "." path}', values = ${concatStringsSep "\n" (map builtins.toJSON list)}"; + in list: (intersectPatterns' [] list); + /* Override only the attributes that are already present in the old set useful for deep-overriding.