Loading lib/trivial.nix +727 −214 Original line number Diff line number Diff line Loading @@ -16,35 +16,87 @@ in { ## Simple (higher order) functions /* The identity function /** The identity function For when you need a function that does “nothing”. Type: id :: a -> a # Inputs `x` : The value to return # Type ``` id :: a -> a ``` */ id = # The value to return x: x; id = x: x; /* The constant function /** The constant function Ignores the second argument. If called with only one argument, constructs a function that always returns a static value. Type: const :: a -> b -> a Example: # Inputs `x` : Value to return `y` : Value to ignore # Type ``` const :: a -> b -> a ``` # Examples :::{.example} ## `lib.trivial.const` usage example ```nix let f = const 5; in f 10 => 5 ``` ::: */ const = # Value to return x: # Value to ignore y: x; /* Pipes a value through a list of functions, left to right. /** Pipes a value through a list of functions, left to right. Type: pipe :: a -> [<functions>] -> <return type of last function> Example: # Inputs `value` : Value to start piping. `fns` : List of functions to apply sequentially. # Type ``` pipe :: a -> [<functions>] -> <return type of last function> ``` # Examples :::{.example} ## `lib.trivial.pipe` usage example ```nix pipe 2 [ (x: x + 2) # 2 + 2 = 4 (x: x * 2) # 4 * 2 = 8 Loading @@ -69,6 +121,9 @@ in { The output type of each function has to be the input type of the next function, and the last function returns the final value. ``` ::: */ pipe = builtins.foldl' (x: f: f x); Loading @@ -79,71 +134,197 @@ in { ## Named versions corresponding to some builtin operators. /* Concatenate two lists /** Concatenate two lists # Inputs `x` : 1\. Function argument `y` : 2\. Function argument Type: concat :: [a] -> [a] -> [a] # Type Example: ``` concat :: [a] -> [a] -> [a] ``` # Examples :::{.example} ## `lib.trivial.concat` usage example ```nix concat [ 1 2 ] [ 3 4 ] => [ 1 2 3 4 ] ``` ::: */ concat = x: y: x ++ y; /* boolean “or” */ /** boolean “or” # Inputs `x` : 1\. Function argument `y` : 2\. Function argument */ or = x: y: x || y; /* boolean “and” */ /** boolean “and” # Inputs `x` : 1\. Function argument `y` : 2\. Function argument */ and = x: y: x && y; /* bitwise “not” */ /** bitwise “not” */ bitNot = builtins.sub (-1); /* Convert a boolean to a string. /** Convert a boolean to a string. This function uses the strings "true" and "false" to represent boolean values. Calling `toString` on a bool instead returns "1" and "" (sic!). Type: boolToString :: bool -> string # Inputs `b` : 1\. Function argument # Type ``` boolToString :: bool -> string ``` */ boolToString = b: if b then "true" else "false"; /* Merge two attribute sets shallowly, right side trumps left /** Merge two attribute sets shallowly, right side trumps left mergeAttrs :: attrs -> attrs -> attrs Example: # Inputs `x` : Left attribute set `y` : Right attribute set (higher precedence for equal keys) # Examples :::{.example} ## `lib.trivial.mergeAttrs` usage example ```nix mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; } => { a = 1; b = 3; c = 4; } ``` ::: */ mergeAttrs = # Left attribute set x: # Right attribute set (higher precedence for equal keys) y: x // y; /* Flip the order of the arguments of a binary function. /** Flip the order of the arguments of a binary function. # Inputs `f` : 1\. Function argument `a` : 2\. Function argument Type: flip :: (a -> b -> c) -> (b -> a -> c) `b` Example: : 3\. Function argument # Type ``` flip :: (a -> b -> c) -> (b -> a -> c) ``` # Examples :::{.example} ## `lib.trivial.flip` usage example ```nix flip concat [1] [2] => [ 2 1 ] ``` ::: */ flip = f: a: b: f b a; /* Apply function if the supplied argument is non-null. /** Apply function if the supplied argument is non-null. # Inputs Example: `f` : Function to call `a` : Argument to check for null before passing it to `f` # Examples :::{.example} ## `lib.trivial.mapNullable` usage example ```nix mapNullable (x: x+1) null => null mapNullable (x: x+1) 22 => 23 ``` ::: */ mapNullable = # Function to call f: # Argument to check for null before passing it to `f` a: if a == null then a else f a; # Pull in some builtins not included elsewhere. Loading @@ -155,13 +336,18 @@ in { ## nixpkgs version strings /* Returns the current full nixpkgs version number. */ /** Returns the current full nixpkgs version number. */ version = release + versionSuffix; /* Returns the current nixpkgs release number as string. */ /** Returns the current nixpkgs release number as string. */ release = lib.strings.fileContents ./.version; /* The latest release that is supported, at the time of release branch-off, /** The latest release that is supported, at the time of release branch-off, if applicable. Ideally, out-of-tree modules should be able to evaluate cleanly with all Loading @@ -171,41 +357,63 @@ in { losing support for supported Nixpkgs versions. This release number allows deprecation warnings to be implemented such that they take effect as soon as the oldest release reaches end of life. */ they take effect as soon as the oldest release reaches end of life. */ oldestSupportedRelease = # Update on master only. Do not backport. 2311; /* Whether a feature is supported in all supported releases (at the time of release branch-off, if applicable). See `oldestSupportedRelease`. */ isInOldestRelease = /* Release number of feature introduction as an integer, e.g. 2111 for 21.11. /** 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 <= lib.trivial.oldestSupportedRelease; /* Returns the current nixpkgs release code name. /** Returns the current nixpkgs release code name. On each release the first letter is bumped and a new animal is chosen starting with that new letter. */ codeName = "Uakari"; /* Returns the current nixpkgs version suffix as string. */ /** Returns the current nixpkgs version suffix as string. */ versionSuffix = let suffixFile = ../.version-suffix; in if pathExists suffixFile then lib.strings.fileContents suffixFile else "pre-git"; /* Attempts to return the the current revision of nixpkgs and /** Attempts to return the the current revision of nixpkgs and returns the supplied default value otherwise. Type: revisionWithDefault :: string -> string # Inputs `default` : Default value to return if revision can not be determined # Type ``` revisionWithDefault :: string -> string ``` */ revisionWithDefault = # Default value to return if revision can not be determined default: let revisionFile = "${toString ./..}/.git-revision"; Loading @@ -217,47 +425,115 @@ in { nixpkgsVersion = warn "lib.nixpkgsVersion is a deprecated alias of lib.version." version; /* Determine whether the function is being called from inside a Nix /** Determine whether the function is being called from inside a Nix shell. Type: inNixShell :: bool # Type ``` inNixShell :: bool ``` */ inNixShell = builtins.getEnv "IN_NIX_SHELL" != ""; /* Determine whether the function is being called from inside pure-eval mode /** 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 # Type ``` inPureEvalMode :: bool ``` */ inPureEvalMode = ! builtins ? currentSystem; ## Integer operations /* Return minimum of two numbers. */ /** 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. */ /** 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 /** Integer modulus # Inputs `base` : 1\. Function argument `int` : 2\. Function argument Example: # 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 /** 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 Loading @@ -266,14 +542,46 @@ in { then 1 else 0; /* Split type into two subtypes by predicate `p`, take all elements /** 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. Type: (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int) Example: # 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 Loading @@ -283,33 +591,51 @@ in { cmp "fooa" "a" => -1 # while compare "fooa" "a" => 1 ``` ::: */ splitByAndCompare = # Predicate p: # Comparison function if predicate holds for both values yes: # Comparison function if predicate holds for neither value no: # First value to compare a: # Second value to compare b: 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. /** Reads a JSON file. # Inputs `path` Type: importJSON :: path -> any : 1\. Function argument # Type ``` importJSON :: path -> any ``` */ importJSON = path: builtins.fromJSON (builtins.readFile path); /* Reads a TOML file. /** Reads a TOML file. Type: importTOML :: path -> any # Inputs `path` : 1\. Function argument # Type ``` importTOML :: path -> any ``` */ importTOML = path: builtins.fromTOML (builtins.readFile path); Loading @@ -329,7 +655,7 @@ in { # TODO: figure out a clever way to integrate location information from # something like __unsafeGetAttrPos. /* /** Print a warning before returning the second argument. This function behaves like `builtins.trace`, but requires a string message and formats it as a warning, including the `warning: ` prefix. Loading @@ -337,28 +663,80 @@ in { To get a call stack trace and abort evaluation, set the environment variable `NIX_ABORT_ON_WARN=true` and set the Nix options `--option pure-eval false --show-trace` Type: string -> a -> a # Inputs `msg` : Warning message to print. `val` : Value to return as-is. # Type ``` string -> a -> a ``` */ warn = if lib.elem (builtins.getEnv "NIX_ABORT_ON_WARN") ["1" "true" "yes"] then msg: builtins.trace "[1;31mwarning: ${msg}[0m" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.") else msg: builtins.trace "[1;31mwarning: ${msg}[0m"; /* /** Like warn, but only warn when the first argument is `true`. Type: bool -> string -> a -> a # 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`). Type: bool -> string -> a -> a # 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 the `assert b; e` expression, but with a custom error message and without the semicolon. Loading @@ -369,33 +747,95 @@ in { Calls can be juxtaposed using function application, as `(r: r) a = a`, so `(r: r) (r: r) a = a`, and so forth. Type: bool -> string -> a -> a Example: # Inputs `cond` : 1\. Function argument `msg` : 2\. Function argument # Type ``` bool -> string -> a -> a ``` # Examples :::{.example} ## `lib.trivial.throwIfNot` usage example ```nix throwIfNot (lib.isList overlays) "The overlays argument to nixpkgs must be a list." lib.foldr (x: throwIfNot (lib.isFunction x) "All overlays passed to nixpkgs must be functions.") (r: r) overlays pkgs ``` ::: */ throwIfNot = cond: msg: if cond then x: x else throw msg; /* /** Like throwIfNot, but negated (throw if the first argument is `true`). Type: bool -> string -> a -> a # 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. /** Check if the elements in a list are valid values from a enum, returning the identity function, or throwing an error message otherwise. # Inputs Example: `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 ``` Type: String -> List ComparableVal -> List ComparableVal -> a -> a ::: */ checkListOfEnum = msg: valid: given: let Loading @@ -410,7 +850,8 @@ in { ## Function annotations /* Add metadata about expected function arguments to a function. /** Add metadata about expected function arguments to a function. The metadata should match the format given by builtins.functionArgs, i.e. a set from expected argument to a bool representing whether that argument has a default or not. Loading @@ -419,6 +860,17 @@ in { This function is necessary because you can't dynamically create a function of the { a, b ? foo, ... }: format, but some facilities like callPackage expect to be able to query expected arguments. # Inputs `f` : 1\. Function argument `args` : 2\. Function argument */ setFunctionArgs = f: args: { # TODO: Should we add call-time "type" checking like built in? Loading @@ -426,31 +878,65 @@ in { __functionArgs = args; }; /* Extract the expected function arguments from a function. /** Extract the expected function arguments from a function. This works both with nix-native { a, b ? foo, ... }: style functions and functions with args set with 'setFunctionArgs'. It has the same return type and semantics as builtins.functionArgs. setFunctionArgs : (a → b) → Map String Bool. # Inputs `f` : 1\. Function argument */ functionArgs = f: if f ? __functor then f.__functionArgs or (functionArgs (f.__functor f)) else builtins.functionArgs f; /* Check whether something is a function or something /** Check whether something is a function or something annotated with function args. # Inputs `f` : 1\. Function argument */ isFunction = f: builtins.isFunction f || (f ? __functor && isFunction (f.__functor f)); /* /** `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`). Type: # Inputs `f` : Function to provide the argument metadata `g` : Function to set the argument metadata to # Type ``` mirrorFunctionArgs :: (a -> b) -> (a -> c) -> (a -> c) ``` Example: # Examples :::{.example} ## `lib.trivial.mirrorFunctionArgs` usage example ```nix addab = {a, b}: a + b addab { a = 2; b = 4; } => 6 Loading @@ -466,37 +952,52 @@ in { => 7 lib.functionArgs addab1' => { a = false; b = false; } ``` ::: */ mirrorFunctionArgs = # Function to provide the argument metadata f: let fArgs = functionArgs f; in # Function to set the argument metadata to g: setFunctionArgs g fArgs; /* /** Turns any non-callable values into constant functions. Returns callable values as is. Example: # 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 = # Any value v: if isFunction v then v else k: v; /* Convert the given positive integer to a string of its hexadecimal /** Convert the given positive integer to a string of its hexadecimal representation. For example: toHexString 0 => "0" Loading @@ -520,7 +1021,8 @@ in { 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 /** `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 ] Loading @@ -528,6 +1030,17 @@ in { toBaseDigits 2 6 => [ 1 1 0 ] toBaseDigits 16 250 => [ 15 10 ] # Inputs `base` : 1\. Function argument `i` : 2\. Function argument */ toBaseDigits = base: i: let Loading Loading
lib/trivial.nix +727 −214 Original line number Diff line number Diff line Loading @@ -16,35 +16,87 @@ in { ## Simple (higher order) functions /* The identity function /** The identity function For when you need a function that does “nothing”. Type: id :: a -> a # Inputs `x` : The value to return # Type ``` id :: a -> a ``` */ id = # The value to return x: x; id = x: x; /* The constant function /** The constant function Ignores the second argument. If called with only one argument, constructs a function that always returns a static value. Type: const :: a -> b -> a Example: # Inputs `x` : Value to return `y` : Value to ignore # Type ``` const :: a -> b -> a ``` # Examples :::{.example} ## `lib.trivial.const` usage example ```nix let f = const 5; in f 10 => 5 ``` ::: */ const = # Value to return x: # Value to ignore y: x; /* Pipes a value through a list of functions, left to right. /** Pipes a value through a list of functions, left to right. Type: pipe :: a -> [<functions>] -> <return type of last function> Example: # Inputs `value` : Value to start piping. `fns` : List of functions to apply sequentially. # Type ``` pipe :: a -> [<functions>] -> <return type of last function> ``` # Examples :::{.example} ## `lib.trivial.pipe` usage example ```nix pipe 2 [ (x: x + 2) # 2 + 2 = 4 (x: x * 2) # 4 * 2 = 8 Loading @@ -69,6 +121,9 @@ in { The output type of each function has to be the input type of the next function, and the last function returns the final value. ``` ::: */ pipe = builtins.foldl' (x: f: f x); Loading @@ -79,71 +134,197 @@ in { ## Named versions corresponding to some builtin operators. /* Concatenate two lists /** Concatenate two lists # Inputs `x` : 1\. Function argument `y` : 2\. Function argument Type: concat :: [a] -> [a] -> [a] # Type Example: ``` concat :: [a] -> [a] -> [a] ``` # Examples :::{.example} ## `lib.trivial.concat` usage example ```nix concat [ 1 2 ] [ 3 4 ] => [ 1 2 3 4 ] ``` ::: */ concat = x: y: x ++ y; /* boolean “or” */ /** boolean “or” # Inputs `x` : 1\. Function argument `y` : 2\. Function argument */ or = x: y: x || y; /* boolean “and” */ /** boolean “and” # Inputs `x` : 1\. Function argument `y` : 2\. Function argument */ and = x: y: x && y; /* bitwise “not” */ /** bitwise “not” */ bitNot = builtins.sub (-1); /* Convert a boolean to a string. /** Convert a boolean to a string. This function uses the strings "true" and "false" to represent boolean values. Calling `toString` on a bool instead returns "1" and "" (sic!). Type: boolToString :: bool -> string # Inputs `b` : 1\. Function argument # Type ``` boolToString :: bool -> string ``` */ boolToString = b: if b then "true" else "false"; /* Merge two attribute sets shallowly, right side trumps left /** Merge two attribute sets shallowly, right side trumps left mergeAttrs :: attrs -> attrs -> attrs Example: # Inputs `x` : Left attribute set `y` : Right attribute set (higher precedence for equal keys) # Examples :::{.example} ## `lib.trivial.mergeAttrs` usage example ```nix mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; } => { a = 1; b = 3; c = 4; } ``` ::: */ mergeAttrs = # Left attribute set x: # Right attribute set (higher precedence for equal keys) y: x // y; /* Flip the order of the arguments of a binary function. /** Flip the order of the arguments of a binary function. # Inputs `f` : 1\. Function argument `a` : 2\. Function argument Type: flip :: (a -> b -> c) -> (b -> a -> c) `b` Example: : 3\. Function argument # Type ``` flip :: (a -> b -> c) -> (b -> a -> c) ``` # Examples :::{.example} ## `lib.trivial.flip` usage example ```nix flip concat [1] [2] => [ 2 1 ] ``` ::: */ flip = f: a: b: f b a; /* Apply function if the supplied argument is non-null. /** Apply function if the supplied argument is non-null. # Inputs Example: `f` : Function to call `a` : Argument to check for null before passing it to `f` # Examples :::{.example} ## `lib.trivial.mapNullable` usage example ```nix mapNullable (x: x+1) null => null mapNullable (x: x+1) 22 => 23 ``` ::: */ mapNullable = # Function to call f: # Argument to check for null before passing it to `f` a: if a == null then a else f a; # Pull in some builtins not included elsewhere. Loading @@ -155,13 +336,18 @@ in { ## nixpkgs version strings /* Returns the current full nixpkgs version number. */ /** Returns the current full nixpkgs version number. */ version = release + versionSuffix; /* Returns the current nixpkgs release number as string. */ /** Returns the current nixpkgs release number as string. */ release = lib.strings.fileContents ./.version; /* The latest release that is supported, at the time of release branch-off, /** The latest release that is supported, at the time of release branch-off, if applicable. Ideally, out-of-tree modules should be able to evaluate cleanly with all Loading @@ -171,41 +357,63 @@ in { losing support for supported Nixpkgs versions. This release number allows deprecation warnings to be implemented such that they take effect as soon as the oldest release reaches end of life. */ they take effect as soon as the oldest release reaches end of life. */ oldestSupportedRelease = # Update on master only. Do not backport. 2311; /* Whether a feature is supported in all supported releases (at the time of release branch-off, if applicable). See `oldestSupportedRelease`. */ isInOldestRelease = /* Release number of feature introduction as an integer, e.g. 2111 for 21.11. /** 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 <= lib.trivial.oldestSupportedRelease; /* Returns the current nixpkgs release code name. /** Returns the current nixpkgs release code name. On each release the first letter is bumped and a new animal is chosen starting with that new letter. */ codeName = "Uakari"; /* Returns the current nixpkgs version suffix as string. */ /** Returns the current nixpkgs version suffix as string. */ versionSuffix = let suffixFile = ../.version-suffix; in if pathExists suffixFile then lib.strings.fileContents suffixFile else "pre-git"; /* Attempts to return the the current revision of nixpkgs and /** Attempts to return the the current revision of nixpkgs and returns the supplied default value otherwise. Type: revisionWithDefault :: string -> string # Inputs `default` : Default value to return if revision can not be determined # Type ``` revisionWithDefault :: string -> string ``` */ revisionWithDefault = # Default value to return if revision can not be determined default: let revisionFile = "${toString ./..}/.git-revision"; Loading @@ -217,47 +425,115 @@ in { nixpkgsVersion = warn "lib.nixpkgsVersion is a deprecated alias of lib.version." version; /* Determine whether the function is being called from inside a Nix /** Determine whether the function is being called from inside a Nix shell. Type: inNixShell :: bool # Type ``` inNixShell :: bool ``` */ inNixShell = builtins.getEnv "IN_NIX_SHELL" != ""; /* Determine whether the function is being called from inside pure-eval mode /** 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 # Type ``` inPureEvalMode :: bool ``` */ inPureEvalMode = ! builtins ? currentSystem; ## Integer operations /* Return minimum of two numbers. */ /** 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. */ /** 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 /** Integer modulus # Inputs `base` : 1\. Function argument `int` : 2\. Function argument Example: # 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 /** 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 Loading @@ -266,14 +542,46 @@ in { then 1 else 0; /* Split type into two subtypes by predicate `p`, take all elements /** 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. Type: (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int) Example: # 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 Loading @@ -283,33 +591,51 @@ in { cmp "fooa" "a" => -1 # while compare "fooa" "a" => 1 ``` ::: */ splitByAndCompare = # Predicate p: # Comparison function if predicate holds for both values yes: # Comparison function if predicate holds for neither value no: # First value to compare a: # Second value to compare b: 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. /** Reads a JSON file. # Inputs `path` Type: importJSON :: path -> any : 1\. Function argument # Type ``` importJSON :: path -> any ``` */ importJSON = path: builtins.fromJSON (builtins.readFile path); /* Reads a TOML file. /** Reads a TOML file. Type: importTOML :: path -> any # Inputs `path` : 1\. Function argument # Type ``` importTOML :: path -> any ``` */ importTOML = path: builtins.fromTOML (builtins.readFile path); Loading @@ -329,7 +655,7 @@ in { # TODO: figure out a clever way to integrate location information from # something like __unsafeGetAttrPos. /* /** Print a warning before returning the second argument. This function behaves like `builtins.trace`, but requires a string message and formats it as a warning, including the `warning: ` prefix. Loading @@ -337,28 +663,80 @@ in { To get a call stack trace and abort evaluation, set the environment variable `NIX_ABORT_ON_WARN=true` and set the Nix options `--option pure-eval false --show-trace` Type: string -> a -> a # Inputs `msg` : Warning message to print. `val` : Value to return as-is. # Type ``` string -> a -> a ``` */ warn = if lib.elem (builtins.getEnv "NIX_ABORT_ON_WARN") ["1" "true" "yes"] then msg: builtins.trace "[1;31mwarning: ${msg}[0m" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.") else msg: builtins.trace "[1;31mwarning: ${msg}[0m"; /* /** Like warn, but only warn when the first argument is `true`. Type: bool -> string -> a -> a # 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`). Type: bool -> string -> a -> a # 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 the `assert b; e` expression, but with a custom error message and without the semicolon. Loading @@ -369,33 +747,95 @@ in { Calls can be juxtaposed using function application, as `(r: r) a = a`, so `(r: r) (r: r) a = a`, and so forth. Type: bool -> string -> a -> a Example: # Inputs `cond` : 1\. Function argument `msg` : 2\. Function argument # Type ``` bool -> string -> a -> a ``` # Examples :::{.example} ## `lib.trivial.throwIfNot` usage example ```nix throwIfNot (lib.isList overlays) "The overlays argument to nixpkgs must be a list." lib.foldr (x: throwIfNot (lib.isFunction x) "All overlays passed to nixpkgs must be functions.") (r: r) overlays pkgs ``` ::: */ throwIfNot = cond: msg: if cond then x: x else throw msg; /* /** Like throwIfNot, but negated (throw if the first argument is `true`). Type: bool -> string -> a -> a # 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. /** Check if the elements in a list are valid values from a enum, returning the identity function, or throwing an error message otherwise. # Inputs Example: `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 ``` Type: String -> List ComparableVal -> List ComparableVal -> a -> a ::: */ checkListOfEnum = msg: valid: given: let Loading @@ -410,7 +850,8 @@ in { ## Function annotations /* Add metadata about expected function arguments to a function. /** Add metadata about expected function arguments to a function. The metadata should match the format given by builtins.functionArgs, i.e. a set from expected argument to a bool representing whether that argument has a default or not. Loading @@ -419,6 +860,17 @@ in { This function is necessary because you can't dynamically create a function of the { a, b ? foo, ... }: format, but some facilities like callPackage expect to be able to query expected arguments. # Inputs `f` : 1\. Function argument `args` : 2\. Function argument */ setFunctionArgs = f: args: { # TODO: Should we add call-time "type" checking like built in? Loading @@ -426,31 +878,65 @@ in { __functionArgs = args; }; /* Extract the expected function arguments from a function. /** Extract the expected function arguments from a function. This works both with nix-native { a, b ? foo, ... }: style functions and functions with args set with 'setFunctionArgs'. It has the same return type and semantics as builtins.functionArgs. setFunctionArgs : (a → b) → Map String Bool. # Inputs `f` : 1\. Function argument */ functionArgs = f: if f ? __functor then f.__functionArgs or (functionArgs (f.__functor f)) else builtins.functionArgs f; /* Check whether something is a function or something /** Check whether something is a function or something annotated with function args. # Inputs `f` : 1\. Function argument */ isFunction = f: builtins.isFunction f || (f ? __functor && isFunction (f.__functor f)); /* /** `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`). Type: # Inputs `f` : Function to provide the argument metadata `g` : Function to set the argument metadata to # Type ``` mirrorFunctionArgs :: (a -> b) -> (a -> c) -> (a -> c) ``` Example: # Examples :::{.example} ## `lib.trivial.mirrorFunctionArgs` usage example ```nix addab = {a, b}: a + b addab { a = 2; b = 4; } => 6 Loading @@ -466,37 +952,52 @@ in { => 7 lib.functionArgs addab1' => { a = false; b = false; } ``` ::: */ mirrorFunctionArgs = # Function to provide the argument metadata f: let fArgs = functionArgs f; in # Function to set the argument metadata to g: setFunctionArgs g fArgs; /* /** Turns any non-callable values into constant functions. Returns callable values as is. Example: # 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 = # Any value v: if isFunction v then v else k: v; /* Convert the given positive integer to a string of its hexadecimal /** Convert the given positive integer to a string of its hexadecimal representation. For example: toHexString 0 => "0" Loading @@ -520,7 +1021,8 @@ in { 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 /** `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 ] Loading @@ -528,6 +1030,17 @@ in { toBaseDigits 2 6 => [ 1 1 0 ] toBaseDigits 16 250 => [ 15 10 ] # Inputs `base` : 1\. Function argument `i` : 2\. Function argument */ toBaseDigits = base: i: let Loading