add WIP trivial
This commit is contained in:
parent
0911efe6d2
commit
6ce2f22854
593
nodes/1_lib/source/detangled/WIP_trivial.nix
Normal file
593
nodes/1_lib/source/detangled/WIP_trivial.nix
Normal file
|
@ -0,0 +1,593 @@
|
||||||
|
let
|
||||||
|
foundation = import ./detangled/1_foundation.nix;
|
||||||
|
static = import ./detangled/2_static.nix;
|
||||||
|
# FIXME: this file is currently broken because it depends on the following:
|
||||||
|
# lib.pathIsGitRepo
|
||||||
|
# lib.commitIdFromGitRepo
|
||||||
|
# lib.fileContents
|
||||||
|
# lib.subtractLists
|
||||||
|
# lib.concatMapStrings
|
||||||
|
in
|
||||||
|
let
|
||||||
|
isFunction = foundation.isFunction;
|
||||||
|
functionArgs = foundation.functionArgs;
|
||||||
|
in {
|
||||||
|
# Pull in some builtins for backwards compatibility (ideally would be deprecated and people would use lib.builtins.THING)
|
||||||
|
pathExists = builtins.pathExists;
|
||||||
|
readFile = builtins.readFile;
|
||||||
|
isBool = builtins.isBool;
|
||||||
|
isInt = builtins.isInt;
|
||||||
|
isFloat = builtins.isFloat;
|
||||||
|
add = builtins.add;
|
||||||
|
sub = builtins.sub;
|
||||||
|
lessThan = builtins.lessThan;
|
||||||
|
seq = builtins.seq;
|
||||||
|
deepSeq = builtins.deepSeq;
|
||||||
|
genericClosure = builtins.genericClosure;
|
||||||
|
bitAnd = builtins.bitAnd;
|
||||||
|
bitOr = builtins.bitOr;
|
||||||
|
bitXor = builtins.bitXor;
|
||||||
|
|
||||||
|
# static stuff
|
||||||
|
release = static.setup.release;
|
||||||
|
codeName = static.setup.codeName;
|
||||||
|
versionSuffix = static.setup.versionSuffix;
|
||||||
|
oldestSupportedRelease = static.setup.oldestSupportedRelease;
|
||||||
|
version = static.setup.release + static.setup.versionSuffix;
|
||||||
|
|
||||||
|
# helpers that are from foundation
|
||||||
|
functionArgs = foundation.functionArgs;
|
||||||
|
isFunction = foundation.isFunction;
|
||||||
|
setFunctionArgs = foundation.setFunctionArgs;
|
||||||
|
warn = foundation.warn;
|
||||||
|
throwIfNot = foundation.throwIfNot;
|
||||||
|
id = foundation.id;
|
||||||
|
const = foundation.const;
|
||||||
|
pipe = foundation.pipe;
|
||||||
|
concat = foundation.concat;
|
||||||
|
and = foundation.and;
|
||||||
|
xor = foundation.xor;
|
||||||
|
bitNot = foundation.bitNot;
|
||||||
|
boolToString = foundation.boolToString;
|
||||||
|
mergeAttrs = foundation.mergeAttrs;
|
||||||
|
flip = foundation.flip;
|
||||||
|
mapNullable = foundation.mapNullable;
|
||||||
|
or = foundation.logicalOr; # different name mapping because of "or" being a keyword
|
||||||
|
|
||||||
|
/**
|
||||||
|
Whether a feature is supported in all supported releases (at the time of
|
||||||
|
release branch-off, if applicable). See `oldestSupportedRelease`.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`release`
|
||||||
|
|
||||||
|
: Release number of feature introduction as an integer, e.g. 2111 for 21.11.
|
||||||
|
Set it to the upcoming release, matching the nixpkgs/.version file.
|
||||||
|
*/
|
||||||
|
isInOldestRelease =
|
||||||
|
release:
|
||||||
|
release <= static.setup.oldestSupportedRelease;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Attempts to return the the current revision of nixpkgs and
|
||||||
|
returns the supplied default value otherwise.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`default`
|
||||||
|
|
||||||
|
: Default value to return if revision can not be determined
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
revisionWithDefault :: string -> string
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
revisionWithDefault =
|
||||||
|
default:
|
||||||
|
let
|
||||||
|
revisionFile = "${toString ./..}/.git-revision";
|
||||||
|
gitRepo = "${toString ./..}/.git";
|
||||||
|
in if lib.pathIsGitRepo gitRepo
|
||||||
|
then lib.commitIdFromGitRepo gitRepo
|
||||||
|
else if builtins.pathExists revisionFile then lib.fileContents revisionFile
|
||||||
|
else default;
|
||||||
|
|
||||||
|
nixpkgsVersion = foundation.warn "lib.nixpkgsVersion is a deprecated alias of lib.version." (static.setup.release + static.setup.versionSuffix);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Determine whether the function is being called from inside a Nix
|
||||||
|
shell.
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
inNixShell :: bool
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
inNixShell = builtins.getEnv "IN_NIX_SHELL" != "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
Determine whether the function is being called from inside pure-eval mode
|
||||||
|
by seeing whether `builtins` contains `currentSystem`. If not, we must be in
|
||||||
|
pure-eval mode.
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
inPureEvalMode :: bool
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
inPureEvalMode = ! builtins ? currentSystem;
|
||||||
|
|
||||||
|
## Integer operations
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return minimum of two numbers.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`x`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`y`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
*/
|
||||||
|
min = x: y: if x < y then x else y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return maximum of two numbers.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`x`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`y`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
*/
|
||||||
|
max = x: y: if x > y then x else y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Integer modulus
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`base`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`int`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
:::{.example}
|
||||||
|
## `lib.trivial.mod` usage example
|
||||||
|
|
||||||
|
```nix
|
||||||
|
mod 11 10
|
||||||
|
=> 1
|
||||||
|
mod 1 10
|
||||||
|
=> 1
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
*/
|
||||||
|
mod = base: int: base - (int * (builtins.div base int));
|
||||||
|
|
||||||
|
|
||||||
|
## Comparisons
|
||||||
|
|
||||||
|
/**
|
||||||
|
C-style comparisons
|
||||||
|
|
||||||
|
a < b, compare a b => -1
|
||||||
|
a == b, compare a b => 0
|
||||||
|
a > b, compare a b => 1
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`a`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`b`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
*/
|
||||||
|
compare = a: b:
|
||||||
|
if a < b
|
||||||
|
then -1
|
||||||
|
else if a > b
|
||||||
|
then 1
|
||||||
|
else 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Split type into two subtypes by predicate `p`, take all elements
|
||||||
|
of the first subtype to be less than all the elements of the
|
||||||
|
second subtype, compare elements of a single subtype with `yes`
|
||||||
|
and `no` respectively.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`p`
|
||||||
|
|
||||||
|
: Predicate
|
||||||
|
|
||||||
|
`yes`
|
||||||
|
|
||||||
|
: Comparison function if predicate holds for both values
|
||||||
|
|
||||||
|
`no`
|
||||||
|
|
||||||
|
: Comparison function if predicate holds for neither value
|
||||||
|
|
||||||
|
`a`
|
||||||
|
|
||||||
|
: First value to compare
|
||||||
|
|
||||||
|
`b`
|
||||||
|
|
||||||
|
: Second value to compare
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
(a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int)
|
||||||
|
```
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
:::{.example}
|
||||||
|
## `lib.trivial.splitByAndCompare` usage example
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in
|
||||||
|
|
||||||
|
cmp "a" "z" => -1
|
||||||
|
cmp "fooa" "fooz" => -1
|
||||||
|
|
||||||
|
cmp "f" "a" => 1
|
||||||
|
cmp "fooa" "a" => -1
|
||||||
|
# while
|
||||||
|
compare "fooa" "a" => 1
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
*/
|
||||||
|
splitByAndCompare =
|
||||||
|
p: yes: no: a: b:
|
||||||
|
if p a
|
||||||
|
then if p b then yes a b else -1
|
||||||
|
else if p b then 1 else no a b;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reads a JSON file.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`path`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
importJSON :: path -> any
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
importJSON = path:
|
||||||
|
builtins.fromJSON (builtins.readFile path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reads a TOML file.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`path`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
importTOML :: path -> any
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
importTOML = path:
|
||||||
|
builtins.fromTOML (builtins.readFile path);
|
||||||
|
|
||||||
|
## Warnings
|
||||||
|
|
||||||
|
/**
|
||||||
|
Like warn, but only warn when the first argument is `true`.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`cond`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`msg`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
|
||||||
|
`val`
|
||||||
|
|
||||||
|
: Value to return as-is.
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
bool -> string -> a -> a
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
warnIf = cond: msg: if cond then warn msg else x: x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Like warnIf, but negated (warn if the first argument is `false`).
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`cond`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`msg`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
|
||||||
|
`val`
|
||||||
|
|
||||||
|
: Value to return as-is.
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
bool -> string -> a -> a
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
warnIfNot = cond: msg: if cond then x: x else warn msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Like throwIfNot, but negated (throw if the first argument is `true`).
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`cond`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`msg`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
bool -> string -> a -> a
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
throwIf = cond: msg: if cond then throw msg else x: x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check if the elements in a list are valid values from a enum, returning the identity function, or throwing an error message otherwise.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`msg`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`valid`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
|
||||||
|
`given`
|
||||||
|
|
||||||
|
: 3\. Function argument
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
String -> List ComparableVal -> List ComparableVal -> a -> a
|
||||||
|
```
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
:::{.example}
|
||||||
|
## `lib.trivial.checkListOfEnum` usage example
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let colorVariants = ["bright" "dark" "black"]
|
||||||
|
in checkListOfEnum "color variants" [ "standard" "light" "dark" ] colorVariants;
|
||||||
|
=>
|
||||||
|
error: color variants: bright, black unexpected; valid ones: standard, light, dark
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
*/
|
||||||
|
checkListOfEnum = msg: valid: given:
|
||||||
|
let
|
||||||
|
unexpected = lib.subtractLists valid given;
|
||||||
|
in
|
||||||
|
foundation.throwIfNot (unexpected == [])
|
||||||
|
"${msg}: ${builtins.concatStringsSep ", " (builtins.map builtins.toString unexpected)} unexpected; valid ones: ${builtins.concatStringsSep ", " (builtins.map builtins.toString valid)}";
|
||||||
|
|
||||||
|
info = msg: builtins.trace "INFO: ${msg}";
|
||||||
|
|
||||||
|
showWarnings = warnings: res: foundation.foldr (w: x: warn w x) res warnings;
|
||||||
|
|
||||||
|
## Function annotations
|
||||||
|
|
||||||
|
/**
|
||||||
|
`mirrorFunctionArgs f g` creates a new function `g'` with the same behavior as `g` (`g' x == g x`)
|
||||||
|
but its function arguments mirroring `f` (`lib.functionArgs g' == lib.functionArgs f`).
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`f`
|
||||||
|
|
||||||
|
: Function to provide the argument metadata
|
||||||
|
|
||||||
|
`g`
|
||||||
|
|
||||||
|
: Function to set the argument metadata to
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
mirrorFunctionArgs :: (a -> b) -> (a -> c) -> (a -> c)
|
||||||
|
```
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
:::{.example}
|
||||||
|
## `lib.trivial.mirrorFunctionArgs` usage example
|
||||||
|
|
||||||
|
```nix
|
||||||
|
addab = {a, b}: a + b
|
||||||
|
addab { a = 2; b = 4; }
|
||||||
|
=> 6
|
||||||
|
lib.functionArgs addab
|
||||||
|
=> { a = false; b = false; }
|
||||||
|
addab1 = attrs: addab attrs + 1
|
||||||
|
addab1 { a = 2; b = 4; }
|
||||||
|
=> 7
|
||||||
|
lib.functionArgs addab1
|
||||||
|
=> { }
|
||||||
|
addab1' = lib.mirrorFunctionArgs addab addab1
|
||||||
|
addab1' { a = 2; b = 4; }
|
||||||
|
=> 7
|
||||||
|
lib.functionArgs addab1'
|
||||||
|
=> { a = false; b = false; }
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
*/
|
||||||
|
mirrorFunctionArgs =
|
||||||
|
f:
|
||||||
|
let
|
||||||
|
fArgs = foundation.functionArgs f;
|
||||||
|
in
|
||||||
|
g:
|
||||||
|
foundation.setFunctionArgs g fArgs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Turns any non-callable values into constant functions.
|
||||||
|
Returns callable values as is.
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`v`
|
||||||
|
|
||||||
|
: Any value
|
||||||
|
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
:::{.example}
|
||||||
|
## `lib.trivial.toFunction` usage example
|
||||||
|
|
||||||
|
```nix
|
||||||
|
nix-repl> lib.toFunction 1 2
|
||||||
|
1
|
||||||
|
|
||||||
|
nix-repl> lib.toFunction (x: x + 1) 2
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
*/
|
||||||
|
toFunction =
|
||||||
|
v:
|
||||||
|
if foundation.isFunction v
|
||||||
|
then v
|
||||||
|
else k: v;
|
||||||
|
|
||||||
|
/**
|
||||||
|
`toBaseDigits base i` converts the positive integer i to a list of its
|
||||||
|
digits in the given base. For example:
|
||||||
|
|
||||||
|
toBaseDigits 10 123 => [ 1 2 3 ]
|
||||||
|
|
||||||
|
toBaseDigits 2 6 => [ 1 1 0 ]
|
||||||
|
|
||||||
|
toBaseDigits 16 250 => [ 15 10 ]
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
|
||||||
|
`base`
|
||||||
|
|
||||||
|
: 1\. Function argument
|
||||||
|
|
||||||
|
`i`
|
||||||
|
|
||||||
|
: 2\. Function argument
|
||||||
|
*/
|
||||||
|
toBaseDigits = base: i:
|
||||||
|
let
|
||||||
|
go = i:
|
||||||
|
if i < base
|
||||||
|
then [i]
|
||||||
|
else
|
||||||
|
let
|
||||||
|
r = i - ((i / base) * base);
|
||||||
|
q = (i - r) / base;
|
||||||
|
in
|
||||||
|
[r] ++ go q;
|
||||||
|
in
|
||||||
|
assert (builtin.isInt base);
|
||||||
|
assert (builtin.isInt i);
|
||||||
|
assert (base >= 2);
|
||||||
|
assert (i >= 0);
|
||||||
|
foundation.reverseList (go i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convert the given positive integer to a string of its hexadecimal
|
||||||
|
representation. For example:
|
||||||
|
|
||||||
|
toHexString 0 => "0"
|
||||||
|
|
||||||
|
toHexString 16 => "10"
|
||||||
|
|
||||||
|
toHexString 250 => "FA"
|
||||||
|
*/
|
||||||
|
toHexString = let
|
||||||
|
hexDigits = {
|
||||||
|
"10" = "A";
|
||||||
|
"11" = "B";
|
||||||
|
"12" = "C";
|
||||||
|
"13" = "D";
|
||||||
|
"14" = "E";
|
||||||
|
"15" = "F";
|
||||||
|
};
|
||||||
|
toHexDigit = d:
|
||||||
|
if d < 10
|
||||||
|
then toString d
|
||||||
|
else hexDigits.${toString d};
|
||||||
|
in i: lib.concatMapStrings toHexDigit (toBaseDigits 16 i);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue