<section xmlns="http://docbook.org/ns/docbook"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        xmlns:xi="http://www.w3.org/2001/XInclude"
        version="5.0"
        xml:id="sec-option-types">

<title>Options Types</title>

  <para>Option types are a way to put constraints on the values a module option 
    can take.
    Types are also responsible of how values are merged in case of multiple 
    value definitions.</para>
  <section><title>Basic Types</title>

    <para>Basic types are the simplest available types in the module system.
      Basic types include multiple string types that mainly differ in how 
      definition merging is handled.</para>

<variablelist>
  <varlistentry>
    <term><varname>types.bool</varname></term>
    <listitem><para>A boolean, its values can be <literal>true</literal> or 
        <literal>false</literal>.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.path</varname></term>
    <listitem><para>A filesystem path, defined as anything that when coerced to 
        a string starts with a slash. Even if derivations can be considered as 
        path, the more specific <literal>types.package</literal> should be 
        preferred.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.package</varname></term>
    <listitem><para>A derivation or a store path.</para></listitem>
  </varlistentry>
</variablelist>

<para>Integer-related types:</para>

<variablelist>
  <varlistentry>
    <term><varname>types.int</varname></term>
    <listitem><para>A signed integer.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term>
      <varname>types.ints.{s8, s16, s32}</varname>
    </term>
    <listitem>
      <para>Signed integers with a fixed length (8, 16 or 32 bits).
        They go from
        <inlineequation><mathphrase>−2<superscript>n</superscript>/2</mathphrase>
        </inlineequation> to <inlineequation>
        <mathphrase>2<superscript>n</superscript>/2−1</mathphrase>
        </inlineequation>
        respectively (e.g. <literal>−128</literal> to <literal>127</literal>
        for 8 bits).
    </para></listitem>
  </varlistentry>
  <varlistentry>
    <term>
      <varname>types.ints.unsigned</varname>
    </term>
    <listitem><para>An unsigned integer (that is >= 0).
    </para></listitem>
  </varlistentry>
  <varlistentry>
    <term>
      <varname>types.ints.{u8, u16, u32}</varname>
    </term>
    <listitem>
      <para>Unsigned integers with a fixed length (8, 16 or 32 bits).
        They go from
        <inlineequation><mathphrase>0</mathphrase></inlineequation> to <inlineequation>
        <mathphrase>2<superscript>n</superscript>−1</mathphrase>
        </inlineequation>
        respectively (e.g. <literal>0</literal> to <literal>255</literal>
        for 8 bits).
    </para></listitem>
  </varlistentry>
  <varlistentry>
    <term>
      <varname>types.ints.positive</varname>
    </term>
    <listitem><para>A positive integer (that is > 0).
    </para></listitem>
  </varlistentry>
</variablelist>

<para>String-related types:</para>

<variablelist>
  <varlistentry>
    <term><varname>types.str</varname></term>
    <listitem><para>A string. Multiple definitions cannot be 
        merged.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.lines</varname></term>
    <listitem><para>A string. Multiple definitions are concatenated with a new 
        line <literal>"\n"</literal>.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.commas</varname></term>
    <listitem><para>A string. Multiple definitions are concatenated with a comma 
        <literal>","</literal>.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.envVar</varname></term>
    <listitem><para>A string. Multiple definitions are concatenated with a 
        collon <literal>":"</literal>.</para></listitem>
  </varlistentry>
</variablelist>

 </section>

 <section><title>Value Types</title>

   <para>Value types are types that take a value parameter.</para>

<variablelist>
  <varlistentry>
    <term><varname>types.enum</varname> <replaceable>l</replaceable></term>
    <listitem><para>One element of the list <replaceable>l</replaceable>, e.g. 
        <literal>types.enum [ "left" "right" ]</literal>. Multiple definitions 
        cannot be merged.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.separatedString</varname>
      <replaceable>sep</replaceable></term>
    <listitem><para>A string with a custom separator
        <replaceable>sep</replaceable>, e.g. <literal>types.separatedString
          "|"</literal>.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term>
      <varname>types.ints.between</varname>
      <replaceable>lowest</replaceable>
      <replaceable>highest</replaceable>
    </term>
    <listitem><para>An integer between <replaceable>lowest</replaceable>
        and <replaceable>highest</replaceable> (both inclusive).
        Useful for creating types like <literal>types.port</literal>.
    </para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.submodule</varname> <replaceable>o</replaceable></term>
    <listitem><para>A set of sub options <replaceable>o</replaceable>.
        <replaceable>o</replaceable> can be an attribute set or a function
        returning an attribute set. Submodules are used in composed types to
        create modular options. Submodule are detailed in <xref
          linkend='section-option-types-submodule' />.</para></listitem>
  </varlistentry>
</variablelist>
 </section>

 <section><title>Composed Types</title>

   <para>Composed types are types that take a type as parameter. <literal>listOf 
       int</literal> and <literal>either int str</literal> are examples of 
     composed types.</para>

<variablelist>
  <varlistentry>
    <term><varname>types.listOf</varname> <replaceable>t</replaceable></term>
    <listitem><para>A list of <replaceable>t</replaceable> type, e.g. 
        <literal>types.listOf int</literal>. Multiple definitions are merged 
        with list concatenation.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.attrsOf</varname> <replaceable>t</replaceable></term>
    <listitem><para>An attribute set of where all the values are of 
        <replaceable>t</replaceable> type. Multiple definitions result in the 
        joined attribute set.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.loaOf</varname> <replaceable>t</replaceable></term>
    <listitem><para>An attribute set or a list of <replaceable>t</replaceable> 
        type. Multiple definitions are merged according to the 
        value.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.nullOr</varname> <replaceable>t</replaceable></term>
    <listitem><para><literal>null</literal> or type 
        <replaceable>t</replaceable>. Multiple definitions are merged according 
        to type <replaceable>t</replaceable>.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.uniq</varname> <replaceable>t</replaceable></term>
    <listitem><para>Ensures that type <replaceable>t</replaceable> cannot be 
        merged. It is used to ensure option definitions are declared only 
        once.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.either</varname> <replaceable>t1</replaceable> 
      <replaceable>t2</replaceable></term>
    <listitem><para>Type <replaceable>t1</replaceable> or type 
        <replaceable>t2</replaceable>, e.g. <literal>with types; either int 
          str</literal>. Multiple definitions cannot be 
        merged.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>types.coercedTo</varname> <replaceable>from</replaceable>
        <replaceable>f</replaceable> <replaceable>to</replaceable></term>
    <listitem><para>Type <replaceable>to</replaceable> or type
        <replaceable>from</replaceable> which will be coerced to
	type <replaceable>to</replaceable> using function
	<replaceable>f</replaceable> which takes an argument of type
        <replaceable>from</replaceable> and return a value of type
	<replaceable>to</replaceable>. Can be used to preserve backwards
        compatibility of an option if its type was changed.</para></listitem>
  </varlistentry>
</variablelist>

</section>

<section xml:id='section-option-types-submodule'><title>Submodule</title>

  <para><literal>submodule</literal> is a very powerful type that defines a set
    of sub-options that are handled like a separate module.</para>

  <para>It takes a parameter <replaceable>o</replaceable>, that should be a set,
    or a function returning a set with an <literal>options</literal> key
    defining the sub-options.
    Submodule option definitions are type-checked accordingly to the
    <literal>options</literal> declarations.
    Of course, you can nest submodule option definitons for even higher
    modularity.</para>

  <para>The option set can be defined directly
    (<xref linkend='ex-submodule-direct' />) or as reference
    (<xref linkend='ex-submodule-reference' />).</para>

<example xml:id='ex-submodule-direct'><title>Directly defined submodule</title>
<screen>
options.mod = mkOption {
  description = "submodule example";
  type = with types; submodule {
    options = {
      foo = mkOption {
        type = int;
      };
      bar = mkOption {
        type = str;
      };
    };
  };
};</screen></example>

<example xml:id='ex-submodule-reference'><title>Submodule defined as a
    reference</title>
<screen>
let
  modOptions = {
    options = {
      foo = mkOption {
        type = int;
      };
      bar = mkOption {
        type = int;
      };
    };
  };
in
options.mod = mkOption {
  description = "submodule example";
  type = with types; submodule modOptions;
};</screen></example>

  <para>The <literal>submodule</literal> type is especially interesting when
    used with composed types like <literal>attrsOf</literal> or
    <literal>listOf</literal>.
    When composed with <literal>listOf</literal>
    (<xref linkend='ex-submodule-listof-declaration' />),
    <literal>submodule</literal> allows multiple definitions of the submodule
    option set (<xref linkend='ex-submodule-listof-definition' />).</para>
    

<example xml:id='ex-submodule-listof-declaration'><title>Declaration of a list 
    nof submodules</title>
<screen>
options.mod = mkOption {
  description = "submodule example";
  type = with types; listOf (submodule {
    options = {
      foo = mkOption {
        type = int;
      };
      bar = mkOption {
        type = str;
      };
    };
  });
};</screen></example>

<example xml:id='ex-submodule-listof-definition'><title>Definition of a list of 
    submodules</title>
<screen>
config.mod = [
  { foo = 1; bar = "one"; }
  { foo = 2; bar = "two"; }
];</screen></example>

  <para>When composed with <literal>attrsOf</literal>
    (<xref linkend='ex-submodule-attrsof-declaration' />),
    <literal>submodule</literal> allows multiple named definitions of the
    submodule option set (<xref linkend='ex-submodule-attrsof-definition' />).
  </para>

<example xml:id='ex-submodule-attrsof-declaration'><title>Declaration of 
    attribute sets of submodules</title>
<screen>
options.mod = mkOption {
  description = "submodule example";
  type = with types; attrsOf (submodule {
    options = {
      foo = mkOption {
        type = int;
      };
      bar = mkOption {
        type = str;
      };
    };
  });
};</screen></example>

<example xml:id='ex-submodule-attrsof-definition'><title>Declaration of 
    attribute sets of submodules</title>
<screen>
config.mod.one = { foo = 1; bar = "one"; };
config.mod.two = { foo = 2; bar = "two"; };</screen></example>

</section>

<section><title>Extending types</title>

  <para>Types are mainly characterized by their <literal>check</literal> and 
    <literal>merge</literal> functions.</para>

<variablelist>
  <varlistentry>
    <term><varname>check</varname></term>
    <listitem><para>The function to type check the value. Takes a value as 
        parameter and return a boolean.
        It is possible to extend a type check with the 
        <literal>addCheck</literal> function (<xref 
          linkend='ex-extending-type-check-1' />), or to fully override the 
        check function (<xref linkend='ex-extending-type-check-2' />).</para>

<example xml:id='ex-extending-type-check-1'><title>Adding a type check</title>
<screen>
byte = mkOption {
  description = "An integer between 0 and 255.";
  type = addCheck types.int (x: x &gt;= 0 &amp;&amp; x &lt;= 255);
};</screen></example>

<example xml:id='ex-extending-type-check-2'><title>Overriding a type 
    check</title>
<screen>
nixThings = mkOption {
  description = "words that start with 'nix'";
  type = types.str // {
    check = (x: lib.hasPrefix "nix" x)
  };
};</screen></example>
    </listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>merge</varname></term>
    <listitem><para>Function to merge the options values when multiple values 
        are set.
The function takes two parameters, <literal>loc</literal> the option path as a 
list of strings, and <literal>defs</literal> the list of defined values as a 
list.
It is possible to override a type merge function for custom 
needs.</para></listitem>
  </varlistentry>
</variablelist>

</section>

<section><title>Custom Types</title>

<para>Custom types can be created with the <literal>mkOptionType</literal> 
  function.
As type creation includes some more complex topics such as submodule handling, 
it is recommended to get familiar with <filename 
  xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/types.nix">types.nix</filename> 
code before creating a new type.</para>

<para>The only required parameter is <literal>name</literal>.</para>

<variablelist>
  <varlistentry>
    <term><varname>name</varname></term>
    <listitem><para>A string representation of the type function 
        name.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>definition</varname></term>
    <listitem><para>Description of the type used in documentation. Give 
        information of the type and any of its arguments.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>check</varname></term>
    <listitem><para>A function to type check the definition value. Takes the 
        definition value as a parameter and returns a boolean indicating the 
        type check result, <literal>true</literal> for success and 
        <literal>false</literal> for failure.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>merge</varname></term>
    <listitem><para>A function to merge multiple definitions values. Takes two 
        parameters:</para>
      <variablelist>
        <varlistentry>
          <term><replaceable>loc</replaceable></term>
          <listitem><para>The option path as a list of strings, e.g. 
              <literal>["boot" "loader "grub" 
                "enable"]</literal>.</para></listitem>
        </varlistentry>
        <varlistentry>
          <term><replaceable>defs</replaceable></term>
          <listitem><para>The list of sets of defined <literal>value</literal> 
              and <literal>file</literal> where the value was defined, e.g. 
              <literal>[ { file = "/foo.nix"; value = 1; } { file = "/bar.nix"; 
                value = 2 } ]</literal>. The <literal>merge</literal> function 
              should return the merged value or throw an error in case the 
              values are impossible or not meant to be merged.</para></listitem>
        </varlistentry>
      </variablelist>
    </listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>getSubOptions</varname></term>
    <listitem><para>For composed types that can take a submodule as type 
        parameter, this function generate sub-options documentation. It takes 
        the current option prefix as a list and return the set of sub-options. 
        Usually defined in a recursive manner by adding a term to the prefix, 
        e.g. <literal>prefix: elemType.getSubOptions (prefix ++ 
          [<replaceable>"prefix"</replaceable>])</literal> where 
        <replaceable>"prefix"</replaceable> is the newly added 
        prefix.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>getSubModules</varname></term>
    <listitem><para>For composed types that can take a submodule as type 
        parameter, this function should return the type parameters submodules. 
        If the type parameter is called <literal>elemType</literal>, the 
        function should just recursively look into submodules by returning 
        <literal>elemType.getSubModules;</literal>.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>substSubModules</varname></term>
    <listitem><para>For composed types that can take a submodule as type 
        parameter, this function can be used to substitute the parameter of a 
        submodule type. It takes a module as parameter and return the type with 
        the submodule options substituted. It is usually defined as a type 
        function call with a recursive call to 
        <literal>substSubModules</literal>, e.g for a type 
        <literal>composedType</literal> that take an <literal>elemtype</literal> 
        type parameter, this function should be defined as <literal>m: 
          composedType (elemType.substSubModules m)</literal>.</para></listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>typeMerge</varname></term>
    <listitem><para>A function to merge multiple type declarations. Takes the 
        type to merge <literal>functor</literal> as parameter. A 
        <literal>null</literal> return value means that type cannot be 
        merged.</para>
      <variablelist>
        <varlistentry>
          <term><replaceable>f</replaceable></term>
          <listitem><para>The type to merge  
              <literal>functor</literal>.</para></listitem>
        </varlistentry>
      </variablelist>
      <para>Note: There is a generic <literal>defaultTypeMerge</literal> that 
        work with most of value and composed types.</para>
    </listitem>
  </varlistentry>
  <varlistentry>
    <term><varname>functor</varname></term>
    <listitem><para>An attribute set representing the type. It is used for type 
        operations and has the following keys:</para>
      <variablelist>
        <varlistentry>
          <term><varname>type</varname></term>
          <listitem><para>The type function.</para></listitem>
        </varlistentry>
        <varlistentry>
          <term><varname>wrapped</varname></term>
          <listitem><para>Holds the type parameter for composed types.</para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term><varname>payload</varname></term>
          <listitem><para>Holds the value parameter for value types. 
              The types that have a <literal>payload</literal> are the
              <literal>enum</literal>, <literal>separatedString</literal> and
              <literal>submodule</literal> types.</para></listitem>
        </varlistentry>
        <varlistentry>
          <term><varname>binOp</varname></term>
          <listitem><para>A binary operation that can merge the payloads of two 
              same types. Defined as a function that take two payloads as 
              parameters and return the payloads merged.</para></listitem>
        </varlistentry>
      </variablelist>
    </listitem>
  </varlistentry>
</variablelist>

</section>
</section>
