Unverified Commit 956fff08 authored by Johannes Kirschbauer's avatar Johannes Kirschbauer Committed by GitHub
Browse files

doc: migrate lib.trivial to use doc-comments (#297270)



* doc: migrate lib.trivial to use doc-comments

* Apply suggestions from code review

---------

Co-authored-by: default avatarDaniel Sidhion <DanielSidhion@users.noreply.github.com>
parent a737a781
Loading
Loading
Loading
Loading
+727 −214
Original line number Diff line number Diff line
@@ -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
@@ -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);

@@ -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.
@@ -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
@@ -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";
@@ -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
@@ -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
@@ -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);
@@ -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.
@@ -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 "warning: ${msg}" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.")
    else msg: builtins.trace "warning: ${msg}";

  /*
  /**
    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.

@@ -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
@@ -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.
@@ -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?
@@ -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
@@ -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"
@@ -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 ]
@@ -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