Merge pull request #254452 from flyingcircusio/lib-attrsToList

lib.attrsets.attrsToList: add function

authored by Silvan Mosberger and committed by GitHub 5323fbf7 26858d74

+56 -2
+30
lib/attrsets.nix
··· 542 attrs: 543 map (name: f name attrs.${name}) (attrNames attrs); 544 545 546 /* Like `mapAttrs`, except that it recursively applies itself to 547 the *leaf* attributes of a potentially-nested attribute set:
··· 542 attrs: 543 map (name: f name attrs.${name}) (attrNames attrs); 544 545 + /* 546 + 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). 547 + Each element of the resulting list is an attribute set with these attributes: 548 + - `name` (string): The name of the attribute 549 + - `value` (any): The value of the attribute 550 + 551 + The following is always true: 552 + ```nix 553 + builtins.listToAttrs (attrsToList attrs) == attrs 554 + ``` 555 + 556 + :::{.warning} 557 + The opposite is not always true. In general expect that 558 + ```nix 559 + attrsToList (builtins.listToAttrs list) != list 560 + ``` 561 + 562 + This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list. 563 + ::: 564 + 565 + Example: 566 + attrsToList { foo = 1; bar = "asdf"; } 567 + => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ] 568 + 569 + Type: 570 + attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ] 571 + 572 + */ 573 + attrsToList = mapAttrsToList nameValuePair; 574 + 575 576 /* Like `mapAttrs`, except that it recursively applies itself to 577 the *leaf* attributes of a potentially-nested attribute set:
+2 -2
lib/default.nix
··· 81 inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath 82 getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs 83 filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs 84 - mapAttrs' mapAttrsToList concatMapAttrs mapAttrsRecursive mapAttrsRecursiveCond 85 - genAttrs isDerivation toDerivation optionalAttrs 86 zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil 87 recursiveUpdate matchAttrs overrideExisting showAttrPath getOutput getBin 88 getLib getDev getMan chooseDevOutputs zipWithNames zip
··· 81 inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath 82 getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs 83 filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs 84 + mapAttrs' mapAttrsToList attrsToList concatMapAttrs mapAttrsRecursive 85 + mapAttrsRecursiveCond genAttrs isDerivation toDerivation optionalAttrs 86 zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil 87 recursiveUpdate matchAttrs overrideExisting showAttrPath getOutput getBin 88 getLib getDev getMan chooseDevOutputs zipWithNames zip
+24
lib/tests/misc.nix
··· 20 expr = (builtins.tryEval (builtins.seq expr "didn't throw")); 21 expected = { success = false; value = false; }; 22 }; 23 testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr); 24 25 testSanitizeDerivationName = { name, expected }: ··· 815 expr = overrideExisting { a = 3; b = 2; } { a = 1; }; 816 expected = { a = 1; b = 2; }; 817 }; 818 819 # GENERATORS 820 # these tests assume attributes are converted to lists
··· 20 expr = (builtins.tryEval (builtins.seq expr "didn't throw")); 21 expected = { success = false; value = false; }; 22 }; 23 + testingEval = expr: { 24 + expr = (builtins.tryEval expr).success; 25 + expected = true; 26 + }; 27 testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr); 28 29 testSanitizeDerivationName = { name, expected }: ··· 819 expr = overrideExisting { a = 3; b = 2; } { a = 1; }; 820 expected = { a = 1; b = 2; }; 821 }; 822 + 823 + testListAttrsReverse = let 824 + exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;}; 825 + exampleSingletonList = [{name="foo"; value=1;}]; 826 + in { 827 + expr = { 828 + isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs; 829 + isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList; 830 + testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]); 831 + }; 832 + expected = { 833 + isReverseToAttrsToList = true; 834 + isReverseToListToAttrs = true; 835 + testDuplicatePruningBehaviour = [{name="a"; value=2;}]; 836 + }; 837 + }; 838 + 839 + testAttrsToListsCanDealWithFunctions = testingEval ( 840 + attrsToList { someFunc= a: a + 1;} 841 + ); 842 843 # GENERATORS 844 # these tests assume attributes are converted to lists