lib: Introduce Cross Index concept

A Cross Index, short for Cross Platform Pair Index, is the essential
shape of a splice, without the invoking the more mind bending concept
of adding variations of for these 6 pairings to an existing thing so
that it can be switched out for something else.

So the purpose of a Cross Index is to contain the result of `f`\
(which may be reified in code, or just an abstract concept):
 - f "build" "build"
 - f "build" "host"
 - ...

Splicing on the other hand refers not just to these six variants, but
to the idea of tacking them onto one of the variants. (hostTarget,
I believe)

Cross Indexes are a necessity for making cross compilation work, but
splicing is more than necessary.
This commit is contained in:
Robert Hensing
2025-07-20 12:39:20 +02:00
parent ca4beaaf1c
commit 7ba464154f
3 changed files with 50 additions and 36 deletions

View File

@@ -865,34 +865,37 @@ rec {
};
/**
Removes a prefix from the attribute names of a set of splices.
Removes a prefix from the attribute names of a cross index.
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
organizing values by cross-compilation platform relationships.
# Inputs
`prefix`
: The prefix to remove from splice attribute names
: The prefix to remove from cross index attribute names
`splices`
: A set of splices with prefixed names
`crossIndex`
: A cross index with prefixed names
# Type
```
renameSplicesFrom :: String -> AttrSet -> AttrSet
renameCrossIndexFrom :: String -> AttrSet -> AttrSet
```
# Examples
:::{.example}
## `lib.customisation.renameSplicesFrom` usage example
## `lib.customisation.renameCrossIndexFrom` usage example
```nix
renameSplicesFrom "pkgs" { pkgsBuildBuild = ...; pkgsBuildHost = ...; ... }
renameCrossIndexFrom "pkgs" { pkgsBuildBuild = ...; pkgsBuildHost = ...; ... }
=> { buildBuild = ...; buildHost = ...; ... }
```
:::
*/
renameSplicesFrom = prefix: x: {
renameCrossIndexFrom = prefix: x: {
buildBuild = x."${prefix}BuildBuild";
buildHost = x."${prefix}BuildHost";
buildTarget = x."${prefix}BuildTarget";
@@ -902,34 +905,37 @@ rec {
};
/**
Adds a prefix to the attribute names of a set of splices.
Adds a prefix to the attribute names of a cross index.
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
organizing values by cross-compilation platform relationships.
# Inputs
`prefix`
: The prefix to add to splice attribute names
: The prefix to add to cross index attribute names
`splices`
: A set of splices to be prefixed
`crossIndex`
: A cross index to be prefixed
# Type
```
renameSplicesTo :: String -> AttrSet -> AttrSet
renameCrossIndexTo :: String -> AttrSet -> AttrSet
```
# Examples
:::{.example}
## `lib.customisation.renameSplicesTo` usage example
## `lib.customisation.renameCrossIndexTo` usage example
```nix
renameSplicesTo "self" { buildBuild = ...; buildHost = ...; ... }
renameCrossIndexTo "self" { buildBuild = ...; buildHost = ...; ... }
=> { selfBuildBuild = ...; selfBuildHost = ...; ... }
```
:::
*/
renameSplicesTo = prefix: x: {
renameCrossIndexTo = prefix: x: {
"${prefix}BuildBuild" = x.buildBuild;
"${prefix}BuildHost" = x.buildHost;
"${prefix}BuildTarget" = x.buildTarget;
@@ -939,34 +945,42 @@ rec {
};
/**
Takes a function and applies it pointwise to each splice.
Takes a function and applies it pointwise to each field of a cross index.
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
organizing values by cross-compilation platform relationships.
# Inputs
`f`
: Function to apply to each splice value
: Function to apply to each cross index value
`splices`
: A set of splices to transform
`crossIndex`
: A cross index to transform
# Type
```
mapSplices :: (a -> b) -> AttrSet -> AttrSet
mapCrossIndex :: (a -> b) -> AttrSet -> AttrSet
```
# Examples
:::{.example}
## `lib.customisation.mapSplices` usage example
## `lib.customisation.mapCrossIndex` usage example
```nix
mapSplices (x: x * 10) { buildBuild = 1; buildHost = 2; ... }
mapCrossIndex (x: x * 10) { buildBuild = 1; buildHost = 2; ... }
=> { buildBuild = 10; buildHost = 20; ... }
```
```nix
# Extract a package from package sets
mapCrossIndex (pkgs: pkgs.hello) crossIndexedPackageSets
```
:::
*/
mapSplices =
mapCrossIndex =
f:
{
buildBuild,

View File

@@ -398,9 +398,9 @@ let
makeScopeWithSplicing
makeScopeWithSplicing'
extendMkDerivation
renameSplicesFrom
renameSplicesTo
mapSplices
renameCrossIndexFrom
renameCrossIndexTo
mapCrossIndex
;
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
inherit (self.generators) mkLuaInline;

View File

@@ -4432,10 +4432,10 @@ runTests {
expected = "/non-existent/this/does/not/exist/for/real/please-dont-mess-with-your-local-fs/default.nix";
};
# Tests for splicing utilities
# Tests for cross index utilities
testRenameSplicesFrom = {
expr = lib.renameSplicesFrom "pkgs" {
testRenameCrossIndexFrom = {
expr = lib.renameCrossIndexFrom "pkgs" {
pkgsBuildBuild = "dummy-build-build";
pkgsBuildHost = "dummy-build-host";
pkgsBuildTarget = "dummy-build-target";
@@ -4453,8 +4453,8 @@ runTests {
};
};
testRenameSplicesTo = {
expr = lib.renameSplicesTo "self" {
testRenameCrossIndexTo = {
expr = lib.renameCrossIndexTo "self" {
buildBuild = "dummy-build-build";
buildHost = "dummy-build-host";
buildTarget = "dummy-build-target";
@@ -4472,8 +4472,8 @@ runTests {
};
};
testMapSplices = {
expr = lib.mapSplices (x: x * 10) {
testMapCrossIndex = {
expr = lib.mapCrossIndex (x: x * 10) {
buildBuild = 1;
buildHost = 2;
buildTarget = 3;
@@ -4491,8 +4491,8 @@ runTests {
};
};
testMapSplicesString = {
expr = lib.mapSplices (x: "prefix-${x}") {
testMapCrossIndexString = {
expr = lib.mapCrossIndex (x: "prefix-${x}") {
buildBuild = "bb";
buildHost = "bh";
buildTarget = "bt";