lib.toExtension: init

Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
This commit is contained in:
Yueh-Shun Li 2024-07-04 20:37:01 +00:00
parent 6749b1c4bc
commit 11c20cd390
3 changed files with 83 additions and 1 deletions

View File

@ -79,7 +79,8 @@ let
fromHexString toHexString toBaseDigits inPureEvalMode isBool isInt pathExists
genericClosure readFile;
inherit (self.fixedPoints) fix fix' converge extends composeExtensions
composeManyExtensions makeExtensible makeExtensibleWithCustomName;
composeManyExtensions makeExtensible makeExtensibleWithCustomName
toExtension;
inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath
getAttrFromPath attrVals attrNames attrValues getAttrs catAttrs filterAttrs
filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs

View File

@ -438,4 +438,68 @@ rec {
${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
}
);
/**
Convert to an extending function (overlay).
`toExtension` is the `toFunction` for extending functions (a.k.a. extensions or overlays).
It converts a non-function or a single-argument function to an extending function,
while returning a double-argument function as-is.
That is, it takes one of `x`, `prev: x`, or `final: prev: x`,
and returns `final: prev: x`, where `x` is not a function.
This function is extracted from the implementation of
the fixed-point arguments support of `stdenv.mkDerivation`.
It bridges the gap between `<pkg>.overrideAttrs`
before and after the overlay-style support,
as well as `config.packageOverrides` and `config.overlays` in `pkgs`.
# Inputs
`f`
: The function or non-function to convert to an extending function.
# Type
```
toExtension ::: (a | a -> a | a -> a -> a) -> a -> a -> a
a = AttrSet & !Function
```
# Examples
:::{.example}
## `lib.fixedPoints.toExtension` usage example
```nix
fix (final: { a = 0; c = final.a; })
=> { a = 0; c = 0; };
fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; }))
=> { a = 1; b = 2; c = 1; };
fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; }))
=> { a = 1; b = 0; c = 1; };
fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1 })) (final: { a = 0; c = final.a; }))
=> { a = 1; b = 0; c = 2; };
```
:::
*/
toExtension =
f:
if lib.isFunction f then
final: prev:
let
fPrev = f prev;
in
if lib.isFunction fPrev then
# f is (final: prev: { ... })
f final prev
else
# f is (prev: { ... })
fPrev
else
# f is { ... }
final: prev: f;
}

View File

@ -45,6 +45,7 @@ let
const
escapeXML
evalModules
extends
filter
fix
fold
@ -102,6 +103,7 @@ let
take
testAllTrue
toBaseDigits
toExtension
toHexString
fromHexString
toInt
@ -1239,6 +1241,21 @@ runTests {
expected = {a = "a";};
};
testToExtension = {
expr = [
(fix (final: { a = 0; c = final.a; }))
(fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; })))
(fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; })))
(fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1; })) (final: { a = 0; c = final.a; })))
];
expected = [
{ a = 0; c = 0; }
{ a = 1; b = 2; c = 1; }
{ a = 1; b = 0; c = 1; }
{ a = 1; b = 0; c = 2; }
];
};
# GENERATORS
# these tests assume attributes are converted to lists
# in alphabetical order