* Refactoring: move the types out of options.nix, which is much too

big.  Also, they could be useful beyond option handling.

svn path=/nixpkgs/trunk/; revision=16055
This commit is contained in:
Eelco Dolstra 2009-06-26 13:53:31 +00:00
parent dd50af4923
commit a440fba8e3
3 changed files with 127 additions and 111 deletions

View file

@ -7,13 +7,14 @@ let
attrsets = import ./attrsets.nix;
sources = import ./sources.nix;
options = import ./options.nix;
types = import ./types.nix;
meta = import ./meta.nix;
debug = import ./debug.nix;
misc = import ./misc.nix;
in
{ inherit trivial lists strings stringsWithDeps attrsets sources options meta debug; }
{ inherit trivial lists strings stringsWithDeps attrsets sources options types meta debug; }
# !!! don't include everything at top-level; perhaps only the most
# commonly used functions.
// trivial // lists // strings // stringsWithDeps // attrsets // sources
// options // meta // debug // misc
// options // types // meta // debug // misc

View file

@ -10,9 +10,8 @@ with import ./attrsets.nix;
rec {
hasType = x: isAttrs x && x ? _type;
typeOf = x: if hasType x then x._type else "";
inherit (lib) typeOf;
isOption = attrs: (typeOf attrs) == "option";
mkOption = attrs: attrs // {
@ -131,112 +130,7 @@ rec {
opt1 // opt2
)) {} opts;
# name (name of the type)
# check (boolean function)
# merge (default merge function)
# iter (iterate on all elements contained in this type)
# fold (fold all elements contained in this type)
# hasOptions (boolean: whatever this option contains an option set)
# path (path contatenated to the option name contained contained in the option set)
isOptionType = attrs: (typeOf attrs) == "option-type";
mkOptionType = attrs@{
name
, check ? (x: true)
, merge ? mergeDefaultOption
# Handle complex structure types.
, iter ? (f: path: v: f path v)
, fold ? (op: nul: v: op v nul)
, docPath ? lib.id
# If the type can contains option sets.
, hasOptions ? false
}: { _type = "option-type";
inherit name check merge iter fold docPath hasOptions;
};
types = {
inferred = mkOptionType {
name = "inferred type";
};
bool = mkOptionType {
name = "boolean";
check = lib.traceValIfNot builtins.isBool;
merge = fold lib.or false;
};
int = mkOptionType {
name = "integer";
check = lib.traceValIfNot builtins.isInt;
};
string = mkOptionType {
name = "string";
check = lib.traceValIfNot (x: builtins ? isString -> builtins.isString x);
merge = lib.concatStrings;
};
attrs = mkOptionType {
name = "attribute set";
check = lib.traceValIfNot builtins.isAttrs;
merge = fold lib.mergeAttrs {};
};
# derivation is a reserved keyword.
package = mkOptionType {
name = "derivation";
check = lib.traceValIfNot isDerivation;
};
list = elemType: mkOptionType {
name = "list of ${elemType.name}s";
check = value: lib.traceValIfNot isList value && all elemType.check value;
merge = concatLists;
iter = f: path: list: map (elemType.iter f (path + ".*")) list;
fold = op: nul: list: lib.fold (e: l: elemType.fold op l e) nul list;
docPath = path: elemType.docPath (path + ".*");
inherit (elemType) hasOptions;
};
attrsOf = elemType: mkOptionType {
name = "attribute set of ${elemType}s";
check = x: lib.traceValIfNot builtins.isAttrs x
&& fold (e: v: v && elemType.check e) true (lib.attrValues x);
merge = fold lib.mergeAttrs {};
iter = f: path: set: lib.mapAttrs (name: elemType.iter f (path + "." + name)) set;
fold = op: nul: set: fold (e: l: elemType.fold op l e) nul (lib.attrValues set);
docPath = path: elemType.docPath (path + ".<name>");
inherit (elemType) hasOptions;
};
uniq = elemType: mkOptionType {
inherit (elemType) name check iter fold docPath hasOptions;
merge = list:
if tail list == [] then
head list
else
throw "Multiple definitions. Only one is allowed for this option.";
};
nullOr = elemType: mkOptionType {
inherit (elemType) name merge docPath hasOptions;
check = x: builtins.isNull x || elemType.check x;
iter = f: path: v: if v == null then v else elemType.iter f path v;
fold = op: nul: v: if v == null then nul else elemType.fold op nul v;
};
optionSet = mkOptionType {
name = "option set";
check = x: lib.traceValIfNot builtins.isAttrs x;
hasOptions = true;
};
};
# !!! This function will be removed because this can be done with the
# multiple option declarations.
addDefaultOptionValues = defs: opts: opts //

121
pkgs/lib/types.nix Normal file
View file

@ -0,0 +1,121 @@
# Definitions related to run-time type checking. Used in particular
# to type-check NixOS configurations.
let lib = import ./default.nix; in
with import ./lists.nix;
with import ./attrsets.nix;
with import ./options.nix;
rec {
hasType = x: isAttrs x && x ? _type;
typeOf = x: if hasType x then x._type else "";
# name (name of the type)
# check (boolean function)
# merge (default merge function)
# iter (iterate on all elements contained in this type)
# fold (fold all elements contained in this type)
# hasOptions (boolean: whatever this option contains an option set)
# path (path contatenated to the option name contained contained in the option set)
isOptionType = attrs: typeOf attrs == "option-type";
mkOptionType =
{ name
, check ? (x: true)
, merge ? mergeDefaultOption
# Handle complex structure types.
, iter ? (f: path: v: f path v)
, fold ? (op: nul: v: op v nul)
, docPath ? lib.id
# If the type can contains option sets.
, hasOptions ? false
}:
{ _type = "option-type";
inherit name check merge iter fold docPath hasOptions;
};
types = {
inferred = mkOptionType {
name = "inferred type";
};
bool = mkOptionType {
name = "boolean";
check = lib.traceValIfNot builtins.isBool;
merge = fold lib.or false;
};
int = mkOptionType {
name = "integer";
check = lib.traceValIfNot builtins.isInt;
};
string = mkOptionType {
name = "string";
check = lib.traceValIfNot (x: builtins ? isString -> builtins.isString x);
merge = lib.concatStrings;
};
attrs = mkOptionType {
name = "attribute set";
check = lib.traceValIfNot builtins.isAttrs;
merge = fold lib.mergeAttrs {};
};
# derivation is a reserved keyword.
package = mkOptionType {
name = "derivation";
check = lib.traceValIfNot isDerivation;
};
list = elemType: mkOptionType {
name = "list of ${elemType.name}s";
check = value: lib.traceValIfNot isList value && all elemType.check value;
merge = concatLists;
iter = f: path: list: map (elemType.iter f (path + ".*")) list;
fold = op: nul: list: lib.fold (e: l: elemType.fold op l e) nul list;
docPath = path: elemType.docPath (path + ".*");
inherit (elemType) hasOptions;
};
attrsOf = elemType: mkOptionType {
name = "attribute set of ${elemType}s";
check = x: lib.traceValIfNot builtins.isAttrs x
&& fold (e: v: v && elemType.check e) true (lib.attrValues x);
merge = fold lib.mergeAttrs {};
iter = f: path: set: lib.mapAttrs (name: elemType.iter f (path + "." + name)) set;
fold = op: nul: set: fold (e: l: elemType.fold op l e) nul (lib.attrValues set);
docPath = path: elemType.docPath (path + ".<name>");
inherit (elemType) hasOptions;
};
uniq = elemType: mkOptionType {
inherit (elemType) name check iter fold docPath hasOptions;
merge = list:
if tail list == [] then
head list
else
throw "Multiple definitions. Only one is allowed for this option.";
};
nullOr = elemType: mkOptionType {
inherit (elemType) name merge docPath hasOptions;
check = x: builtins.isNull x || elemType.check x;
iter = f: path: v: if v == null then v else elemType.iter f path v;
fold = op: nul: v: if v == null then nul else elemType.fold op nul v;
};
optionSet = mkOptionType {
name = "option set";
check = x: lib.traceValIfNot builtins.isAttrs x;
hasOptions = true;
};
};
}