diff --git a/source/dyaml/node.d b/source/dyaml/node.d index bf8ccfe..f29a605 100644 --- a/source/dyaml/node.d +++ b/source/dyaml/node.d @@ -4,10 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -/** - * Node of a YAML document. Used to read YAML data once it's loaded, - * and to prepare data to emit. - */ +/// Node of a YAML document. Used to read YAML data once it's loaded, +/// and to prepare data to emit. module dyaml.node; @@ -30,16 +28,14 @@ import dyaml.style; import dyaml.tag; -///Exception thrown at node related errors. +/// Exception thrown at node related errors. class NodeException : YAMLException { package: - /* - * Construct a NodeException. - * - * Params: msg = Error message. - * start = Start position of the node. - */ + // Construct a NodeException. + // + // Params: msg = Error message. + // start = Start position of the node. this(string msg, Mark start, string file = __FILE__, int line = __LINE__) @safe { @@ -49,7 +45,7 @@ class NodeException : YAMLException private alias NodeException Error; -//Node kinds. +// Node kinds. package enum NodeID : ubyte { Scalar, @@ -57,40 +53,40 @@ package enum NodeID : ubyte Mapping } -///Null YAML type. Used in nodes with _null values. +/// Null YAML type. Used in nodes with _null values. struct YAMLNull { - ///Used for string conversion. + /// Used for string conversion. string toString() const pure @safe nothrow {return "null";} } -//Merge YAML type, used to support "tag:yaml.org,2002:merge". +// Merge YAML type, used to support "tag:yaml.org,2002:merge". package struct YAMLMerge{} -//Base class for YAMLContainer - used for user defined YAML types. +// Base class for YAMLContainer - used for user defined YAML types. package abstract class YAMLObject { public: - //Get type of the stored value. + // Get type of the stored value. @property TypeInfo type() const pure @safe nothrow {assert(false);} protected: - //Compare with another YAMLObject. + // Compare with another YAMLObject. int cmp(const YAMLObject rhs) const @system {assert(false);}; } -//Stores a user defined YAML data type. +// Stores a user defined YAML data type. package class YAMLContainer(T) if (!Node.allowed!T): YAMLObject { private: - //Stored value. + // Stored value. T value_; public: - //Get type of the stored value. + // Get type of the stored value. @property override TypeInfo type() const pure @safe nothrow {return typeid(T);} - //Get string representation of the container. + // Get string representation of the container. override string toString() @system { static if(!hasMember!(T, "toString")) @@ -104,44 +100,42 @@ package class YAMLContainer(T) if (!Node.allowed!T): YAMLObject } protected: - //Compare with another YAMLObject. + // Compare with another YAMLObject. override int cmp(const YAMLObject rhs) const @system { const typeCmp = type.opCmp(rhs.type); if(typeCmp != 0){return typeCmp;} - //Const-casting here as Object opCmp is not const. + // Const-casting here as Object opCmp is not const. T* v1 = cast(T*)&value_; T* v2 = cast(T*)&((cast(YAMLContainer)rhs).value_); return (*v1).opCmp(*v2); } private: - //Construct a YAMLContainer holding specified value. + // Construct a YAMLContainer holding specified value. this(T value) @trusted {value_ = value;} } -/** - * YAML node. - * - * This is a pseudo-dynamic type that can store any YAML value, including a - * sequence or mapping of nodes. You can get data from a Node directly or - * iterate over it if it's a collection. - */ +/// YAML node. +/// +/// This is a pseudo-dynamic type that can store any YAML value, including a +/// sequence or mapping of nodes. You can get data from a Node directly or +/// iterate over it if it's a collection. struct Node { public: - ///Key-value pair of YAML nodes, used in mappings. + /// Key-value pair of YAML nodes, used in mappings. struct Pair { public: - ///Key node. + /// Key node. Node key; - ///Value node. + /// Value node. Node value; public: - ///Construct a Pair from two values. Will be converted to Nodes if needed. + /// Construct a Pair from two values. Will be converted to Nodes if needed. this(K, V)(K key, V value) @safe { static if(is(Unqual!K == Node)){this.key = key;} @@ -150,7 +144,7 @@ struct Node else {this.value = Node(value);} } - ///Equality test with another Pair. + /// Equality test with another Pair. bool opEquals(const ref Pair rhs) const @safe { return cmp!(Yes.useTag)(rhs) == 0; @@ -170,12 +164,10 @@ struct Node } private: - /* - * Comparison with another Pair. - * - * useTag determines whether or not we consider node tags - * in the comparison. - */ + // Comparison with another Pair. + // + // useTag determines whether or not we consider node tags + // in the comparison. int cmp(Flag!"useTag" useTag)(ref const(Pair) rhs) const @safe { const keyCmp = key.cmp!useTag(rhs.key); @@ -195,11 +187,11 @@ struct Node package: - //YAML value type. + // YAML value type. alias Algebraic!(YAMLNull, YAMLMerge, bool, long, real, ubyte[], SysTime, string, Node.Pair[], Node[], YAMLObject) Value; - //Can Value hold this type without wrapping it in a YAMLObject? + // Can Value hold this type without wrapping it in a YAMLObject? template allowed(T) { enum allowed = isIntegral!T || @@ -209,59 +201,57 @@ struct Node } private: - ///Stored value. + /// Stored value. Value value_; - ///Start position of the node. + /// Start position of the node. Mark startMark_; package: - //Tag of the node. + // Tag of the node. Tag tag_; - //Node scalar style. Used to remember style this node was loaded with. + // Node scalar style. Used to remember style this node was loaded with. ScalarStyle scalarStyle = ScalarStyle.Invalid; - //Node collection style. Used to remember style this node was loaded with. + // Node collection style. Used to remember style this node was loaded with. CollectionStyle collectionStyle = CollectionStyle.Invalid; static assert(Value.sizeof <= 24, "Unexpected YAML value size"); static assert(Node.sizeof <= 48, "Unexpected YAML node size"); public: - /** - * Construct a Node from a value. - * - * Any type except for Node can be stored in a Node, but default YAML - * types (integers, floats, strings, timestamps, etc.) will be stored - * more efficiently. To create a node representing a null value, - * construct it from YAMLNull. - * - * - * Note that to emit any non-default types you store - * in a node, you need a Representer to represent them in YAML - - * otherwise emitting will fail. - * - * Params: value = Value to store in the node. - * tag = Overrides tag of the node when emitted, regardless - * of tag determined by Representer. Representer uses - * this to determine YAML data type when a D data type - * maps to multiple different YAML data types. Tag must - * be in full form, e.g. "tag:yaml.org,2002:int", not - * a shortcut, like "!!int". - */ + /// Construct a Node from a value. + /// + /// Any type except for Node can be stored in a Node, but default YAML + /// types (integers, floats, strings, timestamps, etc.) will be stored + /// more efficiently. To create a node representing a null value, + /// construct it from YAMLNull. + /// + /// + /// Note that to emit any non-default types you store + /// in a node, you need a Representer to represent them in YAML - + /// otherwise emitting will fail. + /// + /// Params: value = Value to store in the node. + /// tag = Overrides tag of the node when emitted, regardless + /// of tag determined by Representer. Representer uses + /// this to determine YAML data type when a D data type + /// maps to multiple different YAML data types. Tag must + /// be in full form, e.g. "tag:yaml.org,2002:int", not + /// a shortcut, like "!!int". this(T)(T value, const string tag = null) @trusted if (isSomeString!T || (!isArray!T && !isAssociativeArray!T)) { tag_ = Tag(tag); - //No copyconstruction. + // No copyconstruction. static assert(!is(Unqual!T == Node)); - //We can easily convert ints, floats, strings. + // We can easily convert ints, floats, strings. static if(isIntegral!T) {value_ = Value(cast(long) value);} else static if(isFloatingPoint!T){value_ = Value(cast(real) value);} else static if(isSomeString!T) {value_ = Value(to!string(value));} - //Other directly supported type. + // Other directly supported type. else static if(Value.allowed!T) {value_ = Value(value);} - //User defined type. + // User defined type. else {value_ = userValue(value);} } unittest @@ -280,43 +270,41 @@ struct Node } } - /** - * Construct a node from an _array. - * - * If _array is an _array of nodes or pairs, it is stored directly. - * Otherwise, every value in the array is converted to a node, and - * those nodes are stored. - * - * Params: array = Values to store in the node. - * tag = Overrides tag of the node when emitted, regardless - * of tag determined by Representer. Representer uses - * this to determine YAML data type when a D data type - * maps to multiple different YAML data types. - * This is used to differentiate between YAML sequences - * ("!!seq") and sets ("!!set"), which both are - * internally represented as an array_ of nodes. Tag - * must be in full form, e.g. "tag:yaml.org,2002:set", - * not a shortcut, like "!!set". - * - * Examples: - * -------------------- - * //Will be emitted as a sequence (default for arrays) - * auto seq = Node([1, 2, 3, 4, 5]); - * //Will be emitted as a set (overriden tag) - * auto set = Node([1, 2, 3, 4, 5], "tag:yaml.org,2002:set"); - * -------------------- - */ + /// Construct a node from an _array. + /// + /// If _array is an _array of nodes or pairs, it is stored directly. + /// Otherwise, every value in the array is converted to a node, and + /// those nodes are stored. + /// + /// Params: array = Values to store in the node. + /// tag = Overrides tag of the node when emitted, regardless + /// of tag determined by Representer. Representer uses + /// this to determine YAML data type when a D data type + /// maps to multiple different YAML data types. + /// This is used to differentiate between YAML sequences + /// ("!!seq") and sets ("!!set"), which both are + /// internally represented as an array_ of nodes. Tag + /// must be in full form, e.g. "tag:yaml.org,2002:set", + /// not a shortcut, like "!!set". + /// + /// Examples: + /// -------------------- + /// // Will be emitted as a sequence (default for arrays) + /// auto seq = Node([1, 2, 3, 4, 5]); + /// // Will be emitted as a set (overriden tag) + /// auto set = Node([1, 2, 3, 4, 5], "tag:yaml.org,2002:set"); + /// -------------------- this(T)(T[] array, const string tag = null) @safe if (!isSomeString!(T[])) { tag_ = Tag(tag); - //Construction from raw node or pair array. + // Construction from raw node or pair array. static if(is(Unqual!T == Node) || is(Unqual!T == Node.Pair)) { value_ = Value(array); } - //Need to handle byte buffers separately. + // Need to handle byte buffers separately. else static if(is(Unqual!T == byte) || is(Unqual!T == ubyte)) { value_ = Value(cast(ubyte[]) array); @@ -337,40 +325,38 @@ struct Node assert(opIndex(2).as!int == 3); } - //Will be emitted as a sequence (default for arrays) + // Will be emitted as a sequence (default for arrays) auto seq = Node([1, 2, 3, 4, 5]); - //Will be emitted as a set (overriden tag) + // Will be emitted as a set (overriden tag) auto set = Node([1, 2, 3, 4, 5], "tag:yaml.org,2002:set"); } - /** - * Construct a node from an associative _array. - * - * If keys and/or values of _array are nodes, they stored directly. - * Otherwise they are converted to nodes and then stored. - * - * Params: array = Values to store in the node. - * tag = Overrides tag of the node when emitted, regardless - * of tag determined by Representer. Representer uses - * this to determine YAML data type when a D data type - * maps to multiple different YAML data types. - * This is used to differentiate between YAML unordered - * mappings ("!!map"), ordered mappings ("!!omap"), and - * pairs ("!!pairs") which are all internally - * represented as an _array of node pairs. Tag must be - * in full form, e.g. "tag:yaml.org,2002:omap", not a - * shortcut, like "!!omap". - * - * Examples: - * -------------------- - * //Will be emitted as an unordered mapping (default for mappings) - * auto map = Node([1 : "a", 2 : "b"]); - * //Will be emitted as an ordered map (overriden tag) - * auto omap = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:omap"); - * //Will be emitted as pairs (overriden tag) - * auto pairs = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:pairs"); - * -------------------- - */ + /// Construct a node from an associative _array. + /// + /// If keys and/or values of _array are nodes, they stored directly. + /// Otherwise they are converted to nodes and then stored. + /// + /// Params: array = Values to store in the node. + /// tag = Overrides tag of the node when emitted, regardless + /// of tag determined by Representer. Representer uses + /// this to determine YAML data type when a D data type + /// maps to multiple different YAML data types. + /// This is used to differentiate between YAML unordered + /// mappings ("!!map"), ordered mappings ("!!omap"), and + /// pairs ("!!pairs") which are all internally + /// represented as an _array of node pairs. Tag must be + /// in full form, e.g. "tag:yaml.org,2002:omap", not a + /// shortcut, like "!!omap". + /// + /// Examples: + /// -------------------- + /// // Will be emitted as an unordered mapping (default for mappings) + /// auto map = Node([1 : "a", 2 : "b"]); + /// // Will be emitted as an ordered map (overriden tag) + /// auto omap = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:omap"); + /// // Will be emitted as pairs (overriden tag) + /// auto pairs = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:pairs"); + /// -------------------- this(K, V)(V[K] array, const string tag = null) @safe { tag_ = Tag(tag); @@ -391,51 +377,49 @@ struct Node assert(opIndex("2").as!int == 2); } - //Will be emitted as an unordered mapping (default for mappings) + // Will be emitted as an unordered mapping (default for mappings) auto map = Node([1 : "a", 2 : "b"]); - //Will be emitted as an ordered map (overriden tag) + // Will be emitted as an ordered map (overriden tag) auto omap = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:omap"); - //Will be emitted as pairs (overriden tag) + // Will be emitted as pairs (overriden tag) auto pairs = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:pairs"); } - /** - * Construct a node from arrays of _keys and _values. - * - * Constructs a mapping node with key-value pairs from - * _keys and _values, keeping their order. Useful when order - * is important (ordered maps, pairs). - * - * - * keys and values must have equal length. - * - * - * If _keys and/or _values are nodes, they are stored directly/ - * Otherwise they are converted to nodes and then stored. - * - * Params: keys = Keys of the mapping, from first to last pair. - * values = Values of the mapping, from first to last pair. - * tag = Overrides tag of the node when emitted, regardless - * of tag determined by Representer. Representer uses - * this to determine YAML data type when a D data type - * maps to multiple different YAML data types. - * This is used to differentiate between YAML unordered - * mappings ("!!map"), ordered mappings ("!!omap"), and - * pairs ("!!pairs") which are all internally - * represented as an array of node pairs. Tag must be - * in full form, e.g. "tag:yaml.org,2002:omap", not a - * shortcut, like "!!omap". - * - * Examples: - * -------------------- - * //Will be emitted as an unordered mapping (default for mappings) - * auto map = Node([1, 2], ["a", "b"]); - * //Will be emitted as an ordered map (overriden tag) - * auto omap = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:omap"); - * //Will be emitted as pairs (overriden tag) - * auto pairs = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:pairs"); - * -------------------- - */ + /// Construct a node from arrays of _keys and _values. + /// + /// Constructs a mapping node with key-value pairs from + /// _keys and _values, keeping their order. Useful when order + /// is important (ordered maps, pairs). + /// + /// + /// keys and values must have equal length. + /// + /// + /// If _keys and/or _values are nodes, they are stored directly/ + /// Otherwise they are converted to nodes and then stored. + /// + /// Params: keys = Keys of the mapping, from first to last pair. + /// values = Values of the mapping, from first to last pair. + /// tag = Overrides tag of the node when emitted, regardless + /// of tag determined by Representer. Representer uses + /// this to determine YAML data type when a D data type + /// maps to multiple different YAML data types. + /// This is used to differentiate between YAML unordered + /// mappings ("!!map"), ordered mappings ("!!omap"), and + /// pairs ("!!pairs") which are all internally + /// represented as an array of node pairs. Tag must be + /// in full form, e.g. "tag:yaml.org,2002:omap", not a + /// shortcut, like "!!omap". + /// + /// Examples: + /// -------------------- + /// // Will be emitted as an unordered mapping (default for mappings) + /// auto map = Node([1, 2], ["a", "b"]); + /// // Will be emitted as an ordered map (overriden tag) + /// auto omap = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:omap"); + /// // Will be emitted as pairs (overriden tag) + /// auto pairs = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:pairs"); + /// -------------------- this(K, V)(K[] keys, V[] values, const string tag = null) @safe if(!(isSomeString!(K[]) || isSomeString!(V[]))) in @@ -461,77 +445,75 @@ struct Node assert(opIndex("2").as!int == 2); } - //Will be emitted as an unordered mapping (default for mappings) + // Will be emitted as an unordered mapping (default for mappings) auto map = Node([1, 2], ["a", "b"]); - //Will be emitted as an ordered map (overriden tag) + // Will be emitted as an ordered map (overriden tag) auto omap = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:omap"); - //Will be emitted as pairs (overriden tag) + // Will be emitted as pairs (overriden tag) auto pairs = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:pairs"); } - ///Is this node valid (initialized)? + /// Is this node valid (initialized)? @property bool isValid() const @safe pure nothrow { return value_.hasValue; } - ///Is this node a scalar value? + /// Is this node a scalar value? @property bool isScalar() const @safe nothrow { return !(isMapping || isSequence); } - ///Is this node a sequence? + /// Is this node a sequence? @property bool isSequence() const @safe nothrow { return isType!(Node[]); } - ///Is this node a mapping? + /// Is this node a mapping? @property bool isMapping() const @safe nothrow { return isType!(Pair[]); } - ///Is this node a user defined type? + /// Is this node a user defined type? @property bool isUserType() const @safe nothrow { return isType!YAMLObject; } - ///Is this node null? + /// Is this node null? @property bool isNull() const @safe nothrow { return isType!YAMLNull; } - ///Return tag of the node. + /// Return tag of the node. @property string tag() const @safe nothrow {return tag_.get;} - /** - * Equality test. - * - * If T is Node, recursively compare all subnodes. - * This might be quite expensive if testing entire documents. - * - * If T is not Node, get a value if type T from the node and test - * equality with that. - * - * To test equality with a null YAML value, use YAMLNull. - * - * Examples: - * -------------------- - * auto node = Node(42); - * - * assert(node == 42); - * assert(node != "42"); - * assert(node != "43"); - * -------------------- - * - * Params: rhs = Variable to test equality with. - * - * Returns: true if equal, false otherwise. - */ + /// Equality test. + /// + /// If T is Node, recursively compare all subnodes. + /// This might be quite expensive if testing entire documents. + /// + /// If T is not Node, get a value if type T from the node and test + /// equality with that. + /// + /// To test equality with a null YAML value, use YAMLNull. + /// + /// Examples: + /// -------------------- + /// auto node = Node(42); + /// + /// assert(node == 42); + /// assert(node != "42"); + /// assert(node != "43"); + /// -------------------- + /// + /// Params: rhs = Variable to test equality with. + /// + /// Returns: true if equal, false otherwise. bool opEquals(T)(const auto ref T rhs) const @safe { return equals!(Yes.useTag)(rhs); @@ -548,59 +530,57 @@ struct Node assert(node2 == YAMLNull()); } - ///Shortcut for get(). + /// Shortcut for get(). alias get as; - /** - * Get the value of the node as specified type. - * - * If the specifed type does not match type in the node, - * conversion is attempted. The stringConversion template - * parameter can be used to disable conversion from non-string - * types to strings. - * - * Numeric values are range checked, throwing if out of range of - * requested type. - * - * Timestamps are stored as std.datetime.SysTime. - * Binary values are decoded and stored as ubyte[]. - * - * To get a null value, use get!YAMLNull . This is to - * prevent getting null values for types such as strings or classes. - * - * $(BR)$(B Mapping default values:) - * - * $(PBR - * The '=' key can be used to denote the default value of a mapping. - * This can be used when a node is scalar in early versions of a program, - * but is replaced by a mapping later. Even if the node is a mapping, the - * get method can be used as if it was a scalar if it has a default value. - * This way, new YAML files where the node is a mapping can still be read - * by old versions of the program, which expect the node to be a scalar. - * ) - * - * Examples: - * - * Automatic type conversion: - * -------------------- - * auto node = Node(42); - * - * assert(node.as!int == 42); - * assert(node.as!string == "42"); - * assert(node.as!double == 42.0); - * -------------------- - * - * Returns: Value of the node as specified type. - * - * Throws: NodeException if unable to convert to specified type, or if - * the value is out of range of requested type. - */ + /// Get the value of the node as specified type. + /// + /// If the specifed type does not match type in the node, + /// conversion is attempted. The stringConversion template + /// parameter can be used to disable conversion from non-string + /// types to strings. + /// + /// Numeric values are range checked, throwing if out of range of + /// requested type. + /// + /// Timestamps are stored as std.datetime.SysTime. + /// Binary values are decoded and stored as ubyte[]. + /// + /// To get a null value, use get!YAMLNull . This is to + /// prevent getting null values for types such as strings or classes. + /// + /// $(BR)$(B Mapping default values:) + /// + /// $(PBR + /// The '=' key can be used to denote the default value of a mapping. + /// This can be used when a node is scalar in early versions of a program, + /// but is replaced by a mapping later. Even if the node is a mapping, the + /// get method can be used as if it was a scalar if it has a default value. + /// This way, new YAML files where the node is a mapping can still be read + /// by old versions of the program, which expect the node to be a scalar. + /// ) + /// + /// Examples: + /// + /// Automatic type conversion: + /// -------------------- + /// auto node = Node(42); + /// + /// assert(node.as!int == 42); + /// assert(node.as!string == "42"); + /// assert(node.as!double == 42.0); + /// -------------------- + /// + /// Returns: Value of the node as specified type. + /// + /// Throws: NodeException if unable to convert to specified type, or if + /// the value is out of range of requested type. @property T get(T, Flag!"stringConversion" stringConversion = Yes.stringConversion)() @trusted if(!is(T == const)) { if(isType!T){return value_.get!T;} - ///Must go before others, as even string/int/etc could be stored in a YAMLObject. + /// Must go before others, as even string/int/etc could be stored in a YAMLObject. static if(!allowed!T) if(isUserType) { auto object = as!YAMLObject; @@ -612,8 +592,8 @@ struct Node ". Expected: " ~ typeid(T).toString, startMark_); } - //If we're getting from a mapping and we're not getting Node.Pair[], - //we're getting the default value. + // If we're getting from a mapping and we're not getting Node.Pair[], + // we're getting the default value. if(isMapping){return this["="].as!(T, stringConversion);} static if(isSomeString!T) @@ -626,7 +606,7 @@ struct Node } else { - //Try to convert to string. + // Try to convert to string. try { return value_.coerce!T(); @@ -641,7 +621,7 @@ struct Node { static if(isFloatingPoint!T) { - ///Can convert int to float. + /// Can convert int to float. if(isInt()) {return to!T(value_.get!(const long));} else if(isFloat()){return to!T(value_.get!(const real));} } @@ -664,13 +644,13 @@ struct Node Node(YAMLNull()).get!YAMLNull; } - ///Ditto. + /// Ditto. @property T get(T, Flag!"stringConversion" stringConversion = Yes.stringConversion)() const @trusted if(is(T == const)) { if(isType!(Unqual!T)){return value_.get!T;} - ///Must go before others, as even string/int/etc could be stored in a YAMLObject. + /// Must go before others, as even string/int/etc could be stored in a YAMLObject. static if(!allowed!(Unqual!T)) if(isUserType) { auto object = as!(const YAMLObject); @@ -682,8 +662,8 @@ struct Node ". Expected: " ~ typeid(T).toString, startMark_); } - //If we're getting from a mapping and we're not getting Node.Pair[], - //we're getting the default value. + // If we're getting from a mapping and we're not getting Node.Pair[], + // we're getting the default value. if(isMapping){return indexConst("=").as!( T, stringConversion);} static if(isSomeString!T) @@ -696,10 +676,10 @@ struct Node } else { - //Try to convert to string. + // Try to convert to string. try { - //NOTE: We are casting away const here + // NOTE: We are casting away const here return (cast(Value)value_).coerce!T(); } catch(VariantException e) @@ -712,7 +692,7 @@ struct Node { static if(isFloatingPoint!T) { - ///Can convert int to float. + /// Can convert int to float. if(isInt()) {return to!T(value_.get!(const long));} else if(isFloat()){return to!T(value_.get!(const real));} } @@ -729,15 +709,13 @@ struct Node } } - /** - * If this is a collection, return its _length. - * - * Otherwise, throw NodeException. - * - * Returns: Number of elements in a sequence or key-value pairs in a mapping. - * - * Throws: NodeException if this is not a sequence nor a mapping. - */ + /// If this is a collection, return its _length. + /// + /// Otherwise, throw NodeException. + /// + /// Returns: Number of elements in a sequence or key-value pairs in a mapping. + /// + /// Throws: NodeException if this is not a sequence nor a mapping. @property size_t length() const @safe { if(isSequence) {return value_.get!(const Node[]).length;} @@ -746,25 +724,24 @@ struct Node startMark_); } - /** - * Get the element at specified index. - * - * If the node is a sequence, index must be integral. - * - * - * If the node is a mapping, return the value corresponding to the first - * key equal to index. - * - * To get element at a null index, use YAMLNull for index. - * - * Params: index = Index to use. - * - * Returns: Value corresponding to the index. - * - * Throws: NodeException if the index could not be found, - * non-integral index is used with a sequence or the node is - * not a collection. - */ + /// Get the element at specified index. + /// + /// If the node is a sequence, index must be integral. + /// + /// + /// If the node is a mapping, return the value corresponding to the first + /// key equal to index. containsKey() can be used to determine if a mapping + /// has a specific key. + /// + /// To get element at a null index, use YAMLNull for index. + /// + /// Params: index = Index to use. + /// + /// Returns: Value corresponding to the index. + /// + /// Throws: NodeException if the index could not be found, + /// non-integral index is used with a sequence or the node is + /// not a collection. ref Node opIndex(T)(T index) @trusted { if(isSequence) @@ -789,10 +766,10 @@ struct Node } throw new Error("Trying to index a " ~ nodeTypeString ~ " node", startMark_); } + /// unittest { writeln("D:YAML Node opIndex unittest"); - alias Node.Value Value; alias Node.Pair Pair; Node n1 = Node(cast(long)11); @@ -824,46 +801,42 @@ struct Node assertThrown!NodeException(nmap[14]); } - /** - * Determine if a collection contains specified value. - * - * If the node is a sequence, check if it contains the specified value. - * If it's a mapping, check if it has a value that matches specified value. - * - * To check for a null value, use YAMLNull for rhs. - * - * Params: rhs = Item to look for. - * - * Returns: true if rhs was found, false otherwise. - * - * Throws: NodeException if the node is not a collection. - */ + /// Determine if a collection contains specified value. + /// + /// If the node is a sequence, check if it contains the specified value. + /// If it's a mapping, check if it has a value that matches specified value. + /// + /// To check for a null value, use YAMLNull for rhs. + /// + /// Params: rhs = Item to look for. + /// + /// Returns: true if rhs was found, false otherwise. + /// + /// Throws: NodeException if the node is not a collection. bool contains(T)(T rhs) const @safe { return contains_!(T, No.key, "contains")(rhs); } - /** - * Determine if a collection contains specified key. - * - * If the node is a mapping, check if it has a key - * that matches specified key. - * - * To check for a null key, use YAMLNull for rhs. - * - * Params: rhs = Item to look for. - * - * Returns: true if rhs was found, false otherwise. - * - * Throws: NodeException if the node is not a mapping. - */ + /// Determine if a collection contains specified key. + /// + /// If the node is a mapping, check if it has a key + /// that matches specified key. + /// + /// To check for a null key, use YAMLNull for rhs. + /// + /// Params: rhs = Item to look for. + /// + /// Returns: true if rhs was found, false otherwise. + /// + /// Throws: NodeException if the node is not a mapping. bool containsKey(T)(T rhs) const @safe { return contains_!(T, Yes.key, "containsKey")(rhs); } - //Unittest for contains() and containsKey(). + // Unittest for contains() and containsKey(). unittest { writeln("D:YAML Node contains/containsKey unittest"); @@ -906,7 +879,7 @@ struct Node assert(!map2.containsKey("1")); assert(map2.containsKey(1)); - //scalar + // scalar assertThrown!NodeException(Node(1).contains(4)); assertThrown!NodeException(Node(1).containsKey(4)); @@ -942,33 +915,31 @@ struct Node "Node.opAssign() doesn't produce an equivalent copy"); } - /** - * Set element at specified index in a collection. - * - * This method can only be called on collection nodes. - * - * If the node is a sequence, index must be integral. - * - * If the node is a mapping, sets the _value corresponding to the first - * key matching index (including conversion, so e.g. "42" matches 42). - * - * If the node is a mapping and no key matches index, a new key-value - * pair is added to the mapping. In sequences the index must be in - * range. This ensures behavior siilar to D arrays and associative - * arrays. - * - * To set element at a null index, use YAMLNull for index. - * - * Params: index = Index of the value to set. - * - * Throws: NodeException if the node is not a collection, index is out - * of range or if a non-integral index is used on a sequence node. - */ + /// Set element at specified index in a collection. + /// + /// This method can only be called on collection nodes. + /// + /// If the node is a sequence, index must be integral. + /// + /// If the node is a mapping, sets the _value corresponding to the first + /// key matching index (including conversion, so e.g. "42" matches 42). + /// + /// If the node is a mapping and no key matches index, a new key-value + /// pair is added to the mapping. In sequences the index must be in + /// range. This ensures behavior siilar to D arrays and associative + /// arrays. + /// + /// To set element at a null index, use YAMLNull for index. + /// + /// Params: index = Index of the value to set. + /// + /// Throws: NodeException if the node is not a collection, index is out + /// of range or if a non-integral index is used on a sequence node. void opIndexAssign(K, V)(V value, K index) @safe { if(isSequence()) { - //This ensures K is integral. + // This ensures K is integral. checkSequenceIndex(index); static if(isIntegral!K) { @@ -1028,15 +999,13 @@ struct Node } } - /** - * Foreach over a sequence, getting each element as T. - * - * If T is Node, simply iterate over the nodes in the sequence. - * Otherwise, convert each node to T during iteration. - * - * Throws: NodeException if the node is not a sequence or an - * element could not be converted to specified type. - */ + /// Foreach over a sequence, getting each element as T. + /// + /// If T is Node, simply iterate over the nodes in the sequence. + /// Otherwise, convert each node to T during iteration. + /// + /// Throws: NodeException if the node is not a sequence or an + /// element could not be converted to specified type. int opApply(T)(int delegate(ref T) dg) @trusted { enforce(isSequence, @@ -1085,15 +1054,13 @@ struct Node assert(array2 == [11, 12, 13, 14]); } - /** - * Foreach over a mapping, getting each key/value as K/V. - * - * If the K and/or V is Node, simply iterate over the nodes in the mapping. - * Otherwise, convert each key/value to T during iteration. - * - * Throws: NodeException if the node is not a mapping or an - * element could not be converted to specified type. - */ + /// Foreach over a mapping, getting each key/value as K/V. + /// + /// If the K and/or V is Node, simply iterate over the nodes in the mapping. + /// Otherwise, convert each key/value to T during iteration. + /// + /// Throws: NodeException if the node is not a mapping or an + /// element could not be converted to specified type. int opApply(K, V)(int delegate(ref K, ref V) dg) @trusted { enforce(isMapping, @@ -1179,21 +1146,19 @@ struct Node } } - /** - * Add an element to a sequence. - * - * This method can only be called on sequence nodes. - * - * If value is a node, it is copied to the sequence directly. Otherwise - * value is converted to a node and then stored in the sequence. - * - * $(P When emitting, all values in the sequence will be emitted. When - * using the !!set tag, the user needs to ensure that all elements in - * the sequence are unique, otherwise $(B invalid) YAML code will be - * emitted.) - * - * Params: value = Value to _add to the sequence. - */ + /// Add an element to a sequence. + /// + /// This method can only be called on sequence nodes. + /// + /// If value is a node, it is copied to the sequence directly. Otherwise + /// value is converted to a node and then stored in the sequence. + /// + /// $(P When emitting, all values in the sequence will be emitted. When + /// using the !!set tag, the user needs to ensure that all elements in + /// the sequence are unique, otherwise $(B invalid) YAML code will be + /// emitted.) + /// + /// Params: value = Value to _add to the sequence. void add(T)(T value) @safe { enforce(isSequence(), @@ -1215,22 +1180,20 @@ struct Node } } - /** - * Add a key-value pair to a mapping. - * - * This method can only be called on mapping nodes. - * - * If key and/or value is a node, it is copied to the mapping directly. - * Otherwise it is converted to a node and then stored in the mapping. - * - * $(P It is possible for the same key to be present more than once in a - * mapping. When emitting, all key-value pairs will be emitted. - * This is useful with the "!!pairs" tag, but will result in - * $(B invalid) YAML with "!!map" and "!!omap" tags.) - * - * Params: key = Key to _add. - * value = Value to _add. - */ + /// Add a key-value pair to a mapping. + /// + /// This method can only be called on mapping nodes. + /// + /// If key and/or value is a node, it is copied to the mapping directly. + /// Otherwise it is converted to a node and then stored in the mapping. + /// + /// $(P It is possible for the same key to be present more than once in a + /// mapping. When emitting, all key-value pairs will be emitted. + /// This is useful with the "!!pairs" tag, but will result in + /// $(B invalid) YAML with "!!map" and "!!omap" tags.) + /// + /// Params: key = Key to _add. + /// value = Value to _add. void add(K, V)(K key, V value) @safe { enforce(isMapping(), @@ -1252,21 +1215,19 @@ struct Node } } - /** - * Determine whether a key is in a mapping, and access its value. - * - * This method can only be called on mapping nodes. - * - * Params: key = Key to search for. - * - * Returns: A pointer to the value (as a Node) corresponding to key, - * or null if not found. - * - * Note: Any modification to the node can invalidate the returned - * pointer. - * - * See_Also: contains - */ + /// Determine whether a key is in a mapping, and access its value. + /// + /// This method can only be called on mapping nodes. + /// + /// Params: key = Key to search for. + /// + /// Returns: A pointer to the value (as a Node) corresponding to key, + /// or null if not found. + /// + /// Note: Any modification to the node can invalidate the returned + /// pointer. + /// + /// See_Also: contains Node* opBinaryRight(string op, K)(K key) @trusted if (op == "in") { enforce(isMapping, new Error("Trying to use 'in' on a " ~ @@ -1295,19 +1256,17 @@ struct Node assert(mapping["foo"] == Node("newfoo")); } - /** - * Remove first (if any) occurence of a value in a collection. - * - * This method can only be called on collection nodes. - * - * If the node is a sequence, the first node matching value is removed. - * If the node is a mapping, the first key-value pair where _value - * matches specified value is removed. - * - * Params: rhs = Value to _remove. - * - * Throws: NodeException if the node is not a collection. - */ + /// Remove first (if any) occurence of a value in a collection. + /// + /// This method can only be called on collection nodes. + /// + /// If the node is a sequence, the first node matching value is removed. + /// If the node is a mapping, the first key-value pair where _value + /// matches specified value is removed. + /// + /// Params: rhs = Value to _remove. + /// + /// Throws: NodeException if the node is not a collection. void remove(T)(T rhs) @trusted { remove_!(T, No.key, "remove")(rhs); @@ -1338,25 +1297,23 @@ struct Node } } - /** - * Remove element at the specified index of a collection. - * - * This method can only be called on collection nodes. - * - * If the node is a sequence, index must be integral. - * - * If the node is a mapping, remove the first key-value pair where - * key matches index. - * - * If the node is a mapping and no key matches index, nothing is removed - * and no exception is thrown. This ensures behavior siilar to D arrays - * and associative arrays. - * - * Params: index = Index to remove at. - * - * Throws: NodeException if the node is not a collection, index is out - * of range or if a non-integral index is used on a sequence node. - */ + /// Remove element at the specified index of a collection. + /// + /// This method can only be called on collection nodes. + /// + /// If the node is a sequence, index must be integral. + /// + /// If the node is a mapping, remove the first key-value pair where + /// key matches index. + /// + /// If the node is a mapping and no key matches index, nothing is removed + /// and no exception is thrown. This ensures behavior siilar to D arrays + /// and associative arrays. + /// + /// Params: index = Index to remove at. + /// + /// Throws: NodeException if the node is not a collection, index is out + /// of range or if a non-integral index is used on a sequence node. void removeAt(T)(T index) @trusted { remove_!(T, Yes.key, "removeAt")(index); @@ -1373,7 +1330,7 @@ struct Node } with(Node(["1", "2", "3"], [4, 5, 6])) { - //no integer 2 key, so don't remove anything + // no integer 2 key, so don't remove anything removeAt(2); assert(length == 3); removeAt("2"); @@ -1385,13 +1342,13 @@ struct Node } } - ///Compare with another _node. + /// Compare with another _node. int opCmp(ref const Node node) const @safe { return cmp!(Yes.useTag)(node); } - //Compute hash of the node. + // Compute hash of the node. hash_t toHash() const nothrow @safe { // Hack to allow const nothrow @safe. @@ -1399,11 +1356,11 @@ struct Node hash_t unsafeHash() nothrow @trusted { const tagHash = tag_.isNull ? 0 : tag_.toHash(); - //Variant toHash is not nothrow at the moment, so we need to catch - //an exception that is never thrown. + // Variant toHash is not nothrow at the moment, so we need to catch + // an exception that is never thrown. try { - //Variant toHash is not const at the moment, so we need to const-cast. + // Variant toHash is not const at the moment, so we need to const-cast. return tagHash + (cast(Value)value_).toHash(); } catch(Exception e) @@ -1415,17 +1372,15 @@ struct Node } package: - /* - * Construct a node from raw data. - * - * Params: value = Value of the node. - * startMark = Start position of the node in file. - * tag = Tag of the node. - * scalarStyle = Scalar style of the node. - * collectionStyle = Collection style of the node. - * - * Returns: Constructed node. - */ + // Construct a node from raw data. + // + // Params: value = Value of the node. + // startMark = Start position of the node in file. + // tag = Tag of the node. + // scalarStyle = Scalar style of the node. + // collectionStyle = Collection style of the node. + // + // Returns: Constructed node. static Node rawNode(Value value, const Mark startMark, const Tag tag, const ScalarStyle scalarStyle, const CollectionStyle collectionStyle) @safe @@ -1440,13 +1395,13 @@ struct Node return node; } - //Construct Node.Value from user defined type. + // Construct Node.Value from user defined type. static Value userValue(T)(T value) @trusted nothrow { return Value(cast(YAMLObject)new YAMLContainer!T(value)); } - //Construct Node.Value from a type it can store directly (after casting if needed) + // Construct Node.Value from a type it can store directly (after casting if needed) static Value value(T)(T value) @safe nothrow if(allowed!T) { static if(Value.allowed!T) @@ -1468,11 +1423,9 @@ struct Node else static assert(false, "Unknown value type. Is value() in sync with allowed()?"); } - /* - * Equality test with any value. - * - * useTag determines whether or not to consider tags in node-node comparisons. - */ + // Equality test with any value. + // + // useTag determines whether or not to consider tags in node-node comparisons. bool equals(Flag!"useTag" useTag, T)(ref T rhs) const @safe { static if(is(Unqual!T == Node)) @@ -1484,7 +1437,7 @@ struct Node try { auto stored = get!(const(Unqual!T), No.stringConversion); - //Need to handle NaNs separately. + // Need to handle NaNs separately. static if(isFloatingPoint!T) { return rhs == stored || (isNaN(rhs) && isNaN(stored)); @@ -1498,16 +1451,14 @@ struct Node } } - /* - * Comparison with another node. - * - * Used for ordering in mappings and for opEquals. - * - * useTag determines whether or not to consider tags in the comparison. - */ + // Comparison with another node. + // + // Used for ordering in mappings and for opEquals. + // + // useTag determines whether or not to consider tags in the comparison. int cmp(Flag!"useTag" useTag)(const ref Node rhs) const @trusted { - //Compare tags - if equal or both null, we need to compare further. + // Compare tags - if equal or both null, we need to compare further. static if(useTag) { const tagCmp = tag_.isNull ? rhs.tag_.isNull ? 0 : -1 @@ -1522,7 +1473,7 @@ struct Node 0; } - //Compare validity: if both valid, we have to compare further. + // Compare validity: if both valid, we have to compare further. const v1 = isValid; const v2 = rhs.isValid; if(!v1){return v2 ? -1 : 0;} @@ -1540,7 +1491,7 @@ struct Node { return cmp(c1.length, c2.length); } - //Equal lengths, compare items. + // Equal lengths, compare items. foreach(i; 0 .. c1.length) { const itemCmp = c1[i].cmp!useTag(c2[i]); @@ -1577,8 +1528,8 @@ struct Node { return 0; } - //Floats need special handling for NaNs . - //We consider NaN to be lower than any float. + // Floats need special handling for NaNs . + // We consider NaN to be lower than any float. if(isFloat) { const r1 = value_.get!(const real); @@ -1591,7 +1542,7 @@ struct Node { return 1; } - //Fuzzy equality. + // Fuzzy equality. if(r1 <= r2 + real.epsilon && r1 >= r2 - real.epsilon) { return 0; @@ -1611,13 +1562,11 @@ struct Node assert(false, "Unknown type of node for comparison : " ~ type.toString()); } - /* - * Get a string representation of the node tree. Used for debugging. - * - * Params: level = Level of the node in the tree. - * - * Returns: String representing the node tree. - */ + // Get a string representation of the node tree. Used for debugging. + // + // Params: level = Level of the node in the tree. + // + // Returns: String representing the node tree. @property string debugString(uint level = 0) @trusted { string indent; @@ -1653,49 +1602,47 @@ struct Node assert(false); } - //Get type of the node value (YAMLObject for user types). + // Get type of the node value (YAMLObject for user types). @property TypeInfo type() const @trusted nothrow { alias TypeInfo delegate() const nothrow nothrowType; return (cast(nothrowType)&value_.type)(); } - /* - * Determine if the value stored by the node is of specified type. - * - * This only works for default YAML types, not for user defined types. - */ + // Determine if the value stored by the node is of specified type. + // + // This only works for default YAML types, not for user defined types. @property bool isType(T)() const @safe nothrow { return this.type is typeid(Unqual!T); } private: - //Is the value a bool? + // Is the value a bool? alias isType!bool isBool; - //Is the value a raw binary buffer? + // Is the value a raw binary buffer? alias isType!(ubyte[]) isBinary; - //Is the value an integer? + // Is the value an integer? alias isType!long isInt; - //Is the value a floating point number? + // Is the value a floating point number? alias isType!real isFloat; - //Is the value a string? + // Is the value a string? alias isType!string isString; - //Is the value a timestamp? + // Is the value a timestamp? alias isType!SysTime isTime; - //Does given node have the same type as this node? + // Does given node have the same type as this node? bool hasEqualType(const ref Node node) const @safe { return this.type is node.type; } - //Return a string describing node type (sequence, mapping or scalar) + // Return a string describing node type (sequence, mapping or scalar) @property string nodeTypeString() const @safe nothrow { assert(isScalar || isSequence || isMapping, "Unknown node type"); @@ -1704,19 +1651,19 @@ struct Node isMapping ? "mapping" : ""; } - //Determine if the value can be converted to specified type. + // Determine if the value can be converted to specified type. @property bool convertsTo(T)() const @safe nothrow { if(isType!T){return true;} - //Every type allowed in Value should be convertible to string. + // Every type allowed in Value should be convertible to string. static if(isSomeString!T) {return true;} else static if(isFloatingPoint!T){return isInt() || isFloat();} else static if(isIntegral!T) {return isInt();} else {return false;} } - //Implementation of contains() and containsKey(). + // Implementation of contains() and containsKey(). bool contains_(T, Flag!"key" key, string func)(T rhs) const @safe { static if(!key) if(isSequence) @@ -1737,7 +1684,7 @@ struct Node startMark_); } - //Implementation of remove() and removeAt() + // Implementation of remove() and removeAt() void remove_(T, Flag!"key" key, string func)(T rhs) @system { enforce(isSequence || isMapping, @@ -1768,7 +1715,7 @@ struct Node const index = select!key(rhs, getIndex(this, rhs)); - //This throws if the index is not integral. + // This throws if the index is not integral. checkSequenceIndex(index); static if(isIntegral!(typeof(index))){removeElem!Node(this, index);} @@ -1781,7 +1728,7 @@ struct Node } } - //Get index of pair with key (or value, if key is false) matching index. + // Get index of pair with key (or value, if key is false) matching index. sizediff_t findPair(T, Flag!"key" key = Yes.key)(const ref T index) const @safe { const pairs = value_.get!(const Pair[])(); @@ -1804,7 +1751,7 @@ struct Node return -1; } - //Check if index is integral and in range. + // Check if index is integral and in range. void checkSequenceIndex(T)(T index) const @trusted { assert(isSequence, @@ -1822,7 +1769,7 @@ struct Node } } - //Const version of opIndex. + // Const version of opIndex. ref const(Node) indexConst(T)(T index) const @safe { if(isSequence) @@ -1850,15 +1797,13 @@ struct Node } package: -/* - * Merge a pair into an array of pairs based on merge rules in the YAML spec. - * - * The new pair will only be added if there is not already a pair - * with the same key. - * - * Params: pairs = Appender managing the array of pairs to merge into. - * toMerge = Pair to merge. - */ +// Merge a pair into an array of pairs based on merge rules in the YAML spec. +// +// The new pair will only be added if there is not already a pair +// with the same key. +// +// Params: pairs = Appender managing the array of pairs to merge into. +// toMerge = Pair to merge. void merge(ref Appender!(Node.Pair[], Node.Pair) pairs, ref Node.Pair toMerge) @trusted { foreach(ref pair; pairs.data) @@ -1868,15 +1813,13 @@ void merge(ref Appender!(Node.Pair[], Node.Pair) pairs, ref Node.Pair toMerge) @ pairs.put(toMerge); } -/* - * Merge pairs into an array of pairs based on merge rules in the YAML spec. - * - * Any new pair will only be added if there is not already a pair - * with the same key. - * - * Params: pairs = Appender managing the array of pairs to merge into. - * toMerge = Pairs to merge. - */ +// Merge pairs into an array of pairs based on merge rules in the YAML spec. +// +// Any new pair will only be added if there is not already a pair +// with the same key. +// +// Params: pairs = Appender managing the array of pairs to merge into. +// toMerge = Pairs to merge. void merge(ref Appender!(Node.Pair[], Node.Pair) pairs, Node.Pair[] toMerge) @trusted { bool eq(ref Node.Pair a, ref Node.Pair b){return a.key == b.key;}