diff options
Diffstat (limited to 'src/ext_depends/D-YAML/source/dyaml/node.d')
-rw-r--r-- | src/ext_depends/D-YAML/source/dyaml/node.d | 263 |
1 files changed, 159 insertions, 104 deletions
diff --git a/src/ext_depends/D-YAML/source/dyaml/node.d b/src/ext_depends/D-YAML/source/dyaml/node.d index e96bcec..4c3c5eb 100644 --- a/src/ext_depends/D-YAML/source/dyaml/node.d +++ b/src/ext_depends/D-YAML/source/dyaml/node.d @@ -14,13 +14,17 @@ import std.array; import std.conv; import std.datetime; import std.exception; +import std.format; import std.math; import std.meta : AliasSeq; import std.range; import std.string; import std.traits; import std.typecons; -import std.variant; + +// FIXME: Switch back to upstream's when v2.101 is the oldest +// supported version (recommended: after v2.111 release). +import dyaml.stdsumtype; import dyaml.event; import dyaml.exception; @@ -34,8 +38,9 @@ class NodeException : MarkedYAMLException // // Params: msg = Error message. // start = Start position of the node. - this(string msg, Mark start, string file = __FILE__, size_t line = __LINE__) - @safe + this(string msg, const scope Mark start, + string file = __FILE__, size_t line = __LINE__) + @safe pure nothrow { super(msg, start, file, line); } @@ -57,6 +62,9 @@ struct YAMLNull string toString() const pure @safe nothrow {return "null";} } +/// Invalid YAML type, used internally by SumType +private struct YAMLInvalid {} + // Merge YAML type, used to support "tag:yaml.org,2002:merge". package struct YAMLMerge{} @@ -79,18 +87,28 @@ private struct Pair } /// Equality test with another Pair. - bool opEquals(const ref Pair rhs) const @safe + bool opEquals(const ref Pair rhs) const scope @safe { return key == rhs.key && value == rhs.value; } // Comparison with another Pair. - int opCmp(ref const(Pair) rhs) const @safe + int opCmp(const scope ref Pair rhs) const scope @safe { const keyCmp = key.opCmp(rhs.key); return keyCmp != 0 ? keyCmp : value.opCmp(rhs.value); } + + /// + public void toString (scope void delegate(scope const(char)[]) @safe sink) + const scope @safe + { + // formattedWrite does not accept `scope` parameters + () @trusted { + formattedWrite(sink, "%s: %s", this.key, this.value); + }(); + } } enum NodeType @@ -121,15 +139,16 @@ struct Node package: // YAML value type. - alias Value = Algebraic!(YAMLNull, YAMLMerge, bool, long, real, ubyte[], SysTime, string, - Node.Pair[], Node[]); + alias Value = SumType!( + YAMLInvalid, YAMLNull, YAMLMerge, + bool, long, real, ubyte[], SysTime, string, + Node.Pair[], Node[]); // Can Value hold this type naturally? enum allowed(T) = isIntegral!T || - isFloatingPoint!T || - isSomeString!T || - is(Unqual!T == bool) || - Value.allowed!T; + isFloatingPoint!T || + isSomeString!T || + is(typeof({ Value i = T.init; })); // Stored value. Value value_; @@ -391,19 +410,19 @@ struct Node } /// Is this node valid (initialized)? - @property bool isValid() const @safe pure nothrow + @property bool isValid() const scope @safe pure nothrow @nogc { - return value_.hasValue; + return value_.match!((const YAMLInvalid _) => false, _ => true); } /// Return tag of the node. - @property string tag() const @safe nothrow + @property string tag() const return scope @safe pure nothrow @nogc { return tag_; } /// Return the start position of the node. - @property Mark startMark() const @safe pure nothrow + @property Mark startMark() const return scope @safe pure nothrow @nogc { return startMark_; } @@ -422,11 +441,11 @@ struct Node * * Returns: true if equal, false otherwise. */ - bool opEquals(const Node rhs) const @safe + bool opEquals(const scope Node rhs) const scope @safe { return opCmp(rhs) == 0; } - bool opEquals(T)(const auto ref T rhs) const + bool opEquals(T)(const scope auto ref T rhs) const @safe { try { @@ -497,10 +516,11 @@ struct Node * Throws: NodeException if unable to convert to specified type, or if * the value is out of range of requested type. */ - inout(T) get(T, Flag!"stringConversion" stringConversion = Yes.stringConversion)() inout - if (allowed!(Unqual!T) || hasNodeConstructor!(inout(Unqual!T)) || (!hasIndirections!(Unqual!T) && hasNodeConstructor!(Unqual!T))) + inout(T) get(T, Flag!"stringConversion" stringConversion = Yes.stringConversion)() inout @safe return scope { - if(isType!(Unqual!T)){return getValue!T;} + static assert (allowed!(Unqual!T) || + hasNodeConstructor!(inout(Unqual!T)) || + (!hasIndirections!(Unqual!T) && hasNodeConstructor!(Unqual!T))); static if(!allowed!(Unqual!T)) { @@ -530,6 +550,8 @@ struct Node static assert(0, "Unhandled user type"); } } else { + static if (canBeType!T) + if (isType!(Unqual!T)) { return getValue!T; } // If we're getting from a mapping and we're not getting Node.Pair[], // we're getting the default value. @@ -549,9 +571,9 @@ struct Node // Try to convert to string. try { - return coerceValue!T(); + return coerceValue!T().dup; } - catch(VariantException e) + catch (MatchException e) { throw new NodeException("Unable to convert node value to string", startMark_); } @@ -646,9 +668,11 @@ struct Node this.z = z; } - this(Node node) @safe + this(scope const Node node) @safe { - auto parts = node.as!string().split(":"); + // `std.array.split` is not marked as taking a `scope` range, + // but we don't escape a reference. + scope parts = () @trusted { return node.as!string().split(":"); }(); x = parts[0].to!int; y = parts[1].to!int; z = parts[2].to!int; @@ -770,9 +794,11 @@ struct Node this.z = z; } - this(Node node) @safe inout + this(scope const Node node) @safe inout { - auto parts = node.as!string().split(":"); + // `std.array.split` is not marked as taking a `scope` range, + // but we don't escape a reference. + scope parts = () @trusted { return node.as!string().split(":"); }(); x = parts[0].to!int; y = parts[1].to!int; z = parts[2].to!int; @@ -921,7 +947,7 @@ struct Node * non-integral index is used with a sequence or the node is * not a collection. */ - ref inout(Node) opIndex(T)(T index) inout @safe + ref inout(Node) opIndex(T)(T index) inout return scope @safe { final switch (nodeID) { @@ -1362,7 +1388,7 @@ struct Node string[int] test; foreach (pair; n.mapping) - test[pair.key.as!int] = pair.value.as!string; + test[pair.key.as!int] = pair.value.as!string.idup; assert(test[1] == "foo"); assert(test[2] == "bar"); @@ -1665,7 +1691,7 @@ struct Node Pair(k3, Node(cast(real)1.0)), Pair(k4, Node("yarly"))]); - foreach(string key, Node value; nmap2) + foreach(scope string key, scope Node value; nmap2) { switch(key) { @@ -1957,12 +1983,16 @@ struct Node } /// Compare with another _node. - int opCmp(const ref Node rhs) const @safe - { - // Compare tags - if equal or both null, we need to compare further. - const tagCmp = (tag_ is null) ? (rhs.tag_ is null) ? 0 : -1 - : (rhs.tag_ is null) ? 1 : std.algorithm.comparison.cmp(tag_, rhs.tag_); - if(tagCmp != 0){return tagCmp;} + int opCmp(const scope ref Node rhs) const scope @safe + { + const bool hasNullTag = this.tag_ is null; + // Only one of them is null: we can order nodes + if ((hasNullTag) ^ (rhs.tag is null)) + return hasNullTag ? -1 : 1; + // Either both `null` or both have a value + if (!hasNullTag) + if (int result = std.algorithm.comparison.cmp(tag_, rhs.tag_)) + return result; static int cmp(T1, T2)(T1 a, T2 b) { @@ -1972,15 +2002,14 @@ struct Node } // Compare validity: if both valid, we have to compare further. - const v1 = isValid; - const v2 = rhs.isValid; - if(!v1){return v2 ? -1 : 0;} - if(!v2){return 1;} - - const typeCmp = cmp(type, rhs.type); - if(typeCmp != 0){return typeCmp;} + if (!this.isValid()) + return rhs.isValid() ? -1 : 0; + if (!rhs.isValid()) + return 1; + if (const typeCmp = cmp(type, rhs.type)) + return typeCmp; - static int compareCollections(T)(const ref Node lhs, const ref Node rhs) + static int compareCollections(T)(const scope ref Node lhs, const scope ref Node rhs) { const c1 = lhs.getValue!T; const c2 = rhs.getValue!T; @@ -2070,7 +2099,7 @@ struct Node // Compute hash of the node. hash_t toHash() nothrow const @trusted { - const valueHash = value_.toHash(); + const valueHash = value_.match!(v => hashOf(v)); return tag_ is null ? valueHash : tag_.hashOf(valueHash); } @@ -2081,57 +2110,25 @@ struct Node } /// Get type of the node value. - @property NodeType type() const @safe nothrow - { - if (value_.type is typeid(bool)) - { - return NodeType.boolean; - } - else if (value_.type is typeid(long)) - { - return NodeType.integer; - } - else if (value_.type is typeid(Node[])) - { - return NodeType.sequence; - } - else if (value_.type is typeid(ubyte[])) - { - return NodeType.binary; - } - else if (value_.type is typeid(string)) - { - return NodeType.string; - } - else if (value_.type is typeid(Node.Pair[])) - { - return NodeType.mapping; - } - else if (value_.type is typeid(SysTime)) - { - return NodeType.timestamp; - } - else if (value_.type is typeid(YAMLNull)) - { - return NodeType.null_; - } - else if (value_.type is typeid(YAMLMerge)) - { - return NodeType.merge; - } - else if (value_.type is typeid(real)) - { - return NodeType.decimal; - } - else if (!value_.hasValue) - { - return NodeType.invalid; - } - else assert(0, text(value_.type)); + @property NodeType type() const scope @safe pure nothrow @nogc + { + return this.value_.match!( + (const bool _) => NodeType.boolean, + (const long _) => NodeType.integer, + (const Node[] _) => NodeType.sequence, + (const ubyte[] _) => NodeType.binary, + (const string _) => NodeType.string, + (const Node.Pair[] _) => NodeType.mapping, + (const SysTime _) => NodeType.timestamp, + (const YAMLNull _) => NodeType.null_, + (const YAMLMerge _) => NodeType.merge, + (const real _) => NodeType.decimal, + (const YAMLInvalid _) => NodeType.invalid, + ); } /// Get the kind of node this is. - @property NodeID nodeID() const @safe nothrow + @property NodeID nodeID() const scope @safe pure nothrow @nogc { final switch (type) { @@ -2159,7 +2156,7 @@ struct Node // Params: level = Level of the node in the tree. // // Returns: String representing the node tree. - @property string debugString(uint level = 0) const @safe + @property string debugString(uint level = 0) const scope @safe { string indent; foreach(i; 0 .. level){indent ~= " ";} @@ -2192,7 +2189,7 @@ struct Node public: - @property string nodeTypeString() const @safe nothrow + @property string nodeTypeString() const scope @safe pure nothrow @nogc { final switch (nodeID) { @@ -2325,9 +2322,16 @@ struct Node // This only works for default YAML types, not for user defined types. @property bool isType(T)() const { - return value_.type is typeid(Unqual!T); + return value_.match!( + (const T _) => true, + _ => false, + ); } + /// Check at compile time if a type is stored natively + enum canBeType (T) = is(typeof({ value_.match!((const T _) => true, _ => false); })); + + // Implementation of contains() and containsKey(). bool contains_(T, Flag!"key" key, string func)(T rhs) const { @@ -2403,7 +2407,8 @@ struct Node // Get index of pair with key (or value, if key is false) matching index. // Cannot be inferred @safe due to https://issues.dlang.org/show_bug.cgi?id=16528 - sizediff_t findPair(T, Flag!"key" key = Yes.key)(const ref T index) const @safe + sizediff_t findPair(T, Flag!"key" key = Yes.key)(const scope ref T index) + const scope @safe { const pairs = getValue!(Pair[])(); const(Node)* node; @@ -2427,7 +2432,7 @@ struct Node } // Check if index is integral and in range. - void checkSequenceIndex(T)(T index) const + void checkSequenceIndex(T)(T index) const scope @safe { assert(nodeID == NodeID.sequence, "checkSequenceIndex() called on a " ~ nodeTypeString ~ " node"); @@ -2444,14 +2449,42 @@ struct Node } } // Safe wrapper for getting a value out of the variant. - inout(T) getValue(T)() @trusted inout + inout(T) getValue(T)() @safe return scope inout { - return value_.get!T; + alias RType = typeof(return); + return value_.tryMatch!((RType r) => r); } // Safe wrapper for coercing a value out of the variant. - inout(T) coerceValue(T)() @trusted inout - { - return (cast(Value)value_).coerce!T; + inout(T) coerceValue(T)() @trusted scope return inout + { + alias RType = typeof(return); + static if (is(typeof({ RType rt = T.init; T t = RType.init; }))) + alias TType = T; + else // `inout` matters (indirection) + alias TType = RType; + + // `inout(Node[]).to!string` apparently is not safe: + // struct SumTypeBug { + // import std.conv; + // Node[] data; + // + // string bug () inout @safe + // { + // return this.data.to!string; + // } + // } + // Doesn't compile with DMD v2.100.0 + return this.value_.tryMatch!( + (inout bool v) @safe => v.to!TType, + (inout long v) @safe => v.to!TType, + (inout Node[] v) @trusted => v.to!TType, + (inout ubyte[] v) @safe => v.to!TType, + (inout string v) @safe => v.to!TType, + (inout Node.Pair[] v) @trusted => v.to!TType, + (inout SysTime v) @trusted => v.to!TType, + (inout real v) @safe => v.to!TType, + (inout YAMLNull v) @safe => null.to!TType, + ); } // Safe wrapper for setting a value for the variant. void setValue(T)(T value) @trusted @@ -2469,6 +2502,25 @@ struct Node value_ = tmpNode.value_; } } + + /// + public void toString (DGT) (scope DGT sink) + const scope @safe + { + this.value_.match!( + (const bool v) => formattedWrite(sink, v ? "true" : "false"), + (const long v) => formattedWrite(sink, "%s", v), + (const Node[] v) => formattedWrite(sink, "[%(%s, %)]", v), + (const ubyte[] v) => formattedWrite(sink, "%s", v), + (const string v) => formattedWrite(sink, `"%s"`, v), + (const Node.Pair[] v) => formattedWrite(sink, "{%(%s, %)}", v), + (const SysTime v) => formattedWrite(sink, "%s", v), + (const YAMLNull v) => formattedWrite(sink, "%s", v), + (const YAMLMerge v) => formattedWrite(sink, "%s", v), + (const real v) => formattedWrite(sink, "%s", v), + (const YAMLInvalid v) => formattedWrite(sink, "%s", v), + ); + } } package: @@ -2481,7 +2533,10 @@ package: // toMerge = Pairs to merge. void merge(ref Appender!(Node.Pair[]) pairs, Node.Pair[] toMerge) @safe { - bool eq(ref Node.Pair a, ref Node.Pair b){return a.key == b.key;} + bool eq(ref Node.Pair a, ref Node.Pair b) @safe + { + return a.key == b.key; + } foreach(ref pair; toMerge) if(!canFind!eq(pairs.data, pair)) { @@ -2528,7 +2583,7 @@ enum castableToNode(T) = (is(T == struct) || is(T == class)) && is(typeof(T.opCa { foreach(value; node["bars"].sequence) { - bars ~= value.as!string; + bars ~= value.as!string.idup; } } } |