Merge pull request #54 from BBasile/master
Merge changes from the fork used by the dlang tour
This commit is contained in:
commit
8e1e9893d1
14
.editorconfig
Normal file
14
.editorconfig
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# EditorConfig file: http://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.d]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
10
README.rst
10
README.rst
|
@ -2,9 +2,13 @@
|
||||||
D:YAML 0.5
|
D:YAML 0.5
|
||||||
==========
|
==========
|
||||||
|
|
||||||
.. image:: https://travis-ci.org/kiith-sa/D-YAML.svg?branch=master
|
This is a fork of the D:YAML library by kiith-sa (https://github.com/kiith-sa/D-YAML).
|
||||||
.. image:: https://raw.githubusercontent.com/kiith-sa/D-YAML/master/code.dlang.org-shield.png
|
The intent of this fork is to provide a version suitable for use by dlang-tour, until
|
||||||
:target: http://code.dlang.org
|
fixes are accepted upstream.
|
||||||
|
|
||||||
|
.. image:: https://travis-ci.org/dlang-tour/dyaml-dlang-tour.svg?branch=master
|
||||||
|
.. image:: https://img.shields.io/dub/v/dyaml-dlang-tour.svg
|
||||||
|
:target: http://code.dlang.org/packages/dyaml-dlang-tour
|
||||||
|
|
||||||
**Note**: D:YAML 0.5 brings some **breaking changes**. See the
|
**Note**: D:YAML 0.5 brings some **breaking changes**. See the
|
||||||
`changelog <https://github.com/kiith-sa/D-YAML/blob/master/CHANGES.rst>`_.
|
`changelog <https://github.com/kiith-sa/D-YAML/blob/master/CHANGES.rst>`_.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "dyaml",
|
"name": "dyaml-dlang-tour",
|
||||||
"description": "YAML parser and emitter",
|
"description": "YAML parser and emitter",
|
||||||
"authors": [ "Ferdinand Majerech" ],
|
"authors": [ "Ferdinand Majerech" ],
|
||||||
"libs": [],
|
"libs": [],
|
|
@ -110,7 +110,7 @@ final class Composer
|
||||||
{
|
{
|
||||||
//Get the root node of the next document.
|
//Get the root node of the next document.
|
||||||
assert(!parser_.checkEvent(EventID.StreamEnd),
|
assert(!parser_.checkEvent(EventID.StreamEnd),
|
||||||
"Trying to get a node from Composer when there is no node to "
|
"Trying to get a node from Composer when there is no node to " ~
|
||||||
"get. use checkNode() to determine if there is a node.");
|
"get. use checkNode() to determine if there is a node.");
|
||||||
|
|
||||||
return composeDocument();
|
return composeDocument();
|
||||||
|
@ -120,14 +120,14 @@ final class Composer
|
||||||
Node getSingleNode() @trusted
|
Node getSingleNode() @trusted
|
||||||
{
|
{
|
||||||
assert(!parser_.checkEvent(EventID.StreamEnd),
|
assert(!parser_.checkEvent(EventID.StreamEnd),
|
||||||
"Trying to get a node from Composer when there is no node to "
|
"Trying to get a node from Composer when there is no node to " ~
|
||||||
"get. use checkNode() to determine if there is a node.");
|
"get. use checkNode() to determine if there is a node.");
|
||||||
|
|
||||||
Node document = composeDocument();
|
Node document = composeDocument();
|
||||||
|
|
||||||
//Ensure that the stream contains no more documents.
|
//Ensure that the stream contains no more documents.
|
||||||
enforce(parser_.checkEvent(EventID.StreamEnd),
|
enforce(parser_.checkEvent(EventID.StreamEnd),
|
||||||
new ComposerException("Expected single document in the stream, "
|
new ComposerException("Expected single document in the stream, " ~
|
||||||
"but found another document.",
|
"but found another document.",
|
||||||
parser_.getEvent().startMark));
|
parser_.getEvent().startMark));
|
||||||
|
|
||||||
|
@ -292,11 +292,11 @@ final class Composer
|
||||||
void error(Node node)
|
void error(Node node)
|
||||||
{
|
{
|
||||||
//this is Composer, but the code is related to Constructor.
|
//this is Composer, but the code is related to Constructor.
|
||||||
throw new ConstructorException("While constructing a mapping, "
|
throw new ConstructorException("While constructing a mapping, " ~
|
||||||
"expected a mapping or a list of "
|
"expected a mapping or a list of " ~
|
||||||
"mappings for merging, but found: "
|
"mappings for merging, but found: " ~
|
||||||
~ node.type.toString() ~
|
node.type.toString() ~
|
||||||
" NOTE: line/column shows topmost parent "
|
" NOTE: line/column shows topmost parent " ~
|
||||||
"to which the content is being merged",
|
"to which the content is being merged",
|
||||||
startMark, endMark);
|
startMark, endMark);
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,7 +352,7 @@ final class Constructor
|
||||||
assert((tag in fromScalar_) is null &&
|
assert((tag in fromScalar_) is null &&
|
||||||
(tag in fromSequence_) is null &&
|
(tag in fromSequence_) is null &&
|
||||||
(tag in fromMapping_) is null,
|
(tag in fromMapping_) is null,
|
||||||
"Constructor function for tag " ~ tag.get ~ " is already "
|
"Constructor function for tag " ~ tag.get ~ " is already " ~
|
||||||
"specified. Can't specify another one.");
|
"specified. Can't specify another one.");
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,7 @@ struct Dumper
|
||||||
foreach(handle, prefix; tags)
|
foreach(handle, prefix; tags)
|
||||||
{
|
{
|
||||||
assert(handle.length >= 1 && handle[0] == '!' && handle[$ - 1] == '!',
|
assert(handle.length >= 1 && handle[0] == '!' && handle[$ - 1] == '!',
|
||||||
"A tag handle is empty or does not start and end with a "
|
"A tag handle is empty or does not start and end with a " ~
|
||||||
"'!' character : " ~ handle);
|
"'!' character : " ~ handle);
|
||||||
assert(prefix.length >= 1, "A tag prefix is empty");
|
assert(prefix.length >= 1, "A tag prefix is empty");
|
||||||
t ~= TagDirective(handle, prefix);
|
t ~= TagDirective(handle, prefix);
|
||||||
|
|
|
@ -54,7 +54,7 @@ class EmitterException : YAMLException
|
||||||
private alias EmitterException Error;
|
private alias EmitterException Error;
|
||||||
|
|
||||||
//Stores results of analysis of a scalar, determining e.g. what scalar style to use.
|
//Stores results of analysis of a scalar, determining e.g. what scalar style to use.
|
||||||
align(4) struct ScalarAnalysis
|
struct ScalarAnalysis
|
||||||
{
|
{
|
||||||
//Scalar itself.
|
//Scalar itself.
|
||||||
string scalar;
|
string scalar;
|
||||||
|
@ -228,7 +228,7 @@ struct Emitter
|
||||||
int popIndent() @trusted
|
int popIndent() @trusted
|
||||||
{
|
{
|
||||||
enforce(indents_.length > 0,
|
enforce(indents_.length > 0,
|
||||||
new YAMLException("Emitter: Need to pop an indent level but there"
|
new YAMLException("Emitter: Need to pop an indent level but there" ~
|
||||||
" are no indent levels left"));
|
" are no indent levels left"));
|
||||||
const result = indents_.back;
|
const result = indents_.back;
|
||||||
indents_.length = indents_.length - 1;
|
indents_.length = indents_.length - 1;
|
||||||
|
@ -490,7 +490,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Expected Alias, Scalar, SequenceStart or "
|
throw new Error("Expected Alias, Scalar, SequenceStart or " ~
|
||||||
"MappingStart, but got: " ~ event_.idString);
|
"MappingStart, but got: " ~ event_.idString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,8 +227,12 @@ Event scalarEvent(const Mark start, const Mark end, const Anchor anchor, const T
|
||||||
result.value = value;
|
result.value = value;
|
||||||
result.startMark = start;
|
result.startMark = start;
|
||||||
result.endMark = end;
|
result.endMark = end;
|
||||||
result.anchor = anchor;
|
|
||||||
result.tag = tag;
|
() @trusted {
|
||||||
|
result.anchor = anchor;
|
||||||
|
result.tag = tag;
|
||||||
|
}();
|
||||||
|
|
||||||
result.id = EventID.Scalar;
|
result.id = EventID.Scalar;
|
||||||
result.scalarStyle = style;
|
result.scalarStyle = style;
|
||||||
result.implicit = implicit[0];
|
result.implicit = implicit[0];
|
||||||
|
|
|
@ -52,17 +52,17 @@ struct Flags(names ...) if(names.length <= 8)
|
||||||
foreach(index, name; names)
|
foreach(index, name; names)
|
||||||
{
|
{
|
||||||
string istr = to!string(index);
|
string istr = to!string(index);
|
||||||
result ~= "\n"
|
result ~= "\n" ~
|
||||||
"@property bool " ~ name ~ "(bool value) pure @safe nothrow\n"
|
"@property bool " ~ name ~ "(bool value) pure @safe nothrow\n" ~
|
||||||
"{\n"
|
"{\n" ~
|
||||||
" flags_ = value ? flags_ | (1 <<" ~ istr ~ ")\n"
|
" flags_ = value ? flags_ | (1 <<" ~ istr ~ ")\n" ~
|
||||||
" : flags_ & (0xFF ^ (1 << " ~ istr ~"));\n"
|
" : flags_ & (0xFF ^ (1 << " ~ istr ~"));\n" ~
|
||||||
" return value;\n"
|
" return value;\n" ~
|
||||||
"}\n"
|
"}\n" ~
|
||||||
"\n"
|
"\n" ~
|
||||||
"@property bool " ~ name ~ "() const pure @safe nothrow\n"
|
"@property bool " ~ name ~ "() const pure @safe nothrow\n" ~
|
||||||
"{\n"
|
"{\n" ~
|
||||||
" return (flags_ >> " ~ istr ~ ") & 1;\n"
|
" return (flags_ >> " ~ istr ~ ") & 1;\n" ~
|
||||||
"}\n";
|
"}\n";
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -179,7 +179,7 @@ struct Loader
|
||||||
*
|
*
|
||||||
* Throws: YAMLException if yamlData contains data illegal in YAML.
|
* Throws: YAMLException if yamlData contains data illegal in YAML.
|
||||||
*/
|
*/
|
||||||
this(void[] yamlData) @safe
|
this(void[] yamlData) @trusted
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -380,9 +380,9 @@ struct Loader
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
char[] yaml_input = "red: '#ff0000'\n"
|
char[] yaml_input = ("red: '#ff0000'\n" ~
|
||||||
"green: '#00ff00'\n"
|
"green: '#00ff00'\n" ~
|
||||||
"blue: '#0000ff'".dup;
|
"blue: '#0000ff'").dup;
|
||||||
|
|
||||||
auto colors = Loader.fromString(yaml_input).load();
|
auto colors = Loader.fromString(yaml_input).load();
|
||||||
|
|
||||||
|
|
|
@ -454,7 +454,7 @@ struct Node
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(keys.length == values.length,
|
assert(keys.length == values.length,
|
||||||
"Lengths of keys and values arrays to construct "
|
"Lengths of keys and values arrays to construct " ~
|
||||||
"a YAML node from don't match");
|
"a YAML node from don't match");
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
|
@ -1631,6 +1631,7 @@ struct Node
|
||||||
return (cast(nothrowType)&value_.type)();
|
return (cast(nothrowType)&value_.type)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
// Determine if the value stored by the node is of specified 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.
|
// This only works for default YAML types, not for user defined types.
|
||||||
|
@ -1639,7 +1640,6 @@ struct Node
|
||||||
return this.type is typeid(Unqual!T);
|
return this.type is typeid(Unqual!T);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
// Is the value a bool?
|
// Is the value a bool?
|
||||||
alias isType!bool isBool;
|
alias isType!bool isBool;
|
||||||
|
|
||||||
|
@ -1685,6 +1685,7 @@ struct Node
|
||||||
else {return false;}
|
else {return false;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
// Implementation of contains() and containsKey().
|
// Implementation of contains() and containsKey().
|
||||||
bool contains_(T, Flag!"key" key, string func)(T rhs) const @trusted
|
bool contains_(T, Flag!"key" key, string func)(T rhs) const @trusted
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,7 +99,7 @@ final class Reader
|
||||||
auto endianResult = fixUTFByteOrder(buffer);
|
auto endianResult = fixUTFByteOrder(buffer);
|
||||||
if(endianResult.bytesStripped > 0)
|
if(endianResult.bytesStripped > 0)
|
||||||
{
|
{
|
||||||
throw new ReaderException("Size of UTF-16 or UTF-32 input not aligned "
|
throw new ReaderException("Size of UTF-16 or UTF-32 input not aligned " ~
|
||||||
"to 2 or 4 bytes, respectively");
|
"to 2 or 4 bytes, respectively");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,33 +226,33 @@ final class Resolver
|
||||||
void addImplicitResolvers() @safe
|
void addImplicitResolvers() @safe
|
||||||
{
|
{
|
||||||
addImplicitResolver("tag:yaml.org,2002:bool",
|
addImplicitResolver("tag:yaml.org,2002:bool",
|
||||||
regex(r"^(?:yes|Yes|YES|no|No|NO|true|True|TRUE"
|
regex(r"^(?:yes|Yes|YES|no|No|NO|true|True|TRUE" ~
|
||||||
"|false|False|FALSE|on|On|ON|off|Off|OFF)$"),
|
"|false|False|FALSE|on|On|ON|off|Off|OFF)$"),
|
||||||
"yYnNtTfFoO");
|
"yYnNtTfFoO");
|
||||||
addImplicitResolver("tag:yaml.org,2002:float",
|
addImplicitResolver("tag:yaml.org,2002:float",
|
||||||
regex(r"^(?:[-+]?([0-9][0-9_]*)\\.[0-9_]*"
|
regex(r"^(?:[-+]?([0-9][0-9_]*)\\.[0-9_]*" ~
|
||||||
"(?:[eE][-+][0-9]+)?|[-+]?(?:[0-9][0-9_]"
|
"(?:[eE][-+][0-9]+)?|[-+]?(?:[0-9][0-9_]" ~
|
||||||
"*)?\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?"
|
"*)?\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?" ~
|
||||||
"[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]"
|
"[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]" ~
|
||||||
"*|[-+]?\\.(?:inf|Inf|INF)|\\."
|
"*|[-+]?\\.(?:inf|Inf|INF)|\\." ~
|
||||||
"(?:nan|NaN|NAN))$"),
|
"(?:nan|NaN|NAN))$"),
|
||||||
"-+0123456789.");
|
"-+0123456789.");
|
||||||
addImplicitResolver("tag:yaml.org,2002:int",
|
addImplicitResolver("tag:yaml.org,2002:int",
|
||||||
regex(r"^(?:[-+]?0b[0-1_]+"
|
regex(r"^(?:[-+]?0b[0-1_]+" ~
|
||||||
"|[-+]?0[0-7_]+"
|
"|[-+]?0[0-7_]+" ~
|
||||||
"|[-+]?(?:0|[1-9][0-9_]*)"
|
"|[-+]?(?:0|[1-9][0-9_]*)" ~
|
||||||
"|[-+]?0x[0-9a-fA-F_]+"
|
"|[-+]?0x[0-9a-fA-F_]+" ~
|
||||||
"|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"),
|
"|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"),
|
||||||
"-+0123456789");
|
"-+0123456789");
|
||||||
addImplicitResolver("tag:yaml.org,2002:merge", regex(r"^<<$"), "<");
|
addImplicitResolver("tag:yaml.org,2002:merge", regex(r"^<<$"), "<");
|
||||||
addImplicitResolver("tag:yaml.org,2002:null",
|
addImplicitResolver("tag:yaml.org,2002:null",
|
||||||
regex(r"^$|^(?:~|null|Null|NULL)$"), "~nN\0");
|
regex(r"^$|^(?:~|null|Null|NULL)$"), "~nN\0");
|
||||||
addImplicitResolver("tag:yaml.org,2002:timestamp",
|
addImplicitResolver("tag:yaml.org,2002:timestamp",
|
||||||
regex(r"^[0-9][0-9][0-9][0-9]-[0-9][0-9]-"
|
regex(r"^[0-9][0-9][0-9][0-9]-[0-9][0-9]-" ~
|
||||||
"[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9]"
|
"[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9]" ~
|
||||||
"[0-9]?-[0-9][0-9]?[Tt]|[ \t]+[0-9]"
|
"[0-9]?-[0-9][0-9]?[Tt]|[ \t]+[0-9]" ~
|
||||||
"[0-9]?:[0-9][0-9]:[0-9][0-9]"
|
"[0-9]?:[0-9][0-9]:[0-9][0-9]" ~
|
||||||
"(?:\\.[0-9]*)?(?:[ \t]*Z|[-+][0-9]"
|
"(?:\\.[0-9]*)?(?:[ \t]*Z|[-+][0-9]" ~
|
||||||
"[0-9]?(?::[0-9][0-9])?)?$"),
|
"[0-9]?(?::[0-9][0-9])?)?$"),
|
||||||
"0123456789");
|
"0123456789");
|
||||||
addImplicitResolver("tag:yaml.org,2002:value", regex(r"^=$"), "=");
|
addImplicitResolver("tag:yaml.org,2002:value", regex(r"^=$"), "=");
|
||||||
|
|
|
@ -320,7 +320,7 @@ final class Scanner
|
||||||
default: if(checkPlain()) { return fetchPlain(); }
|
default: if(checkPlain()) { return fetchPlain(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ScannerException("While scanning for the next token, found character "
|
throw new ScannerException("While scanning for the next token, found character " ~
|
||||||
"\'%s\', index %s that cannot start any token"
|
"\'%s\', index %s that cannot start any token"
|
||||||
.format(c, to!int(c)), reader_.mark);
|
.format(c, to!int(c)), reader_.mark);
|
||||||
}
|
}
|
||||||
|
@ -368,7 +368,7 @@ final class Scanner
|
||||||
{
|
{
|
||||||
// Check if a simple key is required at the current position.
|
// Check if a simple key is required at the current position.
|
||||||
const required = (flowLevel_ == 0 && indent_ == reader_.column);
|
const required = (flowLevel_ == 0 && indent_ == reader_.column);
|
||||||
assert(allowSimpleKey_ || !required, "A simple key is required only if it is "
|
assert(allowSimpleKey_ || !required, "A simple key is required only if it is " ~
|
||||||
"the first token in the current line. Therefore it is always allowed.");
|
"the first token in the current line. Therefore it is always allowed.");
|
||||||
|
|
||||||
if(!allowSimpleKey_) { return; }
|
if(!allowSimpleKey_) { return; }
|
||||||
|
@ -1606,7 +1606,7 @@ final class Scanner
|
||||||
if(overflow)
|
if(overflow)
|
||||||
{
|
{
|
||||||
error("While scanning a double quoted scalar", startMark,
|
error("While scanning a double quoted scalar", startMark,
|
||||||
"overflow when parsing an escape sequence of "
|
"overflow when parsing an escape sequence of " ~
|
||||||
"hexadecimal numbers.", reader_.mark);
|
"hexadecimal numbers.", reader_.mark);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1773,7 +1773,7 @@ final class Scanner
|
||||||
reader_.sliceBuilder.finish();
|
reader_.sliceBuilder.finish();
|
||||||
reader_.forward(length);
|
reader_.forward(length);
|
||||||
error("While scanning a plain scalar", startMark,
|
error("While scanning a plain scalar", startMark,
|
||||||
"found unexpected ':' . Please check "
|
"found unexpected ':' . Please check " ~
|
||||||
"http://pyyaml.org/wiki/YAMLColonInFlowContext for details.",
|
"http://pyyaml.org/wiki/YAMLColonInFlowContext for details.",
|
||||||
reader_.mark);
|
reader_.mark);
|
||||||
return Token.init;
|
return Token.init;
|
||||||
|
@ -2015,7 +2015,7 @@ final class Scanner
|
||||||
const dchar c = reader_.peek(k);
|
const dchar c = reader_.peek(k);
|
||||||
if(!c.isHexDigit)
|
if(!c.isHexDigit)
|
||||||
{
|
{
|
||||||
auto msg = expected("URI escape sequence of 2 hexadecimal "
|
auto msg = expected("URI escape sequence of 2 hexadecimal " ~
|
||||||
"numbers", c);
|
"numbers", c);
|
||||||
error(contextMsg, startMark, msg, reader_.mark);
|
error(contextMsg, startMark, msg, reader_.mark);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,74 +1,136 @@
|
||||||
module dyaml.stream;
|
module dyaml.stream;
|
||||||
|
|
||||||
enum BOM {
|
enum BOM
|
||||||
UTF8, /// UTF-8
|
{
|
||||||
UTF16LE, /// UTF-16 Little Endian
|
UTF8, /// UTF-8
|
||||||
UTF16BE, /// UTF-16 Big Endian
|
UTF16LE, /// UTF-16 Little Endian
|
||||||
UTF32LE, /// UTF-32 Little Endian
|
UTF16BE, /// UTF-16 Big Endian
|
||||||
UTF32BE, /// UTF-32 Big Endian
|
UTF32LE, /// UTF-32 Little Endian
|
||||||
|
UTF32BE, /// UTF-32 Big Endian
|
||||||
}
|
}
|
||||||
|
|
||||||
import std.system;
|
import std.system;
|
||||||
|
|
||||||
private enum int NBOMS = 5;
|
private enum int NBOMS = 5;
|
||||||
immutable Endian[NBOMS] BOMEndian =
|
immutable Endian[NBOMS] BOMEndian =
|
||||||
[ std.system.endian,
|
[
|
||||||
Endian.littleEndian, Endian.bigEndian,
|
std.system.endian,
|
||||||
Endian.littleEndian, Endian.bigEndian
|
Endian.littleEndian, Endian.bigEndian,
|
||||||
];
|
Endian.littleEndian, Endian.bigEndian
|
||||||
|
];
|
||||||
|
|
||||||
immutable ubyte[][NBOMS] ByteOrderMarks =
|
immutable ubyte[][NBOMS] ByteOrderMarks =
|
||||||
[ [0xEF, 0xBB, 0xBF],
|
[
|
||||||
[0xFF, 0xFE],
|
[0xEF, 0xBB, 0xBF],
|
||||||
[0xFE, 0xFF],
|
[0xFF, 0xFE],
|
||||||
[0xFF, 0xFE, 0x00, 0x00],
|
[0xFE, 0xFF],
|
||||||
[0x00, 0x00, 0xFE, 0xFF]
|
[0xFF, 0xFE, 0x00, 0x00],
|
||||||
];
|
[0x00, 0x00, 0xFE, 0xFF]
|
||||||
|
];
|
||||||
|
|
||||||
interface YStream {
|
interface YStream
|
||||||
void writeExact(const void* buffer, size_t size);
|
{
|
||||||
size_t write(const(ubyte)[] buffer);
|
void writeExact(const void* buffer, size_t size);
|
||||||
void flush();
|
size_t write(const(ubyte)[] buffer);
|
||||||
@property bool writeable();
|
size_t write(const(char)[] str);
|
||||||
|
void flush();
|
||||||
|
@property bool writeable();
|
||||||
}
|
}
|
||||||
|
|
||||||
class YMemoryStream : YStream {
|
class YMemoryStream : YStream
|
||||||
ubyte[] data;
|
{
|
||||||
|
ubyte[] data;
|
||||||
|
|
||||||
void writeExact(const void* buffer, size_t size) {
|
void writeExact(const void* buffer, size_t size)
|
||||||
data ~= cast(ubyte[])buffer[0 .. size];
|
{
|
||||||
}
|
data ~= cast(ubyte[])buffer[0 .. size];
|
||||||
|
}
|
||||||
|
|
||||||
size_t write(const(ubyte)[] buffer) {
|
size_t write(const(ubyte)[] buffer)
|
||||||
data ~= buffer;
|
{
|
||||||
return buffer.length;
|
data ~= buffer;
|
||||||
}
|
return buffer.length;
|
||||||
|
}
|
||||||
|
|
||||||
void flush() {}
|
size_t write(const(char)[] str)
|
||||||
|
{
|
||||||
|
return write(cast(const(ubyte)[])str);
|
||||||
|
}
|
||||||
|
|
||||||
@property bool writeable() { return true; }
|
void flush() {}
|
||||||
|
|
||||||
|
@property bool writeable() { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
class YFile : YStream {
|
class YFile : YStream
|
||||||
static import std.stdio;
|
{
|
||||||
std.stdio.File file;
|
static import std.stdio;
|
||||||
|
std.stdio.File file;
|
||||||
|
|
||||||
this(string fn) {
|
this(string fn)
|
||||||
this.file = std.stdio.File(fn, "w");
|
{
|
||||||
}
|
this.file = std.stdio.File(fn, "w");
|
||||||
|
}
|
||||||
|
|
||||||
void writeExact(const void* buffer, size_t size) {
|
this(std.stdio.File file)
|
||||||
this.file.write(cast(const ubyte[])buffer[0 .. size]);
|
{
|
||||||
}
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
size_t write(const(ubyte)[] buffer) {
|
unittest
|
||||||
this.file.write(buffer);
|
{
|
||||||
return buffer.length;
|
import std.stdio : stdout;
|
||||||
}
|
auto stream = new YFile(stdout);
|
||||||
|
stream.write("Test writing to stdout through YFile stream\n");
|
||||||
|
}
|
||||||
|
|
||||||
void flush() {
|
void writeExact(const void* buffer, size_t size)
|
||||||
this.file.flush();
|
{
|
||||||
}
|
this.file.rawWrite(cast(const) buffer[0 .. size]);
|
||||||
|
}
|
||||||
|
|
||||||
@property bool writeable() { return true; }
|
size_t write(const(ubyte)[] buffer)
|
||||||
|
{
|
||||||
|
this.file.rawWrite(buffer);
|
||||||
|
return buffer.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const(char)[] str)
|
||||||
|
{
|
||||||
|
return write(cast(const(ubyte)[])str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush()
|
||||||
|
{
|
||||||
|
this.file.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@property bool writeable() { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
import dyaml.dumper, dyaml.loader, dyaml.node;
|
||||||
|
import std.file : readText, remove;
|
||||||
|
|
||||||
|
char[] test = ("Hello World : [Hello, World]\n" ~
|
||||||
|
"Answer: 42").dup;
|
||||||
|
//Read the input.
|
||||||
|
Node expected = Loader.fromString(test).load();
|
||||||
|
assert(expected["Hello World"][0] == "Hello");
|
||||||
|
assert(expected["Hello World"][1] == "World");
|
||||||
|
assert(expected["Answer"].as!int == 42);
|
||||||
|
|
||||||
|
//Dump the loaded document to output.yaml.
|
||||||
|
Dumper("output.yaml").dump(expected);
|
||||||
|
|
||||||
|
// Load the file and verify that it was saved correctly.
|
||||||
|
Node actual = Loader("output.yaml").load();
|
||||||
|
assert(actual["Hello World"][0] == "Hello");
|
||||||
|
assert(actual["Hello World"][1] == "World");
|
||||||
|
assert(actual["Answer"].as!int == 42);
|
||||||
|
assert(actual == expected);
|
||||||
|
|
||||||
|
// Clean up.
|
||||||
|
remove("output.yaml");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ struct ZeroString(string TypeName)
|
||||||
@disable int opCmp(ref ZeroString);
|
@disable int opCmp(ref ZeroString);
|
||||||
|
|
||||||
///Construct a string.
|
///Construct a string.
|
||||||
this(const string str) pure nothrow @safe
|
this(const string str) pure nothrow @trusted
|
||||||
{
|
{
|
||||||
if(str is null || str == "")
|
if(str is null || str == "")
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue