lib.attrsets.attrsToList: add function
For transforming back between lists and attrsets, it makes sense to have a quasi-inverse of `builtins.listToAttrs` available as a library function. Co-authored-by: Silvan Mosberger <github@infinisil.com> Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
This commit is contained in:
parent
27eedb5601
commit
d70633f91c
@ -542,6 +542,36 @@ rec {
|
||||
attrs:
|
||||
map (name: f name attrs.${name}) (attrNames attrs);
|
||||
|
||||
/*
|
||||
Deconstruct an attrset to a list of name-value pairs as expected by [`builtins.listToAttrs`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs).
|
||||
Each element of the resulting list is an attribute set with these attributes:
|
||||
- `name` (string): The name of the attribute
|
||||
- `value` (any): The value of the attribute
|
||||
|
||||
The following is always true:
|
||||
```nix
|
||||
builtins.listToAttrs (attrsToList attrs) == attrs
|
||||
```
|
||||
|
||||
:::{.warning}
|
||||
The opposite is not always true. In general expect that
|
||||
```nix
|
||||
attrsToList (builtins.listToAttrs list) != list
|
||||
```
|
||||
|
||||
This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
|
||||
:::
|
||||
|
||||
Example:
|
||||
attrsToList { foo = 1; bar = "asdf"; }
|
||||
=> [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
|
||||
|
||||
Type:
|
||||
attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
|
||||
|
||||
*/
|
||||
attrsToList = mapAttrsToList nameValuePair;
|
||||
|
||||
|
||||
/* Like `mapAttrs`, except that it recursively applies itself to
|
||||
the *leaf* attributes of a potentially-nested attribute set:
|
||||
|
@ -81,8 +81,8 @@ let
|
||||
inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath
|
||||
getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs
|
||||
filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs
|
||||
mapAttrs' mapAttrsToList concatMapAttrs mapAttrsRecursive mapAttrsRecursiveCond
|
||||
genAttrs isDerivation toDerivation optionalAttrs
|
||||
mapAttrs' mapAttrsToList attrsToList concatMapAttrs mapAttrsRecursive
|
||||
mapAttrsRecursiveCond genAttrs isDerivation toDerivation optionalAttrs
|
||||
zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil
|
||||
recursiveUpdate matchAttrs overrideExisting showAttrPath getOutput getBin
|
||||
getLib getDev getMan chooseDevOutputs zipWithNames zip
|
||||
|
@ -20,6 +20,10 @@ let
|
||||
expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
|
||||
expected = { success = false; value = false; };
|
||||
};
|
||||
testingEval = expr: {
|
||||
expr = (builtins.tryEval expr).success;
|
||||
expected = true;
|
||||
};
|
||||
testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr);
|
||||
|
||||
testSanitizeDerivationName = { name, expected }:
|
||||
@ -784,6 +788,26 @@ runTests {
|
||||
expected = { a = 1; b = 2; };
|
||||
};
|
||||
|
||||
testListAttrsReverse = let
|
||||
exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;};
|
||||
exampleSingletonList = [{name="foo"; value=1;}];
|
||||
in {
|
||||
expr = {
|
||||
isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs;
|
||||
isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList;
|
||||
testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]);
|
||||
};
|
||||
expected = {
|
||||
isReverseToAttrsToList = true;
|
||||
isReverseToListToAttrs = true;
|
||||
testDuplicatePruningBehaviour = [{name="a"; value=2;}];
|
||||
};
|
||||
};
|
||||
|
||||
testAttrsToListsCanDealWithFunctions = testingEval (
|
||||
attrsToList { someFunc= a: a + 1;}
|
||||
);
|
||||
|
||||
# GENERATORS
|
||||
# these tests assume attributes are converted to lists
|
||||
# in alphabetical order
|
||||
|
Loading…
Reference in New Issue
Block a user