aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ext_depends/D-YAML/source/dyaml/representer.d
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext_depends/D-YAML/source/dyaml/representer.d')
-rw-r--r--src/ext_depends/D-YAML/source/dyaml/representer.d517
1 files changed, 517 insertions, 0 deletions
diff --git a/src/ext_depends/D-YAML/source/dyaml/representer.d b/src/ext_depends/D-YAML/source/dyaml/representer.d
new file mode 100644
index 0000000..a7ca802
--- /dev/null
+++ b/src/ext_depends/D-YAML/source/dyaml/representer.d
@@ -0,0 +1,517 @@
+
+// Copyright Ferdinand Majerech 2011.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+/**
+ * YAML node _representer. Prepares YAML nodes for output. A tutorial can be
+ * found $(LINK2 ../tutorials/custom_types.html, here).
+ *
+ * Code based on $(LINK2 http://www.pyyaml.org, PyYAML).
+ */
+module dyaml.representer;
+
+
+import std.algorithm;
+import std.array;
+import std.base64;
+import std.container;
+import std.conv;
+import std.datetime;
+import std.exception;
+import std.format;
+import std.math;
+import std.typecons;
+import std.string;
+
+import dyaml.exception;
+import dyaml.node;
+import dyaml.serializer;
+import dyaml.style;
+
+package:
+///Exception thrown on Representer errors.
+class RepresenterException : YAMLException
+{
+ mixin ExceptionCtors;
+}
+
+/**
+ * Represents YAML nodes as scalar, sequence and mapping nodes ready for output.
+ */
+Node representData(const Node data, ScalarStyle defaultScalarStyle, CollectionStyle defaultCollectionStyle) @safe
+{
+ Node result;
+ final switch(data.type)
+ {
+ case NodeType.null_:
+ result = representNull();
+ break;
+ case NodeType.merge:
+ break;
+ case NodeType.boolean:
+ result = representBool(data);
+ break;
+ case NodeType.integer:
+ result = representLong(data);
+ break;
+ case NodeType.decimal:
+ result = representReal(data);
+ break;
+ case NodeType.binary:
+ result = representBytes(data);
+ break;
+ case NodeType.timestamp:
+ result = representSysTime(data);
+ break;
+ case NodeType.string:
+ result = representString(data);
+ break;
+ case NodeType.mapping:
+ result = representPairs(data, defaultScalarStyle, defaultCollectionStyle);
+ break;
+ case NodeType.sequence:
+ result = representNodes(data, defaultScalarStyle, defaultCollectionStyle);
+ break;
+ case NodeType.invalid:
+ assert(0);
+ }
+
+ final switch (result.nodeID)
+ {
+ case NodeID.scalar:
+ if (result.scalarStyle == ScalarStyle.invalid)
+ {
+ result.scalarStyle = defaultScalarStyle;
+ }
+ break;
+ case NodeID.sequence, NodeID.mapping:
+ if (defaultCollectionStyle != CollectionStyle.invalid)
+ {
+ result.collectionStyle = defaultCollectionStyle;
+ }
+ case NodeID.invalid:
+ }
+
+
+ //Override tag if specified.
+ if(data.tag_ !is null){result.tag_ = data.tag_;}
+
+ //Remember style if this was loaded before.
+ if(data.scalarStyle != ScalarStyle.invalid)
+ {
+ result.scalarStyle = data.scalarStyle;
+ }
+ if(data.collectionStyle != CollectionStyle.invalid)
+ {
+ result.collectionStyle = data.collectionStyle;
+ }
+ return result;
+}
+
+@safe unittest
+{
+ // We don't emit yaml merge nodes.
+ assert(representData(Node(YAMLMerge()), ScalarStyle.invalid, CollectionStyle.invalid) == Node.init);
+}
+
+@safe unittest
+{
+ assert(representData(Node(YAMLNull()), ScalarStyle.invalid, CollectionStyle.invalid) == Node("null", "tag:yaml.org,2002:null"));
+}
+
+@safe unittest
+{
+ assert(representData(Node(cast(string)null), ScalarStyle.invalid, CollectionStyle.invalid) == Node("null", "tag:yaml.org,2002:null"));
+ assert(representData(Node("Hello world!"), ScalarStyle.invalid, CollectionStyle.invalid) == Node("Hello world!", "tag:yaml.org,2002:str"));
+}
+
+@safe unittest
+{
+ assert(representData(Node(64), ScalarStyle.invalid, CollectionStyle.invalid) == Node("64", "tag:yaml.org,2002:int"));
+}
+
+@safe unittest
+{
+ assert(representData(Node(true), ScalarStyle.invalid, CollectionStyle.invalid) == Node("true", "tag:yaml.org,2002:bool"));
+ assert(representData(Node(false), ScalarStyle.invalid, CollectionStyle.invalid) == Node("false", "tag:yaml.org,2002:bool"));
+}
+
+@safe unittest
+{
+ // Float comparison is pretty unreliable...
+ auto result = representData(Node(1.0), ScalarStyle.invalid, CollectionStyle.invalid);
+ assert(approxEqual(result.as!string.to!real, 1.0));
+ assert(result.tag == "tag:yaml.org,2002:float");
+
+ assert(representData(Node(real.nan), ScalarStyle.invalid, CollectionStyle.invalid) == Node(".nan", "tag:yaml.org,2002:float"));
+ assert(representData(Node(real.infinity), ScalarStyle.invalid, CollectionStyle.invalid) == Node(".inf", "tag:yaml.org,2002:float"));
+ assert(representData(Node(-real.infinity), ScalarStyle.invalid, CollectionStyle.invalid) == Node("-.inf", "tag:yaml.org,2002:float"));
+}
+
+@safe unittest
+{
+ assert(representData(Node(SysTime(DateTime(2000, 3, 14, 12, 34, 56), UTC())), ScalarStyle.invalid, CollectionStyle.invalid) == Node("2000-03-14T12:34:56Z", "tag:yaml.org,2002:timestamp"));
+}
+
+@safe unittest
+{
+ assert(representData(Node(Node[].init, "tag:yaml.org,2002:set"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node.Pair[].init, "tag:yaml.org,2002:set"));
+ assert(representData(Node(Node[].init, "tag:yaml.org,2002:seq"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node[].init, "tag:yaml.org,2002:seq"));
+ {
+ auto nodes = [
+ Node("a"),
+ Node("b"),
+ Node("c"),
+ ];
+ assert(representData(Node(nodes, "tag:yaml.org,2002:set"), ScalarStyle.invalid, CollectionStyle.invalid) ==
+ Node([
+ Node.Pair(
+ Node("a", "tag:yaml.org,2002:str"),
+ Node("null", "tag:yaml.org,2002:null")
+ ),
+ Node.Pair(
+ Node("b", "tag:yaml.org,2002:str"),
+ Node("null", "tag:yaml.org,2002:null")
+ ),
+ Node.Pair(
+ Node("c", "tag:yaml.org,2002:str"),
+ Node("null", "tag:yaml.org,2002:null")
+ )
+ ], "tag:yaml.org,2002:set"));
+ }
+ {
+ auto nodes = [
+ Node("a"),
+ Node("b"),
+ Node("c"),
+ ];
+ assert(representData(Node(nodes, "tag:yaml.org,2002:seq"), ScalarStyle.invalid, CollectionStyle.invalid) ==
+ Node([
+ Node("a", "tag:yaml.org,2002:str"),
+ Node("b", "tag:yaml.org,2002:str"),
+ Node("c", "tag:yaml.org,2002:str")
+ ], "tag:yaml.org,2002:seq"));
+ }
+}
+
+@safe unittest
+{
+ assert(representData(Node(Node.Pair[].init, "tag:yaml.org,2002:omap"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node[].init, "tag:yaml.org,2002:omap"));
+ assert(representData(Node(Node.Pair[].init, "tag:yaml.org,2002:pairs"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node[].init, "tag:yaml.org,2002:pairs"));
+ assert(representData(Node(Node.Pair[].init, "tag:yaml.org,2002:map"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node.Pair[].init, "tag:yaml.org,2002:map"));
+ {
+ auto nodes = [
+ Node.Pair("a", "b"),
+ Node.Pair("a", "c")
+ ];
+ assertThrown(representData(Node(nodes, "tag:yaml.org,2002:omap"), ScalarStyle.invalid, CollectionStyle.invalid));
+ }
+ // Yeah, this gets ugly really fast.
+ {
+ auto nodes = [
+ Node.Pair("a", "b"),
+ Node.Pair("a", "c")
+ ];
+ assert(representData(Node(nodes, "tag:yaml.org,2002:pairs"), ScalarStyle.invalid, CollectionStyle.invalid) ==
+ Node([
+ Node(
+ [Node.Pair(
+ Node("a", "tag:yaml.org,2002:str"),
+ Node("b", "tag:yaml.org,2002:str")
+ )],
+ "tag:yaml.org,2002:map"),
+ Node(
+ [Node.Pair(
+ Node("a", "tag:yaml.org,2002:str"),
+ Node("c", "tag:yaml.org,2002:str")
+ )],
+ "tag:yaml.org,2002:map"),
+ ], "tag:yaml.org,2002:pairs"));
+ }
+ {
+ auto nodes = [
+ Node.Pair("a", "b"),
+ Node.Pair("a", "c")
+ ];
+ assertThrown(representData(Node(nodes, "tag:yaml.org,2002:map"), ScalarStyle.invalid, CollectionStyle.invalid));
+ }
+ {
+ auto nodes = [
+ Node.Pair("a", "b"),
+ Node.Pair("c", "d")
+ ];
+ assert(representData(Node(nodes, "tag:yaml.org,2002:omap"), ScalarStyle.invalid, CollectionStyle.invalid) ==
+ Node([
+ Node([
+ Node.Pair(
+ Node("a", "tag:yaml.org,2002:str"),
+ Node("b", "tag:yaml.org,2002:str")
+ )
+ ], "tag:yaml.org,2002:map"),
+ Node([
+ Node.Pair(
+ Node("c", "tag:yaml.org,2002:str"),
+ Node("d", "tag:yaml.org,2002:str")
+ )
+ ], "tag:yaml.org,2002:map"
+ )], "tag:yaml.org,2002:omap"));
+ }
+ {
+ auto nodes = [
+ Node.Pair("a", "b"),
+ Node.Pair("c", "d")
+ ];
+ assert(representData(Node(nodes, "tag:yaml.org,2002:map"), ScalarStyle.invalid, CollectionStyle.invalid) ==
+ Node([
+ Node.Pair(
+ Node("a", "tag:yaml.org,2002:str"),
+ Node("b", "tag:yaml.org,2002:str")
+ ),
+ Node.Pair(
+ Node("c", "tag:yaml.org,2002:str"),
+ Node("d", "tag:yaml.org,2002:str")
+ ),
+ ], "tag:yaml.org,2002:map"));
+ }
+}
+
+private:
+
+//Represent a _null _node as a _null YAML value.
+Node representNull() @safe
+{
+ return Node("null", "tag:yaml.org,2002:null");
+}
+
+//Represent a string _node as a string scalar.
+Node representString(const Node node) @safe
+{
+ string value = node.as!string;
+ return value is null
+ ? Node("null", "tag:yaml.org,2002:null")
+ : Node(value, "tag:yaml.org,2002:str");
+}
+
+//Represent a bytes _node as a binary scalar.
+Node representBytes(const Node node) @safe
+{
+ const ubyte[] value = node.as!(ubyte[]);
+ if(value is null){return Node("null", "tag:yaml.org,2002:null");}
+
+ auto newNode = Node(Base64.encode(value).idup, "tag:yaml.org,2002:binary");
+ newNode.scalarStyle = ScalarStyle.literal;
+ return newNode;
+}
+
+//Represent a bool _node as a bool scalar.
+Node representBool(const Node node) @safe
+{
+ return Node(node.as!bool ? "true" : "false", "tag:yaml.org,2002:bool");
+}
+
+//Represent a long _node as an integer scalar.
+Node representLong(const Node node) @safe
+{
+ return Node(node.as!long.to!string, "tag:yaml.org,2002:int");
+}
+
+//Represent a real _node as a floating point scalar.
+Node representReal(const Node node) @safe
+{
+ real f = node.as!real;
+ string value = isNaN(f) ? ".nan":
+ f == real.infinity ? ".inf":
+ f == -1.0 * real.infinity ? "-.inf":
+ {auto a = appender!string();
+ formattedWrite(a, "%12f", f);
+ return a.data.strip();}();
+
+ return Node(value, "tag:yaml.org,2002:float");
+}
+
+//Represent a SysTime _node as a timestamp.
+Node representSysTime(const Node node) @safe
+{
+ return Node(node.as!SysTime.toISOExtString(), "tag:yaml.org,2002:timestamp");
+}
+
+//Represent a sequence _node as sequence/set.
+Node representNodes(const Node node, ScalarStyle defaultScalarStyle, CollectionStyle defaultCollectionStyle) @safe
+{
+ auto nodes = node.as!(Node[]);
+ if(node.tag_ == "tag:yaml.org,2002:set")
+ {
+ //YAML sets are mapping with null values.
+ Node.Pair[] pairs;
+ pairs.length = nodes.length;
+
+ foreach(idx, key; nodes)
+ {
+ pairs[idx] = Node.Pair(key, Node("null", "tag:yaml.org,2002:null"));
+ }
+ Node.Pair[] value;
+ value.length = pairs.length;
+
+ auto bestStyle = CollectionStyle.flow;
+ foreach(idx, pair; pairs)
+ {
+ value[idx] = Node.Pair(representData(pair.key, defaultScalarStyle, defaultCollectionStyle), representData(pair.value, defaultScalarStyle, defaultCollectionStyle));
+ if(value[idx].shouldUseBlockStyle)
+ {
+ bestStyle = CollectionStyle.block;
+ }
+ }
+
+ auto newNode = Node(value, node.tag_);
+ newNode.collectionStyle = bestStyle;
+ return newNode;
+ }
+ else
+ {
+ Node[] value;
+ value.length = nodes.length;
+
+ auto bestStyle = CollectionStyle.flow;
+ foreach(idx, item; nodes)
+ {
+ value[idx] = representData(item, defaultScalarStyle, defaultCollectionStyle);
+ const isScalar = value[idx].nodeID == NodeID.scalar;
+ const s = value[idx].scalarStyle;
+ if(!isScalar || (s != ScalarStyle.invalid && s != ScalarStyle.plain))
+ {
+ bestStyle = CollectionStyle.block;
+ }
+ }
+
+ auto newNode = Node(value, "tag:yaml.org,2002:seq");
+ newNode.collectionStyle = bestStyle;
+ return newNode;
+ }
+}
+
+bool shouldUseBlockStyle(const Node value) @safe
+{
+ const isScalar = value.nodeID == NodeID.scalar;
+ const s = value.scalarStyle;
+ return (!isScalar || (s != ScalarStyle.invalid && s != ScalarStyle.plain));
+}
+bool shouldUseBlockStyle(const Node.Pair value) @safe
+{
+ const keyScalar = value.key.nodeID == NodeID.scalar;
+ const valScalar = value.value.nodeID == NodeID.scalar;
+ const keyStyle = value.key.scalarStyle;
+ const valStyle = value.value.scalarStyle;
+ if(!keyScalar ||
+ (keyStyle != ScalarStyle.invalid && keyStyle != ScalarStyle.plain))
+ {
+ return true;
+ }
+ if(!valScalar ||
+ (valStyle != ScalarStyle.invalid && valStyle != ScalarStyle.plain))
+ {
+ return true;
+ }
+ return false;
+}
+
+//Represent a mapping _node as map/ordered map/pairs.
+Node representPairs(const Node node, ScalarStyle defaultScalarStyle, CollectionStyle defaultCollectionStyle) @safe
+{
+ auto pairs = node.as!(Node.Pair[]);
+
+ bool hasDuplicates(const Node.Pair[] pairs) @safe
+ {
+ //TODO this should be replaced by something with deterministic memory allocation.
+ auto keys = redBlackTree!Node();
+ foreach(pair; pairs)
+ {
+ if(pair.key in keys){return true;}
+ keys.insert(pair.key);
+ }
+ return false;
+ }
+
+ Node[] mapToSequence(const Node.Pair[] pairs) @safe
+ {
+ Node[] nodes;
+ nodes.length = pairs.length;
+ foreach(idx, pair; pairs)
+ {
+ Node.Pair value;
+
+ auto bestStyle = value.shouldUseBlockStyle ? CollectionStyle.block : CollectionStyle.flow;
+ value = Node.Pair(representData(pair.key, defaultScalarStyle, defaultCollectionStyle), representData(pair.value, defaultScalarStyle, defaultCollectionStyle));
+
+ auto newNode = Node([value], "tag:yaml.org,2002:map");
+ newNode.collectionStyle = bestStyle;
+ nodes[idx] = newNode;
+ }
+ return nodes;
+ }
+
+ if(node.tag_ == "tag:yaml.org,2002:omap")
+ {
+ enforce(!hasDuplicates(pairs),
+ new RepresenterException("Duplicate entry in an ordered map"));
+ auto sequence = mapToSequence(pairs);
+ Node[] value;
+ value.length = sequence.length;
+
+ auto bestStyle = CollectionStyle.flow;
+ foreach(idx, item; sequence)
+ {
+ value[idx] = representData(item, defaultScalarStyle, defaultCollectionStyle);
+ if(value[idx].shouldUseBlockStyle)
+ {
+ bestStyle = CollectionStyle.block;
+ }
+ }
+
+ auto newNode = Node(value, node.tag_);
+ newNode.collectionStyle = bestStyle;
+ return newNode;
+ }
+ else if(node.tag_ == "tag:yaml.org,2002:pairs")
+ {
+ auto sequence = mapToSequence(pairs);
+ Node[] value;
+ value.length = sequence.length;
+
+ auto bestStyle = CollectionStyle.flow;
+ foreach(idx, item; sequence)
+ {
+ value[idx] = representData(item, defaultScalarStyle, defaultCollectionStyle);
+ if(value[idx].shouldUseBlockStyle)
+ {
+ bestStyle = CollectionStyle.block;
+ }
+ }
+
+ auto newNode = Node(value, node.tag_);
+ newNode.collectionStyle = bestStyle;
+ return newNode;
+ }
+ else
+ {
+ enforce(!hasDuplicates(pairs),
+ new RepresenterException("Duplicate entry in an unordered map"));
+ Node.Pair[] value;
+ value.length = pairs.length;
+
+ auto bestStyle = CollectionStyle.flow;
+ foreach(idx, pair; pairs)
+ {
+ value[idx] = Node.Pair(representData(pair.key, defaultScalarStyle, defaultCollectionStyle), representData(pair.value, defaultScalarStyle, defaultCollectionStyle));
+ if(value[idx].shouldUseBlockStyle)
+ {
+ bestStyle = CollectionStyle.block;
+ }
+ }
+
+ auto newNode = Node(value, "tag:yaml.org,2002:map");
+ newNode.collectionStyle = bestStyle;
+ return newNode;
+ }
+}