Loading lib/attrsets.nix +72 −0 Original line number Diff line number Diff line Loading @@ -51,12 +51,19 @@ rec { /* Return if an attribute from nested attribute set exists. **Laws**: 1. ```nix hasAttrByPath [] x == true ``` Example: x = { a = { b = 3; }; } hasAttrByPath ["a" "b"] x => true hasAttrByPath ["z" "z"] x => false hasAttrByPath [] (throw "no need") => true Type: hasAttrByPath :: [String] -> AttrSet -> Bool Loading @@ -80,6 +87,71 @@ rec { in hasAttrByPath' 0 e; /* Return the longest prefix of an attribute path that refers to an existing attribute in a nesting of attribute sets. Can be used after [`mapAttrsRecursiveCond`](#function-library-lib.attrsets.mapAttrsRecursiveCond) to apply a condition, although this will evaluate the predicate function on sibling attributes as well. Note that the empty attribute path is valid for all values, so this function only throws an exception if any of its inputs does. **Laws**: 1. ```nix attrsets.longestValidPathPrefix [] x == [] ``` 2. ```nix hasAttrByPath (attrsets.longestValidPathPrefix p x) x == true ``` Example: x = { a = { b = 3; }; } attrsets.longestValidPathPrefix ["a" "b" "c"] x => ["a" "b"] attrsets.longestValidPathPrefix ["a"] x => ["a"] attrsets.longestValidPathPrefix ["z" "z"] x => [] attrsets.longestValidPathPrefix ["z" "z"] (throw "no need") => [] Type: attrsets.longestValidPathPrefix :: [String] -> Value -> [String] */ longestValidPathPrefix = # A list of strings representing the longest possible path that may be returned. attrPath: # The nested attribute set to check. v: let lenAttrPath = length attrPath; getPrefixForSetAtIndex = # The nested attribute set to check, if it is an attribute set, which # is not a given. remainingSet: # The index of the attribute we're about to check, as well as # the length of the prefix we've already checked. remainingPathIndex: if remainingPathIndex == lenAttrPath then # All previously checked attributes exist, and no attr names left, # so we return the whole path. attrPath else let attr = elemAt attrPath remainingPathIndex; in if remainingSet ? ${attr} then getPrefixForSetAtIndex remainingSet.${attr} # advance from the set to the attribute value (remainingPathIndex + 1) # advance the path else # The attribute doesn't exist, so we return the prefix up to the # previously checked length. take remainingPathIndex attrPath; in getPrefixForSetAtIndex v 0; /* Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`. Example: Loading lib/strings.nix +11 −8 Original line number Diff line number Diff line Loading @@ -771,12 +771,13 @@ rec { cmakeOptionType "string" "ENGINE" "sdl2" => "-DENGINE:STRING=sdl2" */ cmakeOptionType = type: feature: value: assert (lib.elem (lib.toUpper type) [ "BOOL" "FILEPATH" "PATH" "STRING" "INTERNAL" ]); assert (lib.isString feature); assert (lib.isString value); "-D${feature}:${lib.toUpper type}=${value}"; cmakeOptionType = let types = [ "BOOL" "FILEPATH" "PATH" "STRING" "INTERNAL" ]; in type: feature: value: assert (elem (toUpper type) types); assert (isString feature); assert (isString value); "-D${feature}:${toUpper type}=${value}"; /* Create a -D<condition>={TRUE,FALSE} string that can be passed to typical CMake invocations. Loading Loading @@ -977,9 +978,11 @@ rec { Many types of value are coercible to string this way, including int, float, null, bool, list of similarly coercible values. */ isConvertibleWithToString = x: isConvertibleWithToString = let types = [ "null" "int" "float" "bool" ]; in x: isStringLike x || elem (typeOf x) [ "null" "int" "float" "bool" ] || elem (typeOf x) types || (isList x && lib.all isConvertibleWithToString x); /* Check whether a value can be coerced to a string. Loading lib/tests/misc.nix +45 −0 Original line number Diff line number Diff line Loading @@ -697,6 +697,51 @@ runTests { expected = false; }; testHasAttrByPathNonStrict = { expr = hasAttrByPath [] (throw "do not use"); expected = true; }; testLongestValidPathPrefix_empty_empty = { expr = attrsets.longestValidPathPrefix [ ] { }; expected = [ ]; }; testLongestValidPathPrefix_empty_nonStrict = { expr = attrsets.longestValidPathPrefix [ ] (throw "do not use"); expected = [ ]; }; testLongestValidPathPrefix_zero = { expr = attrsets.longestValidPathPrefix [ "a" (throw "do not use") ] { d = null; }; expected = [ ]; }; testLongestValidPathPrefix_zero_b = { expr = attrsets.longestValidPathPrefix [ "z" "z" ] "remarkably harmonious"; expected = [ ]; }; testLongestValidPathPrefix_one = { expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a = null; }; expected = [ "a" ]; }; testLongestValidPathPrefix_two = { expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b = null; }; expected = [ "a" "b" ]; }; testLongestValidPathPrefix_three = { expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c = null; }; expected = [ "a" "b" "c" ]; }; testLongestValidPathPrefix_three_extra = { expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c.d = throw "nope"; }; expected = [ "a" "b" "c" ]; }; testFindFirstIndexExample1 = { expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ]; expected = 1; Loading lib/trivial.nix +15 −19 Original line number Diff line number Diff line Loading @@ -70,9 +70,7 @@ in { of the next function, and the last function returns the final value. */ pipe = val: functions: let reverseApply = x: f: f x; in builtins.foldl' reverseApply val functions; pipe = builtins.foldl' (x: f: f x); # note please don’t add a function like `compose = flip pipe`. # This would confuse users, because the order of the functions Loading Loading @@ -522,22 +520,20 @@ in { toHexString 250 => "FA" */ toHexString = i: let toHexDigit = d: if d < 10 then toString d else { toHexString = let hexDigits = { "10" = "A"; "11" = "B"; "12" = "C"; "13" = "D"; "14" = "E"; "15" = "F"; }.${toString d}; in lib.concatMapStrings toHexDigit (toBaseDigits 16 i); }; toHexDigit = d: if d < 10 then toString d else hexDigits.${toString d}; in i: lib.concatMapStrings toHexDigit (toBaseDigits 16 i); /* `toBaseDigits base i` converts the positive integer i to a list of its digits in the given base. For example: Loading maintainers/maintainer-list.nix +6 −0 Original line number Diff line number Diff line Loading @@ -605,6 +605,12 @@ githubId = 4717906; name = "Jakub Skokan"; }; ajaxbits = { email = "contact@ajaxbits.com"; github = "ajaxbits"; githubId = 45179933; name = "Alex Jackson"; }; ajgrf = { email = "a@ajgrf.com"; github = "ajgrf"; Loading Loading
lib/attrsets.nix +72 −0 Original line number Diff line number Diff line Loading @@ -51,12 +51,19 @@ rec { /* Return if an attribute from nested attribute set exists. **Laws**: 1. ```nix hasAttrByPath [] x == true ``` Example: x = { a = { b = 3; }; } hasAttrByPath ["a" "b"] x => true hasAttrByPath ["z" "z"] x => false hasAttrByPath [] (throw "no need") => true Type: hasAttrByPath :: [String] -> AttrSet -> Bool Loading @@ -80,6 +87,71 @@ rec { in hasAttrByPath' 0 e; /* Return the longest prefix of an attribute path that refers to an existing attribute in a nesting of attribute sets. Can be used after [`mapAttrsRecursiveCond`](#function-library-lib.attrsets.mapAttrsRecursiveCond) to apply a condition, although this will evaluate the predicate function on sibling attributes as well. Note that the empty attribute path is valid for all values, so this function only throws an exception if any of its inputs does. **Laws**: 1. ```nix attrsets.longestValidPathPrefix [] x == [] ``` 2. ```nix hasAttrByPath (attrsets.longestValidPathPrefix p x) x == true ``` Example: x = { a = { b = 3; }; } attrsets.longestValidPathPrefix ["a" "b" "c"] x => ["a" "b"] attrsets.longestValidPathPrefix ["a"] x => ["a"] attrsets.longestValidPathPrefix ["z" "z"] x => [] attrsets.longestValidPathPrefix ["z" "z"] (throw "no need") => [] Type: attrsets.longestValidPathPrefix :: [String] -> Value -> [String] */ longestValidPathPrefix = # A list of strings representing the longest possible path that may be returned. attrPath: # The nested attribute set to check. v: let lenAttrPath = length attrPath; getPrefixForSetAtIndex = # The nested attribute set to check, if it is an attribute set, which # is not a given. remainingSet: # The index of the attribute we're about to check, as well as # the length of the prefix we've already checked. remainingPathIndex: if remainingPathIndex == lenAttrPath then # All previously checked attributes exist, and no attr names left, # so we return the whole path. attrPath else let attr = elemAt attrPath remainingPathIndex; in if remainingSet ? ${attr} then getPrefixForSetAtIndex remainingSet.${attr} # advance from the set to the attribute value (remainingPathIndex + 1) # advance the path else # The attribute doesn't exist, so we return the prefix up to the # previously checked length. take remainingPathIndex attrPath; in getPrefixForSetAtIndex v 0; /* Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`. Example: Loading
lib/strings.nix +11 −8 Original line number Diff line number Diff line Loading @@ -771,12 +771,13 @@ rec { cmakeOptionType "string" "ENGINE" "sdl2" => "-DENGINE:STRING=sdl2" */ cmakeOptionType = type: feature: value: assert (lib.elem (lib.toUpper type) [ "BOOL" "FILEPATH" "PATH" "STRING" "INTERNAL" ]); assert (lib.isString feature); assert (lib.isString value); "-D${feature}:${lib.toUpper type}=${value}"; cmakeOptionType = let types = [ "BOOL" "FILEPATH" "PATH" "STRING" "INTERNAL" ]; in type: feature: value: assert (elem (toUpper type) types); assert (isString feature); assert (isString value); "-D${feature}:${toUpper type}=${value}"; /* Create a -D<condition>={TRUE,FALSE} string that can be passed to typical CMake invocations. Loading Loading @@ -977,9 +978,11 @@ rec { Many types of value are coercible to string this way, including int, float, null, bool, list of similarly coercible values. */ isConvertibleWithToString = x: isConvertibleWithToString = let types = [ "null" "int" "float" "bool" ]; in x: isStringLike x || elem (typeOf x) [ "null" "int" "float" "bool" ] || elem (typeOf x) types || (isList x && lib.all isConvertibleWithToString x); /* Check whether a value can be coerced to a string. Loading
lib/tests/misc.nix +45 −0 Original line number Diff line number Diff line Loading @@ -697,6 +697,51 @@ runTests { expected = false; }; testHasAttrByPathNonStrict = { expr = hasAttrByPath [] (throw "do not use"); expected = true; }; testLongestValidPathPrefix_empty_empty = { expr = attrsets.longestValidPathPrefix [ ] { }; expected = [ ]; }; testLongestValidPathPrefix_empty_nonStrict = { expr = attrsets.longestValidPathPrefix [ ] (throw "do not use"); expected = [ ]; }; testLongestValidPathPrefix_zero = { expr = attrsets.longestValidPathPrefix [ "a" (throw "do not use") ] { d = null; }; expected = [ ]; }; testLongestValidPathPrefix_zero_b = { expr = attrsets.longestValidPathPrefix [ "z" "z" ] "remarkably harmonious"; expected = [ ]; }; testLongestValidPathPrefix_one = { expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a = null; }; expected = [ "a" ]; }; testLongestValidPathPrefix_two = { expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b = null; }; expected = [ "a" "b" ]; }; testLongestValidPathPrefix_three = { expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c = null; }; expected = [ "a" "b" "c" ]; }; testLongestValidPathPrefix_three_extra = { expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c.d = throw "nope"; }; expected = [ "a" "b" "c" ]; }; testFindFirstIndexExample1 = { expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ]; expected = 1; Loading
lib/trivial.nix +15 −19 Original line number Diff line number Diff line Loading @@ -70,9 +70,7 @@ in { of the next function, and the last function returns the final value. */ pipe = val: functions: let reverseApply = x: f: f x; in builtins.foldl' reverseApply val functions; pipe = builtins.foldl' (x: f: f x); # note please don’t add a function like `compose = flip pipe`. # This would confuse users, because the order of the functions Loading Loading @@ -522,22 +520,20 @@ in { toHexString 250 => "FA" */ toHexString = i: let toHexDigit = d: if d < 10 then toString d else { toHexString = let hexDigits = { "10" = "A"; "11" = "B"; "12" = "C"; "13" = "D"; "14" = "E"; "15" = "F"; }.${toString d}; in lib.concatMapStrings toHexDigit (toBaseDigits 16 i); }; toHexDigit = d: if d < 10 then toString d else hexDigits.${toString d}; in i: lib.concatMapStrings toHexDigit (toBaseDigits 16 i); /* `toBaseDigits base i` converts the positive integer i to a list of its digits in the given base. For example: Loading
maintainers/maintainer-list.nix +6 −0 Original line number Diff line number Diff line Loading @@ -605,6 +605,12 @@ githubId = 4717906; name = "Jakub Skokan"; }; ajaxbits = { email = "contact@ajaxbits.com"; github = "ajaxbits"; githubId = 45179933; name = "Alex Jackson"; }; ajgrf = { email = "a@ajgrf.com"; github = "ajgrf"; Loading