diff --git a/source/dyaml/composer.d b/source/dyaml/composer.d index a9da3d7..239093d 100644 --- a/source/dyaml/composer.d +++ b/source/dyaml/composer.d @@ -232,7 +232,7 @@ final class Composer } ///Compose a scalar node. - Node composeScalarNode() @system + Node composeScalarNode() @safe { immutable event = parser_.getEvent(); const tag = resolver_.resolve(NodeID.Scalar, event.tag, event.value, @@ -263,9 +263,7 @@ final class Composer nodeAppender.put(composeNode(pairAppenderLevel, nodeAppenderLevel + 1)); } - core.memory.GC.disable(); - scope(exit){core.memory.GC.enable();} - Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark, + Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark, tag, nodeAppender.data.dup, startEvent.collectionStyle); nodeAppender.clear(); @@ -286,7 +284,7 @@ final class Composer * Returns: Flattened mapping as pairs. */ Node.Pair[] flatten(ref Node root, const Mark startMark, const Mark endMark, - const uint pairAppenderLevel, const uint nodeAppenderLevel) @system + const uint pairAppenderLevel, const uint nodeAppenderLevel) @safe { void error(Node node) { @@ -306,11 +304,11 @@ final class Composer if(root.isMapping) { Node[] toMerge; + toMerge.reserve(root.length); foreach(ref Node key, ref Node value; root) { if(key.isType!YAMLMerge) { - toMerge.assumeSafeAppend(); toMerge ~= value; } else @@ -337,8 +335,6 @@ final class Composer error(root); } - core.memory.GC.disable(); - scope(exit){core.memory.GC.enable();} auto flattened = pairAppender.data.dup; pairAppender.clear(); @@ -381,9 +377,7 @@ final class Composer pairAppenderLevel + 1, nodeAppenderLevel)); } - core.memory.GC.disable(); - scope(exit){core.memory.GC.enable();} - Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark, + Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark, tag, pairAppender.data.dup, startEvent.collectionStyle); pairAppender.clear(); diff --git a/source/dyaml/constructor.d b/source/dyaml/constructor.d index ff1ddbe..63311a7 100644 --- a/source/dyaml/constructor.d +++ b/source/dyaml/constructor.d @@ -182,7 +182,6 @@ final class Constructor * -------------------- */ void addConstructorScalar(T)(const string tag, T function(ref Node) ctor) - @safe nothrow { const t = tag; auto deleg = addConstructor!T(t, ctor); @@ -233,7 +232,6 @@ final class Constructor * -------------------- */ void addConstructorSequence(T)(const string tag, T function(ref Node) ctor) - @safe nothrow { const t = tag; auto deleg = addConstructor!T(t, ctor); @@ -284,7 +282,6 @@ final class Constructor * -------------------- */ void addConstructorMapping(T)(const string tag, T function(ref Node) ctor) - @safe nothrow { const t = tag; auto deleg = addConstructor!T(t, ctor); @@ -346,7 +343,6 @@ final class Constructor * ctor = Constructor function. */ auto addConstructor(T)(const string tag, T function(ref Node) ctor) - @safe nothrow { assert((tag in fromScalar_) is null && (tag in fromSequence_) is null && @@ -363,7 +359,7 @@ final class Constructor } //Get the array of constructor functions for scalar, sequence or mapping. - @property auto delegates(T)() @safe pure nothrow @nogc + @property auto delegates(T)() { static if(is(T : string)) {return &fromScalar_;} else static if(is(T : Node[])) {return &fromSequence_;} @@ -397,7 +393,7 @@ bool constructBool(ref Node node) @safe } /// Construct an integer (long) _node. -long constructLong(ref Node node) +long constructLong(ref Node node) @safe { string value = node.as!string().replace("_", ""); const char c = value[0]; @@ -442,9 +438,9 @@ long constructLong(ref Node node) return result; } -unittest +@safe unittest { - long getLong(string str) + long getLong(string str) @safe { auto node = Node(str); return constructLong(node); @@ -466,7 +462,7 @@ unittest } /// Construct a floating point (real) _node. -real constructReal(ref Node node) +real constructReal(ref Node node) @safe { string value = node.as!string().replace("_", "").toLower(); const char c = value[0]; @@ -508,14 +504,14 @@ real constructReal(ref Node node) return result; } -unittest +@safe unittest { - bool eq(real a, real b, real epsilon = 0.2) + bool eq(real a, real b, real epsilon = 0.2) @safe { return a >= (b - epsilon) && a <= (b + epsilon); } - real getReal(string str) + real getReal(string str) @safe { auto node = Node(str); return constructReal(node); @@ -537,7 +533,7 @@ unittest } /// Construct a binary (base64) _node. -ubyte[] constructBinary(ref Node node) +ubyte[] constructBinary(ref Node node) @safe { import std.ascii : newline; import std.array : array; @@ -554,12 +550,12 @@ ubyte[] constructBinary(ref Node node) } } -unittest +@safe unittest { - ubyte[] test = cast(ubyte[])"The Answer: 42"; + auto test = "The Answer: 42".representation; char[] buffer; buffer.length = 256; - string input = cast(string)Base64.encode(test, buffer); + string input = Base64.encode(test, buffer).idup; auto node = Node(input); auto value = constructBinary(node); assert(value == test); @@ -567,7 +563,7 @@ unittest } /// Construct a timestamp (SysTime) _node. -SysTime constructTimestamp(ref Node node) +SysTime constructTimestamp(ref Node node) @safe { string value = node.as!string; @@ -639,7 +635,7 @@ SysTime constructTimestamp(ref Node node) assert(false, "This code should never be reached"); } -unittest +@safe unittest { writeln("D:YAML construction timestamp unittest"); @@ -669,23 +665,22 @@ unittest } /// Construct a string _node. -string constructString(ref Node node) +string constructString(ref Node node) @safe { return node.as!string; } /// Convert a sequence of single-element mappings into a sequence of pairs. -Node.Pair[] getPairs(string type, Node[] nodes) +Node.Pair[] getPairs(string type, Node[] nodes) @safe { Node.Pair[] pairs; - + pairs.reserve(nodes.length); foreach(ref node; nodes) { enforce(node.isMapping && node.length == 1, new Exception("While constructing " ~ type ~ ", expected a mapping with single element")); - pairs.assumeSafeAppend(); pairs ~= node.as!(Node.Pair[]); } @@ -693,14 +688,13 @@ Node.Pair[] getPairs(string type, Node[] nodes) } /// Construct an ordered map (ordered sequence of key:value pairs without duplicates) _node. -Node.Pair[] constructOrderedMap(ref Node node) +Node.Pair[] constructOrderedMap(ref Node node) @safe { auto pairs = getPairs("ordered map", node.as!(Node[])); //Detect duplicates. //TODO this should be replaced by something with deterministic memory allocation. auto keys = redBlackTree!Node(); - scope(exit){keys.destroy();} foreach(ref pair; pairs) { enforce(!(pair.key in keys), @@ -710,37 +704,35 @@ Node.Pair[] constructOrderedMap(ref Node node) } return pairs; } -unittest +@safe unittest { writeln("D:YAML construction ordered map unittest"); alias Node.Pair Pair; - Node[] alternateTypes(uint length) + Node[] alternateTypes(uint length) @safe { Node[] pairs; foreach(long i; 0 .. length) { auto pair = (i % 2) ? Pair(i.to!string, i) : Pair(i, i.to!string); - pairs.assumeSafeAppend(); pairs ~= Node([pair]); } return pairs; } - Node[] sameType(uint length) + Node[] sameType(uint length) @safe { Node[] pairs; foreach(long i; 0 .. length) { auto pair = Pair(i.to!string, i); - pairs.assumeSafeAppend(); pairs ~= Node([pair]); } return pairs; } - bool hasDuplicates(Node[] nodes) + bool hasDuplicates(Node[] nodes) @safe { auto node = Node(nodes); return null !is collectException(constructOrderedMap(node)); @@ -755,13 +747,13 @@ unittest } /// Construct a pairs (ordered sequence of key: value pairs allowing duplicates) _node. -Node.Pair[] constructPairs(ref Node node) +Node.Pair[] constructPairs(ref Node node) @safe { return getPairs("pairs", node.as!(Node[])); } /// Construct a set _node. -Node[] constructSet(ref Node node) +Node[] constructSet(ref Node node) @safe { auto pairs = node.as!(Node.Pair[]); @@ -769,28 +761,26 @@ Node[] constructSet(ref Node node) // memory allocation if possible. // Detect duplicates. ubyte[Node] map; - scope(exit){map.destroy();} Node[] nodes; + nodes.reserve(pairs.length); foreach(ref pair; pairs) { enforce((pair.key in map) is null, new Exception("Duplicate entry in a set")); map[pair.key] = 0; - nodes.assumeSafeAppend(); nodes ~= pair.key; } return nodes; } -unittest +@safe unittest { writeln("D:YAML construction set unittest"); - Node.Pair[] set(uint length) + Node.Pair[] set(uint length) @safe { Node.Pair[] pairs; foreach(long i; 0 .. length) { - pairs.assumeSafeAppend(); pairs ~= Node.Pair(i.to!string, YAMLNull()); } @@ -827,19 +817,18 @@ unittest } /// Construct a sequence (array) _node. -Node[] constructSequence(ref Node node) +Node[] constructSequence(ref Node node) @safe { return node.as!(Node[]); } /// Construct an unordered map (unordered set of key:value _pairs without duplicates) _node. -Node.Pair[] constructMap(ref Node node) +Node.Pair[] constructMap(ref Node node) @safe { auto pairs = node.as!(Node.Pair[]); //Detect duplicates. //TODO this should be replaced by something with deterministic memory allocation. auto keys = redBlackTree!Node(); - scope(exit){keys.destroy();} foreach(ref pair; pairs) { enforce(!(pair.key in keys), @@ -868,26 +857,26 @@ struct MyStruct } } -MyStruct constructMyStructScalar(ref Node node) +MyStruct constructMyStructScalar(ref Node node) @safe { // Guaranteed to be string as we construct from scalar. auto parts = node.as!string().split(":"); return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2])); } -MyStruct constructMyStructSequence(ref Node node) +MyStruct constructMyStructSequence(ref Node node) @safe { // node is guaranteed to be sequence. return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int); } -MyStruct constructMyStructMapping(ref Node node) +MyStruct constructMyStructMapping(ref Node node) @safe { // node is guaranteed to be mapping. return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int); } -unittest +@safe unittest { char[] data = "!mystruct 1:2:3".dup; auto loader = Loader(data); @@ -899,7 +888,7 @@ unittest assert(node.as!MyStruct == MyStruct(1, 2, 3)); } -unittest +@safe unittest { char[] data = "!mystruct [1, 2, 3]".dup; auto loader = Loader(data); @@ -911,7 +900,7 @@ unittest assert(node.as!MyStruct == MyStruct(1, 2, 3)); } -unittest +@safe unittest { char[] data = "!mystruct {x: 1, y: 2, z: 3}".dup; auto loader = Loader(data); diff --git a/source/dyaml/dumper.d b/source/dyaml/dumper.d index 47fb463..752f885 100644 --- a/source/dyaml/dumper.d +++ b/source/dyaml/dumper.d @@ -80,28 +80,28 @@ import dyaml.tagdirective; */ struct Dumper { - unittest + @safe unittest { auto node = Node([1, 2, 3, 4, 5]); Dumper(new YMemoryStream()).dump(node); } - - unittest + + @safe unittest { auto node1 = Node([1, 2, 3, 4, 5]); auto node2 = Node("This document contains only one string"); Dumper(new YMemoryStream()).dump(node1, node2); } - - unittest + + @safe unittest { //import std.stream; auto stream = new YMemoryStream(); auto node = Node([1, 2, 3, 4, 5]); Dumper(stream).dump(node); } - - unittest + + @safe unittest { auto node = Node([1, 2, 3, 4, 5]); auto representer = new Representer(); @@ -157,7 +157,7 @@ struct Dumper * * Throws: YAMLException if the file can not be dumped to (e.g. cannot be opened). */ - this(string filename) @trusted + this(string filename) @safe { name_ = filename; //try{this(new File(filename, FileMode.OutNew));} @@ -183,7 +183,6 @@ struct Dumper ///Destroy the Dumper. @trusted ~this() { - YAMLVersion_ = null; if(weOwnStream_) { destroy(stream_); } } @@ -194,16 +193,14 @@ struct Dumper } ///Specify custom Resolver to use. - @property void resolver(Resolver resolver) @trusted + @property void resolver(Resolver resolver) @safe { - resolver_.destroy(); resolver_ = resolver; } ///Specify custom Representer to use. - @property void representer(Representer representer) @trusted + @property void representer(Representer representer) @safe { - representer_.destroy(); representer_ = representer; } @@ -290,7 +287,7 @@ struct Dumper * dumper.dump(Node("foo")); * -------------------- */ - @property void tagDirectives(string[string] tags) pure @trusted + @property void tagDirectives(string[string] tags) pure @safe { TagDirective[] t; foreach(handle, prefix; tags) diff --git a/source/dyaml/emitter.d b/source/dyaml/emitter.d index d96320c..f64f77e 100644 --- a/source/dyaml/emitter.d +++ b/source/dyaml/emitter.d @@ -184,21 +184,6 @@ struct Emitter analysis_.flags.isNull = true; } - ///Destroy the emitter. - @trusted ~this() - { - stream_ = null; - states_.destroy(); - events_.destroy(); - indents_.destroy(); - tagDirectives_.destroy(); - tagDirectives_ = null; - preparedAnchor_.destroy(); - preparedAnchor_ = null; - preparedTag_.destroy(); - preparedTag_ = null; - } - ///Emit an event. Throws EmitterException on error. void emit(Event event) @trusted { @@ -237,20 +222,20 @@ struct Emitter } ///Write a string to the file/stream. - void writeString(const string str) @system + void writeString(const char[] str) @safe { try final switch(encoding_) { case Encoding.UTF_8: - stream_.writeExact(str.ptr, str.length * char.sizeof); + stream_.writeExact(str); break; case Encoding.UTF_16: const buffer = to!wstring(str); - stream_.writeExact(buffer.ptr, buffer.length * wchar.sizeof); + stream_.writeExact(buffer); break; case Encoding.UTF_32: const buffer = to!dstring(str); - stream_.writeExact(buffer.ptr, buffer.length * dchar.sizeof); + stream_.writeExact(buffer); break; } catch(Exception e) @@ -260,7 +245,7 @@ struct Emitter } ///In some cases, we wait for a few next events before emitting. - bool needMoreEvents() @trusted nothrow + bool needMoreEvents() @safe nothrow { if(events_.length == 0){return true;} @@ -273,7 +258,7 @@ struct Emitter } ///Determines if we need specified number of more events. - bool needEvents(in uint count) @system nothrow + bool needEvents(in uint count) @safe nothrow { int level = 0; @@ -315,7 +300,7 @@ struct Emitter } ///Determines if the type of current event is as specified. Throws if no event. - bool eventTypeIs(in EventID id) const pure @trusted + bool eventTypeIs(in EventID id) const pure @safe { enforce(!event_.isNull, new Error("Expected an event, but no event is available.")); @@ -340,7 +325,7 @@ struct Emitter } ///Expect nothing, throwing if we still have something. - void expectNothing() const @trusted + void expectNothing() const @safe { throw new Error("Expected nothing, but got " ~ event_.idString); } @@ -452,7 +437,7 @@ struct Emitter } ///Handle a new node. Context specifies where in the document we are. - void expectNode(const Context context) @trusted + void expectNode(const Context context) @safe { context_ = context; @@ -504,7 +489,7 @@ struct Emitter } ///Handle a scalar. - void expectScalar() @trusted + void expectScalar() @safe { increaseIndent(Yes.flow); processScalar(); @@ -835,7 +820,7 @@ struct Emitter } ///Determine style to write the current scalar in. - ScalarStyle chooseScalarStyle() @trusted + ScalarStyle chooseScalarStyle() @safe { if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);} @@ -878,7 +863,7 @@ struct Emitter } ///Prepare YAML version string for output. - static string prepareVersion(const string YAMLVersion) @trusted + static string prepareVersion(const string YAMLVersion) @safe { enforce(YAMLVersion.split(".")[0] == "1", new Error("Unsupported YAML version: " ~ YAMLVersion)); @@ -886,7 +871,7 @@ struct Emitter } ///Encode an Unicode character for tag directive and write it to writer. - static void encodeChar(Writer)(ref Writer writer, in dchar c) @trusted + static void encodeChar(Writer)(ref Writer writer, in dchar c) @safe { char[4] data; const bytes = encode(data, c); @@ -898,7 +883,7 @@ struct Emitter } ///Prepare tag directive handle for output. - static string prepareTagHandle(const string handle) @trusted + static string prepareTagHandle(const string handle) @safe { enforce(handle !is null && handle != "", new Error("Tag handle must not be empty")); @@ -913,7 +898,7 @@ struct Emitter } ///Prepare tag directive prefix for output. - static string prepareTagPrefix(const string prefix) @trusted + static string prepareTagPrefix(const string prefix) @safe { enforce(prefix !is null && prefix != "", new Error("Tag prefix must not be empty")); @@ -944,7 +929,7 @@ struct Emitter } ///Prepare tag for output. - string prepareTag(in string tag) @trusted + string prepareTag(in string tag) @safe { enforce(tag !is null, new Error("Tag must not be empty")); @@ -991,7 +976,7 @@ struct Emitter } ///Prepare anchor for output. - static string prepareAnchor(const string anchor) @trusted + static string prepareAnchor(const string anchor) @safe { enforce(anchor != "", new Error("Anchor must not be empty")); @@ -1172,7 +1157,7 @@ struct Emitter //Writers. ///Start the YAML stream (write the unicode byte order mark). - void writeStreamStart() @system + void writeStreamStart() @safe { immutable(ubyte)[] bom; //Write BOM (except for UTF-8) @@ -1196,13 +1181,13 @@ struct Emitter } ///End the YAML stream. - void writeStreamEnd() @system {stream_.flush();} + void writeStreamEnd() @safe {stream_.flush();} ///Write an indicator (e.g. ":", "[", ">", etc.). - void writeIndicator(const string indicator, - const Flag!"needWhitespace" needWhitespace, + void writeIndicator(const char[] indicator, + const Flag!"needWhitespace" needWhitespace, const Flag!"whitespace" whitespace = No.whitespace, - const Flag!"indentation" indentation = No.indentation) @system + const Flag!"indentation" indentation = No.indentation) @safe { const bool prefixSpace = !whitespace_ && needWhitespace; whitespace_ = whitespace; @@ -1218,7 +1203,7 @@ struct Emitter } ///Write indentation. - void writeIndent() @system + void writeIndent() @safe { const indent = indent_ == -1 ? 0 : indent_; @@ -1244,7 +1229,7 @@ struct Emitter } ///Start new line. - void writeLineBreak(const string data = null) @system + void writeLineBreak(const char[] data = null) @safe { whitespace_ = indentation_ = true; ++line_; @@ -1253,7 +1238,7 @@ struct Emitter } ///Write a YAML version directive. - void writeVersionDirective(const string versionText) @system + void writeVersionDirective(const string versionText) @safe { writeString("%YAML "); writeString(versionText); @@ -1261,7 +1246,7 @@ struct Emitter } ///Write a tag directive. - void writeTagDirective(const string handle, const string prefix) @system + void writeTagDirective(const string handle, const string prefix) @safe { writeString("%TAG "); writeString(handle); @@ -1319,14 +1304,8 @@ struct ScalarWriter split_ = split; } - ///Destroy the ScalarWriter. - @trusted nothrow ~this() - { - text_ = null; - } - ///Write text as single quoted scalar. - void writeSingleQuoted() @system + void writeSingleQuoted() @safe { emitter_.writeIndicator("\'", Yes.needWhitespace); spaces_ = breaks_ = false; @@ -1376,7 +1355,7 @@ struct ScalarWriter } ///Write text as double quoted scalar. - void writeDoubleQuoted() @system + void writeDoubleQuoted() @safe { resetTextPosition(); emitter_.writeIndicator("\"", Yes.needWhitespace); @@ -1438,7 +1417,7 @@ struct ScalarWriter } ///Write text as folded block scalar. - void writeFolded() @system + void writeFolded() @safe { initBlock('>'); bool leadingSpace = true; @@ -1484,7 +1463,7 @@ struct ScalarWriter } ///Write text as literal block scalar. - void writeLiteral() @system + void writeLiteral() @safe { initBlock('|'); breaks_ = true; @@ -1511,7 +1490,7 @@ struct ScalarWriter } ///Write text as plain scalar. - void writePlain() @system + void writePlain() @safe { if(emitter_.context_ == Emitter.Context.Root){emitter_.openEnded_ = true;} if(text_ == ""){return;} @@ -1588,7 +1567,7 @@ struct ScalarWriter } ///Determine hints (indicators) for block scalar. - size_t determineBlockHints(char[] hints, uint bestIndent) const pure @trusted + size_t determineBlockHints(char[] hints, uint bestIndent) const pure @safe { size_t hintsIdx = 0; if(text_.length == 0){return hintsIdx;} @@ -1619,12 +1598,12 @@ struct ScalarWriter } ///Initialize for block scalar writing with specified indicator. - void initBlock(const char indicator) @system + void initBlock(const char indicator) @safe { char[4] hints; hints[0] = indicator; const hintsLength = 1 + determineBlockHints(hints[1 .. $], emitter_.bestIndent_); - emitter_.writeIndicator(cast(string)hints[0 .. hintsLength], Yes.needWhitespace); + emitter_.writeIndicator(hints[0 .. hintsLength], Yes.needWhitespace); if(hints.length > 0 && hints[$ - 1] == '+') { emitter_.openEnded_ = true; @@ -1633,7 +1612,7 @@ struct ScalarWriter } ///Write out the current text range. - void writeCurrentRange(const Flag!"UpdateColumn" updateColumn) @system + void writeCurrentRange(const Flag!"UpdateColumn" updateColumn) @safe { emitter_.writeString(text_[startByte_ .. endByte_]); if(updateColumn){emitter_.column_ += endChar_ - startChar_;} @@ -1641,7 +1620,7 @@ struct ScalarWriter } ///Write line breaks in the text range. - void writeLineBreaks() @system + void writeLineBreaks() @safe { foreach(const dchar br; text_[startByte_ .. endByte_]) { @@ -1650,20 +1629,20 @@ struct ScalarWriter { char[4] brString; const bytes = encode(brString, br); - emitter_.writeLineBreak(cast(string)brString[0 .. bytes]); + emitter_.writeLineBreak(brString[0 .. bytes]); } } updateRangeStart(); } ///Write line break if start of the text range is a newline. - void writeStartLineBreak() @system + void writeStartLineBreak() @safe { if(charAtStart == '\n'){emitter_.writeLineBreak();} } ///Write indentation, optionally resetting whitespace/indentation flags. - void writeIndent(const Flag!"ResetSpace" resetSpace) @system + void writeIndent(const Flag!"ResetSpace" resetSpace) @safe { emitter_.writeIndent(); if(resetSpace) @@ -1680,7 +1659,7 @@ struct ScalarWriter } ///Update the line breaks_ flag, optionally updating the spaces_ flag. - void updateBreaks(in dchar c, const Flag!"UpdateSpaces" updateSpaces) pure @trusted + void updateBreaks(in dchar c, const Flag!"UpdateSpaces" updateSpaces) pure @safe { if(c == dcharNone){return;} breaks_ = newlineSearch_.canFind(c); diff --git a/source/dyaml/event.d b/source/dyaml/event.d index dac8492..7be2443 100644 --- a/source/dyaml/event.d +++ b/source/dyaml/event.d @@ -89,10 +89,10 @@ struct Event CollectionStyle collectionStyle = CollectionStyle.Invalid; ///Is this a null (uninitialized) event? - @property bool isNull() const pure @system nothrow {return id == EventID.Invalid;} + @property bool isNull() const pure @safe nothrow {return id == EventID.Invalid;} ///Get string representation of the token ID. - @property string idString() const @system {return to!string(id);} + @property string idString() const @safe {return to!string(id);} static assert(Event.sizeof <= 64, "Event struct larger than expected"); } @@ -105,7 +105,7 @@ struct Event * anchor = Anchor, if this is an alias event. */ Event event(EventID id)(const Mark start, const Mark end, const string anchor = null) - pure @trusted nothrow + @trusted { Event result; result.startMark = start; @@ -149,7 +149,7 @@ Event collectionStartEvent(EventID id) * encoding = Encoding of the stream. */ Event streamStartEvent(const Mark start, const Mark end, const Encoding encoding) - pure @trusted nothrow + pure @safe nothrow { Event result; result.startMark = start; @@ -198,7 +198,7 @@ Event documentStartEvent(const Mark start, const Mark end, const bool explicit, * end = End position of the event in the file/stream. * explicit = Is this an explicit document end? */ -Event documentEndEvent(const Mark start, const Mark end, const bool explicit) pure @trusted nothrow +Event documentEndEvent(const Mark start, const Mark end, const bool explicit) pure @safe nothrow { Event result; result.startMark = start; @@ -219,17 +219,15 @@ Event documentEndEvent(const Mark start, const Mark end, const bool explicit) pu /// style = Scalar style. Event scalarEvent(const Mark start, const Mark end, const string anchor, const string tag, const Tuple!(bool, bool) implicit, const string value, - const ScalarStyle style = ScalarStyle.Invalid) @safe pure nothrow @nogc + const ScalarStyle style = ScalarStyle.Invalid) @trusted pure nothrow @nogc { Event result; result.value = value; result.startMark = start; result.endMark = end; - () @trusted { - result.anchor = anchor; - result.tag = tag; - }(); + result.anchor = anchor; + result.tag = tag; result.id = EventID.Scalar; result.scalarStyle = style; diff --git a/source/dyaml/fastcharsearch.d b/source/dyaml/fastcharsearch.d index 8aa1c60..80e9687 100644 --- a/source/dyaml/fastcharsearch.d +++ b/source/dyaml/fastcharsearch.d @@ -35,7 +35,7 @@ template FastCharSearch(dstring chars, uint tableSize = 256) } /// Generate the search table and the canFind method. -string searchCode(dstring chars, uint tableSize)() @safe pure //nothrow +string searchCode(dstring chars, uint tableSize)() { import std.string; @@ -87,3 +87,9 @@ string searchCode(dstring chars, uint tableSize)() @safe pure //nothrow return code; } + +@safe unittest +{ + mixin FastCharSearch!("+", 128) search; + assert(search.canFind('+')); +} diff --git a/source/dyaml/flags.d b/source/dyaml/flags.d index 7d03bb1..9287360 100644 --- a/source/dyaml/flags.d +++ b/source/dyaml/flags.d @@ -72,7 +72,7 @@ struct Flags(names ...) if(names.length <= 8) ///Flag accessors. mixin(flags(names)); } -unittest +@safe unittest { import std.stdio; writeln("Flags unittest"); diff --git a/source/dyaml/hacks.d b/source/dyaml/hacks.d index 8ddbb8d..8f4a539 100644 --- a/source/dyaml/hacks.d +++ b/source/dyaml/hacks.d @@ -39,7 +39,7 @@ ScalarStyle scalarStyleHack(ref const(Node) node) @safe nothrow assert(node.isScalar, "Trying to get scalar style of a non-scalar node"); return node.scalarStyle; } -unittest +@safe unittest { writeln("D:YAML scalarStyleHack getter unittest"); auto node = Node(5); @@ -57,7 +57,7 @@ CollectionStyle collectionStyleHack(ref const(Node) node) @safe nothrow assert(!node.isScalar, "Trying to get collection style of a scalar node"); return node.collectionStyle; } -unittest +@safe unittest { writeln("D:YAML collectionStyleHack getter unittest"); auto node = Node([1, 2, 3, 4, 5]); @@ -77,7 +77,7 @@ void scalarStyleHack(ref Node node, const ScalarStyle rhs) @safe nothrow node.scalarStyle = rhs; } /// -unittest +@safe unittest { writeln("D:YAML scalarStyleHack setter unittest"); auto node = Node(5); @@ -97,7 +97,7 @@ void collectionStyleHack(ref Node node, const CollectionStyle rhs) @safe nothrow node.collectionStyle = rhs; } /// -unittest +@safe unittest { writeln("D:YAML collectionStyleHack setter unittest"); auto node = Node([1, 2, 3, 4, 5]); diff --git a/source/dyaml/loader.d b/source/dyaml/loader.d index 33ae4db..1a181a8 100644 --- a/source/dyaml/loader.d +++ b/source/dyaml/loader.d @@ -157,9 +157,9 @@ struct Loader return Loader(cast(ubyte[])data); } /// - unittest + @safe unittest { - assert(Loader.fromString(cast(char[])"42").load().as!int == 42); + assert(Loader.fromString("42".dup).load().as!int == 42); } /** Construct a Loader to load YAML from a buffer. @@ -265,12 +265,11 @@ struct Loader * * Throws: YAMLException on a parsing error. */ - Node[] loadAll() @trusted + Node[] loadAll() @safe { Node[] nodes; - foreach(ref node; this) + foreach(ref node; this) { - nodes.assumeSafeAppend(); nodes ~= node; } return nodes; @@ -316,14 +315,13 @@ struct Loader package: // Scan and return all tokens. Used for debugging. - Token[] scan() @trusted + Token[] scan() @safe { try { Token[] result; while(scanner_.checkToken()) { - result.assumeSafeAppend(); result ~= scanner_.getToken(); } return result; @@ -378,7 +376,7 @@ struct Loader } } -unittest +@safe unittest { char[] yaml_input = ("red: '#ff0000'\n" ~ "green: '#00ff00'\n" ~ diff --git a/source/dyaml/node.d b/source/dyaml/node.d index 8f950f5..23cabed 100644 --- a/source/dyaml/node.d +++ b/source/dyaml/node.d @@ -112,7 +112,7 @@ package class YAMLContainer(T) if (!Node.allowed!T): YAMLObject private: // Construct a YAMLContainer holding specified value. - this(T value) @trusted {value_ = value;} + this(T value) @safe {value_ = value;} } @@ -127,7 +127,7 @@ private struct Pair public: /// Construct a Pair from two values. Will be converted to Nodes if needed. - this(K, V)(K key, V value) @safe + this(K, V)(K key, V value) { static if(is(Unqual!K == Node)){this.key = key;} else {this.key = Node(key);} @@ -265,7 +265,7 @@ struct Node } /// Ditto. // Overload for types where we can make this nothrow. - this(T)(T value, const string tag = null) @trusted pure nothrow + this(T)(T value, const string tag = null) @trusted if(scalarCtorNothrow!T) { tag_ = tag; @@ -276,7 +276,7 @@ struct Node // User defined type or plain string. else { value_ = Value(value);} } - unittest + @safe unittest { { auto node = Node(42); @@ -343,7 +343,7 @@ struct Node value_ = Value(nodes); } } - unittest + @safe unittest { with(Node([1, 2, 3])) { @@ -393,7 +393,7 @@ struct Node foreach(key, ref value; array){pairs ~= Pair(key, value);} value_ = Value(pairs); } - unittest + @safe unittest { int[string] aa; aa["1"] = 1; @@ -465,7 +465,7 @@ struct Node foreach(i; 0 .. keys.length){pairs ~= Pair(keys[i], values[i]);} value_ = Value(pairs); } - unittest + @safe unittest { with(Node(["1", "2"], [1, 2])) { @@ -535,12 +535,12 @@ struct Node * * Returns: true if equal, false otherwise. */ - bool opEquals(T)(const auto ref T rhs) const @safe + bool opEquals(T)(const auto ref T rhs) const { return equals!(Yes.useTag)(rhs); } /// - unittest + @safe unittest { auto node = Node(42); @@ -671,7 +671,7 @@ struct Node } assert(false, "This code should never be reached"); } - unittest + @safe unittest { assertThrown!NodeException(Node("42").get!int); Node(YAMLNull()).get!YAMLNull; @@ -807,7 +807,7 @@ struct Node throw new Error("Trying to index a " ~ nodeTypeString ~ " node", startMark_); } /// - unittest + @safe unittest { writeln("D:YAML Node opIndex unittest"); alias Node.Value Value; @@ -821,7 +821,7 @@ struct Node assert(nmap["11"].as!int == 11); assert(nmap["14"].as!int == 14); } - unittest + @safe unittest { writeln("D:YAML Node opIndex unittest"); alias Node.Value Value; @@ -856,7 +856,7 @@ struct Node * * Throws: NodeException if the node is not a collection. */ - bool contains(T)(T rhs) const @safe + bool contains(T)(T rhs) const { return contains_!(T, No.key, "contains")(rhs); } @@ -870,13 +870,13 @@ struct Node * * Throws: NodeException if the node is not a mapping. */ - bool containsKey(T)(T rhs) const @safe + bool containsKey(T)(T rhs) const { return contains_!(T, Yes.key, "containsKey")(rhs); } // Unittest for contains() and containsKey(). - unittest + @safe unittest { writeln("D:YAML Node contains/containsKey unittest"); auto seq = Node([1, 2, 3, 4, 5]); @@ -946,7 +946,7 @@ struct Node collectionStyle = rhs.collectionStyle; } // Unittest for opAssign(). - unittest + @safe unittest { auto seq = Node([1, 2, 3, 4, 5]); auto assigned = seq; @@ -1007,7 +1007,7 @@ struct Node throw new Error("Trying to index a " ~ nodeTypeString ~ " node", startMark_); } - unittest + @safe unittest { writeln("D:YAML Node opIndexAssign unittest"); @@ -1048,7 +1048,7 @@ struct Node * Throws: NodeException if the node is not a sequence or an element * could not be converted to specified type. */ - auto sequence(T = Node)() @trusted + auto sequence(T = Node)() { enforce(isSequence, new Error("Trying to 'sequence'-iterate over a " ~ nodeTypeString ~ " node", @@ -1118,7 +1118,7 @@ struct Node } return Range(get!(Node[])); } - unittest + @safe unittest { writeln("D:YAML Node sequence unittest"); @@ -1137,56 +1137,56 @@ struct Node * Throws: NodeException if the node is not a mapping. * */ - auto mapping() @trusted + auto mapping() @safe { enforce(isMapping, - new Error("Trying to 'mapping'-iterate over a " + new Error("Trying to 'mapping'-iterate over a " ~ nodeTypeString ~ " node", startMark_)); struct Range { Node.Pair[] pairs; size_t position; - this(Node.Pair[] pairs) + this(Node.Pair[] pairs) @safe { this.pairs = pairs; position = 0; } /* Input range functionality. */ - bool empty() { return position >= pairs.length; } + bool empty() @safe { return position >= pairs.length; } - void popFront() - { + void popFront() @safe + { enforce(!empty, "Attempted to popFront an empty mapping"); - position++; + position++; } - Pair front() - { + Pair front() @safe + { enforce(!empty, "Attempted to take the front of an empty mapping"); - return pairs[position]; + return pairs[position]; } /* Forward range functionality. */ - Range save() { return this; } + Range save() @safe { return this; } /* Bidirectional range functionality. */ - void popBack() - { + void popBack() @safe + { enforce(!empty, "Attempted to popBack an empty mapping"); - pairs = pairs[0 .. $ - 1]; + pairs = pairs[0 .. $ - 1]; } - Pair back() - { + Pair back() @safe + { enforce(!empty, "Attempted to take the back of an empty mapping"); - return pairs[$ - 1]; + return pairs[$ - 1]; } /* Random-access range functionality. */ - size_t length() const @property { return pairs.length; } - Pair opIndex(size_t index) { return pairs[index]; } + size_t length() const @property @safe { return pairs.length; } + Pair opIndex(size_t index) @safe { return pairs[index]; } static assert(isInputRange!Range); static assert(isForwardRange!Range); @@ -1195,7 +1195,7 @@ struct Node } return Range(get!(Node.Pair[])); } - unittest + @safe unittest { writeln("D:YAML Node mapping unittest"); @@ -1222,7 +1222,7 @@ struct Node * Throws: NodeException if the nodes is not a mapping or an element * could not be converted to specified type. */ - auto mappingKeys(K = Node)() @trusted + auto mappingKeys(K = Node)() { enforce(isMapping, new Error("Trying to 'mappingKeys'-iterate over a " @@ -1232,7 +1232,7 @@ struct Node else return mapping.map!(pair => pair.key.as!K); } - unittest + @safe unittest { writeln("D:YAML Node mappingKeys unittest"); @@ -1252,7 +1252,7 @@ struct Node * Throws: NodeException if the nodes is not a mapping or an element * could not be converted to specified type. */ - auto mappingValues(V = Node)() @trusted + auto mappingValues(V = Node)() { enforce(isMapping, new Error("Trying to 'mappingValues'-iterate over a " @@ -1262,7 +1262,7 @@ struct Node else return mapping.map!(pair => pair.value.as!V); } - unittest + @safe unittest { writeln("D:YAML Node mappingValues unittest"); @@ -1304,7 +1304,7 @@ struct Node } return result; } - unittest + @system unittest { writeln("D:YAML Node opApply unittest 1"); @@ -1372,7 +1372,7 @@ struct Node } return result; } - unittest + @safe unittest { writeln("D:YAML Node opApply unittest 2"); @@ -1447,7 +1447,7 @@ struct Node else {nodes ~= Node(value);} value_ = Value(nodes); } - unittest + @safe unittest { writeln("D:YAML Node add unittest 1"); @@ -1484,7 +1484,7 @@ struct Node pairs ~= Pair(key, value); value_ = Value(pairs); } - unittest + @safe unittest { writeln("D:YAML Node add unittest 2"); with(Node([1, 2], [3, 4])) @@ -1508,7 +1508,7 @@ struct Node * * See_Also: contains */ - Node* opBinaryRight(string op, K)(K key) @system + Node* opBinaryRight(string op, K)(K key) if (op == "in") { enforce(isMapping, new Error("Trying to use 'in' on a " ~ @@ -1524,7 +1524,7 @@ struct Node return &(get!(Node.Pair[])[idx].value); } } - unittest + @safe unittest { writeln(`D:YAML Node opBinaryRight!"in" unittest`); auto mapping = Node(["foo", "baz"], ["bar", "qux"]); @@ -1553,7 +1553,7 @@ struct Node { remove_!(T, No.key, "remove")(rhs); } - unittest + @safe unittest { writeln("D:YAML Node remove unittest"); with(Node([1, 2, 3, 4, 3])) @@ -1601,7 +1601,7 @@ struct Node { remove_!(T, Yes.key, "removeAt")(index); } - unittest + @safe unittest { writeln("D:YAML Node removeAt unittest"); with(Node([1, 2, 3, 4, 3])) @@ -1632,13 +1632,13 @@ struct Node } // Compute hash of the node. - hash_t toHash() nothrow const + hash_t toHash() nothrow const @trusted { - const tagHash = (tag_ is null) ? 0 : tag_.hashOf(); - // Variant toHash is not const at the moment, so we need to const-cast. - return tagHash + value_.toHash(); + const valueHash = value_.toHash(); + + return tag_ is null ? valueHash : tag_.hashOf(valueHash); } - unittest + @safe unittest { writeln("Node(42).toHash(): ", Node(42).toHash()); } @@ -1668,13 +1668,13 @@ struct Node } // Construct Node.Value from user defined type. - static Value userValue(T)(T value) @trusted nothrow + static Value userValue(T)(T value) @trusted { return Value(cast(YAMLObject)new YAMLContainer!T(value)); } // Construct Node.Value from a type it can store directly (after casting if needed) - static Value value(T)(T value) @system nothrow if(allowed!T) + static Value value(T)(T value) if(allowed!T) { static if(Value.allowed!T) { @@ -1702,7 +1702,7 @@ struct Node // 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 + bool equals(Flag!"useTag" useTag, T)(ref T rhs) const { static if(is(Unqual!T == Node)) { @@ -1843,7 +1843,7 @@ struct Node // Params: level = Level of the node in the tree. // // Returns: String representing the node tree. - @property string debugString(uint level = 0) @trusted + @property string debugString(uint level = 0) @safe { string indent; foreach(i; 0 .. level){indent ~= " ";} @@ -1879,17 +1879,16 @@ struct Node } // Get type of the node value (YAMLObject for user types). - @property TypeInfo type() const @trusted nothrow + @property TypeInfo type() const @safe nothrow { - alias TypeInfo delegate() const nothrow nothrowType; - return (cast(nothrowType)&value_.type)(); + return value_.type; } public: // 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 + @property bool isType(T)() const { return this.type is typeid(Unqual!T); } @@ -1928,7 +1927,7 @@ struct Node } // Determine if the value can be converted to specified type. - @property bool convertsTo(T)() const @safe nothrow + @property bool convertsTo(T)() const { if(isType!T){return true;} @@ -1963,7 +1962,7 @@ struct Node } // Implementation of remove() and removeAt() - void remove_(T, Flag!"key" key, string func)(T rhs) @system + void remove_(T, Flag!"key" key, string func)(T rhs) { enforce(isSequence || isMapping, new Error("Trying to " ~ func ~ "() from a " ~ nodeTypeString ~ " node", @@ -2083,7 +2082,7 @@ package: // // Params: pairs = Appender managing the array of pairs to merge into. // toMerge = Pair to merge. -void merge(ref Appender!(Node.Pair[]) pairs, ref Node.Pair toMerge) @trusted +void merge(ref Appender!(Node.Pair[]) pairs, ref Node.Pair toMerge) @safe { foreach(ref pair; pairs.data) { @@ -2099,7 +2098,7 @@ void merge(ref Appender!(Node.Pair[]) pairs, ref Node.Pair toMerge) @trusted // // Params: pairs = Appender managing the array of pairs to merge into. // toMerge = Pairs to merge. -void merge(ref Appender!(Node.Pair[]) pairs, Node.Pair[] toMerge) @trusted +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;} diff --git a/source/dyaml/nogcutil.d b/source/dyaml/nogcutil.d index d907bbc..85ae430 100644 --- a/source/dyaml/nogcutil.d +++ b/source/dyaml/nogcutil.d @@ -143,7 +143,7 @@ struct AppenderNoGCFixed(A : T[], T) /// Construct an appender that will work with given buffer. /// /// Data written to the appender will overwrite the buffer from the start. - this(T[] arr) @trusted pure nothrow + this(T[] arr) @safe pure nothrow { // initialize to a given array. _data.arr = cast(Unqual!T[])arr[0 .. 0]; //trusted @@ -163,11 +163,8 @@ struct AppenderNoGCFixed(A : T[], T) /** * Returns the managed array. */ - @property inout(T)[] data() inout @trusted pure nothrow + @property inout(T)[] data() inout @safe pure nothrow { - /* @trusted operation: - * casting Unqual!T[] to inout(T)[] - */ return cast(typeof(return))(_data.arr); } @@ -217,7 +214,7 @@ struct AppenderNoGCFixed(A : T[], T) @disable void clear(); } } -unittest +@safe unittest { char[256] buffer; auto appender = appenderNoGC(buffer[]); @@ -245,7 +242,7 @@ struct ValidateResult /// Validate a UTF-8 string, checking if it is well-formed Unicode. /// /// See_Also: ValidateResult -ValidateResult validateUTF8NoGC(const(char[]) str) @trusted pure nothrow @nogc +ValidateResult validateUTF8NoGC(const(char[]) str) @safe pure nothrow @nogc { immutable len = str.length; size_t characterCount; @@ -289,7 +286,6 @@ ValidateResult validateUTF8NoGC(const(char[]) str) @trusted pure nothrow @nogc /// 'string errorMessage' member that is null on success and otherwise stores /// the error message. auto decodeUTF8NoGC(Flag!"validated" validated)(const(char[]) str, ref size_t index) - @trusted pure nothrow @nogc { static if(!validated) struct Result { @@ -301,7 +297,7 @@ auto decodeUTF8NoGC(Flag!"validated" validated)(const(char[]) str, ref size_t in /// Dchar bitmask for different numbers of UTF-8 code units. enum bitMask = tuple((1 << 7) - 1, (1 << 11) - 1, (1 << 16) - 1, (1 << 21) - 1); - auto pstr = str.ptr + index; + auto pstr = str[index..$]; immutable length = str.length - index; ubyte fst = pstr[0]; diff --git a/source/dyaml/parser.d b/source/dyaml/parser.d index 710dcd8..d7fecfc 100644 --- a/source/dyaml/parser.d +++ b/source/dyaml/parser.d @@ -127,12 +127,12 @@ final class Parser TagDirective[] tagDirectives_; ///Stack of states. - Array!(Event delegate()) states_; + Array!(Event delegate() @safe) states_; ///Stack of marks used to keep track of extents of e.g. YAML collections. Array!Mark marks_; ///Current state. - Event delegate() state_; + Event delegate() @safe state_; public: ///Construct a Parser using specified Scanner. @@ -165,7 +165,7 @@ final class Parser * or if there are any events left if no types specified. * false otherwise. */ - bool checkEvent(EventID[] ids...) @trusted + bool checkEvent(EventID[] ids...) @safe { //Check if the next event is one of specified types. if(currentEvent_.isNull && state_ !is null) @@ -228,7 +228,7 @@ final class Parser private: ///Pop and return the newest state in states_. - Event delegate() popState() @trusted + Event delegate() @safe popState() @trusted { enforce(states_.length > 0, new YAMLException("Parser: Need to pop state but no states left to pop")); @@ -347,7 +347,7 @@ final class Parser while(scanner_.checkToken(TokenID.Directive)) { const token = scanner_.getToken(); - const value = token.value; + string value = token.value.idup; if(token.directive == DirectiveType.YAML) { enforce(YAMLVersion_ is null, @@ -356,11 +356,11 @@ final class Parser enforce(minor == "1", new Error("Incompatible document (version 1.x is required)", token.startMark)); - YAMLVersion_ = cast(string)value; + YAMLVersion_ = value; } else if(token.directive == DirectiveType.TAG) { - auto handle = cast(string)value[0 .. token.valueDivider]; + auto handle = value[0 .. token.valueDivider]; foreach(ref pair; tagDirectives_) { @@ -369,8 +369,8 @@ final class Parser enforce(h != handle, new Error("Duplicate tag handle: " ~ handle, token.startMark)); } - tagDirectives_ ~= - TagDirective(handle, cast(string)value[token.valueDivider .. $]); + tagDirectives_ ~= + TagDirective(handle, value[token.valueDivider .. $]); } // Any other directive type is ignored (only YAML and TAG are in YAML // 1.1/1.2, any other directives are "reserved") @@ -432,7 +432,7 @@ final class Parser uint tagHandleEnd; //Get anchor/tag if detected. Return false otherwise. - bool get(const TokenID id, const Flag!"first" first, ref string target) + bool get(const TokenID id, const Flag!"first" first, ref string target) @trusted { if(!scanner_.checkToken(id)){return false;} invalidMarks = false; @@ -536,7 +536,7 @@ final class Parser /// Handle escape sequences in a double quoted scalar. /// /// Moved here from scanner as it can't always be done in-place with slices. - string handleDoubleQuotedScalarEscapes(char[] tokenValue) + string handleDoubleQuotedScalarEscapes(char[] tokenValue) const @system { string notInPlace; bool inEscape = false; @@ -623,7 +623,7 @@ final class Parser */ string processTag(const string tag, const uint handleEnd, const Mark startMark, const Mark tagMark) - const @trusted + const @safe { const handle = tag[0 .. handleEnd]; const suffix = tag[handleEnd .. $]; @@ -829,7 +829,7 @@ final class Parser } ///Parse a key in flow context. - Event parseFlowKey(in Event delegate() nextState) @trusted + Event parseFlowKey(in Event delegate() @safe nextState) @trusted { const token = scanner_.getToken(); @@ -851,7 +851,7 @@ final class Parser } ///Parse a mapping value in a flow context. - Event parseFlowValue(TokenID checkId, in Event delegate() nextState) + Event parseFlowValue(TokenID checkId, in Event delegate() @safe nextState) @trusted { if(scanner_.checkToken(TokenID.Value)) diff --git a/source/dyaml/queue.d b/source/dyaml/queue.d index 2ee2af9..0422551 100644 --- a/source/dyaml/queue.d +++ b/source/dyaml/queue.d @@ -220,7 +220,7 @@ void free(T)(T* ptr) @system nothrow core.stdc.stdlib.free(ptr); } -unittest +@safe unittest { auto queue = Queue!int(); assert(queue.empty); diff --git a/source/dyaml/reader.d b/source/dyaml/reader.d index f7607f7..5b759d2 100644 --- a/source/dyaml/reader.d +++ b/source/dyaml/reader.d @@ -94,7 +94,7 @@ final class Reader /// /// Throws: ReaderException on a UTF decoding error or if there are /// nonprintable Unicode characters illegal in YAML. - this(ubyte[] buffer) @trusted pure //!nothrow + this(ubyte[] buffer) @trusted pure { auto endianResult = fixUTFByteOrder(buffer); if(endianResult.bytesStripped > 0) @@ -124,7 +124,6 @@ final class Reader checkASCII(); } -pure nothrow @nogc: /// Get character at specified index relative to current position. /// /// Params: index = Index of the character to get relative to current position @@ -135,7 +134,7 @@ pure nothrow @nogc: /// // XXX removed; search for 'risky' to find why. // Throws: ReaderException if trying to read past the end of the buffer. - dchar peek(const size_t index) @safe + dchar peek(const size_t index) @safe pure nothrow @nogc { if(index < upcomingASCII_) { return buffer_[bufferOffset_ + index]; } if(characterCount_ <= charIndex_ + index) @@ -178,7 +177,7 @@ pure nothrow @nogc: } /// Optimized version of peek() for the case where peek index is 0. - dchar peek() @safe + dchar peek() @safe pure nothrow @nogc { if(upcomingASCII_ > 0) { return buffer_[bufferOffset_]; } if(characterCount_ <= charIndex_) { return '\0'; } @@ -195,13 +194,13 @@ pure nothrow @nogc: /// case, '\0' will be returned. /// /// Returns: Byte at specified position or '\0' if outside of the buffer. - char peekByte(const size_t index) @safe + char peekByte(const size_t index) @safe pure nothrow @nogc { return characterCount_ > (charIndex_ + index) ? buffer_[bufferOffset_ + index] : '\0'; } /// Optimized version of peekByte() for the case where peek byte index is 0. - char peekByte() @safe + char peekByte() @safe pure nothrow @nogc { return characterCount_ > charIndex_ ? buffer_[bufferOffset_] : '\0'; } @@ -218,7 +217,7 @@ pure nothrow @nogc: /// slice will be shorter. /// /// Returns: Characters starting at current position or an empty slice if out of bounds. - char[] prefix(const size_t length) @safe + char[] prefix(const size_t length) @safe pure nothrow @nogc { return slice(length); } @@ -234,7 +233,7 @@ pure nothrow @nogc: /// this. /// /// Returns: Bytes starting at current position. - char[] prefixBytes(const size_t length) @safe + char[] prefixBytes(const size_t length) @safe pure nothrow @nogc { assert(length == 0 || bufferOffset_ + length < buffer_.length, "prefixBytes out of bounds"); @@ -251,7 +250,7 @@ pure nothrow @nogc: /// be shorter. /// /// Returns: Slice into the internal buffer or an empty slice if out of bounds. - char[] slice(const size_t end) @safe + char[] slice(const size_t end) @safe pure nothrow @nogc { // Fast path in case the caller has already peek()ed all the way to end. if(end == lastDecodedCharOffset_) @@ -279,7 +278,7 @@ pure nothrow @nogc: /// /// Throws: ReaderException if trying to read past the end of the buffer /// or if invalid data is read. - dchar get() @safe + dchar get() @safe pure nothrow @nogc { const result = peek(); forward(); @@ -291,7 +290,7 @@ pure nothrow @nogc: /// Params: length = Number or characters (code points, not bytes) to get. /// /// Returns: Characters starting at current position. - char[] get(const size_t length) @safe + char[] get(const size_t length) @safe pure nothrow @nogc { auto result = slice(length); forward(length); @@ -301,7 +300,7 @@ pure nothrow @nogc: /// Move current position forward. /// /// Params: length = Number of characters to move position forward. - void forward(size_t length) @safe + void forward(size_t length) @safe pure nothrow @nogc { mixin FastCharSearch!"\n\u0085\u2028\u2029"d search; @@ -356,7 +355,7 @@ pure nothrow @nogc: } /// Move current position forward by one character. - void forward() @trusted + void forward() @safe pure nothrow @nogc { ++charIndex_; lastDecodedBufferOffset_ = bufferOffset_; @@ -401,25 +400,24 @@ pure nothrow @nogc: /// Used to build slices of read data in Reader; to avoid allocations. SliceBuilder sliceBuilder; -@safe pure nothrow @nogc: /// Get a string describing current buffer position, used for error messages. - Mark mark() const { return Mark(line_, column_); } + Mark mark() const pure nothrow @nogc @safe { return Mark(line_, column_); } /// Get current line number. - uint line() const { return line_; } + uint line() const @safe pure nothrow @nogc { return line_; } /// Get current column number. - uint column() const { return column_; } + uint column() const @safe pure nothrow @nogc { return column_; } /// Get index of the current character in the buffer. - size_t charIndex() const { return charIndex_; } + size_t charIndex() const @safe pure nothrow @nogc { return charIndex_; } /// Get encoding of the input buffer. - Encoding encoding() const { return encoding_; } + Encoding encoding() const @safe pure nothrow @nogc { return encoding_; } private: // Update upcomingASCII_ (should be called forward()ing over a UTF-8 sequence) - void checkASCII() + void checkASCII() @safe pure nothrow @nogc { upcomingASCII_ = countASCII(buffer_[bufferOffset_ .. $]); } @@ -428,7 +426,7 @@ private: // lastDecodedCharOffset_/lastDecodedBufferOffset_ and update them. // // Does not advance the buffer position. Used in peek() and slice(). - dchar decodeNext() + dchar decodeNext() @safe pure nothrow @nogc { assert(lastDecodedBufferOffset_ < buffer_.length, "Attempted to decode past the end of YAML buffer"); @@ -453,7 +451,6 @@ private: /// See begin() documentation. struct SliceBuilder { -pure nothrow @nogc: private: // No copying by the user. @disable this(this); @@ -474,7 +471,7 @@ private: // The number of elements currently in endStack_. size_t endStackUsed_ = 0; - @safe const invariant() + @safe const pure nothrow @nogc invariant() { if(!inProgress) { return; } assert(end_ <= reader_.bufferOffset_, "Slice ends after buffer position"); @@ -482,7 +479,7 @@ private: } // Is a slice currently being built? - bool inProgress() @safe const + bool inProgress() @safe const pure nothrow @nogc { assert(start_ == size_t.max ? end_ == size_t.max : end_ != size_t.max, "start_/end_ are not consistent"); @@ -500,7 +497,7 @@ public: /// forward() move the position. E.g. it is valid to extend a slice by write()-ing /// a string just returned by get() - but not one returned by prefix() unless the /// position has changed since the prefix() call. - void begin() @system + void begin() @safe pure nothrow @nogc { assert(!inProgress, "Beginning a slice while another slice is being built"); assert(endStackUsed_ == 0, "Slice stack not empty at slice begin"); @@ -516,7 +513,7 @@ public: /// /// Returns a string; once a slice is finished it is definitive that its contents /// will not be changed. - char[] finish() @system + char[] finish() @safe pure nothrow @nogc { assert(inProgress, "finish called without begin"); assert(endStackUsed_ == 0, "Finishing a slice with running transactions."); @@ -534,7 +531,7 @@ public: /// end of the slice being built, the slice is extended (trivial operation). /// /// See_Also: begin - void write(char[] str) @system + void write(char[] str) @trusted pure nothrow @nogc { assert(inProgress, "write called without begin"); assert(end_ <= reader_.bufferOffset_, @@ -561,7 +558,7 @@ public: /// Data can only be written up to the current position in the Reader buffer. /// /// See_Also: begin - void write(dchar c) @system + void write(dchar c) @safe pure nothrow @nogc { assert(inProgress, "write called without begin"); if(c < 0x80) @@ -588,7 +585,7 @@ public: /// position = Position to insert the character at in code units, not code points. /// Must be less than slice length(); a previously returned length() /// can be used. - void insert(const dchar c, const size_t position) @system + void insert(const dchar c, const size_t position) @system pure nothrow @nogc { assert(inProgress, "insert called without begin"); assert(start_ + position <= end_, "Trying to insert after the end of the slice"); @@ -612,7 +609,7 @@ public: } /// Get the current length of the slice. - size_t length() @safe const + size_t length() @safe const pure nothrow @nogc { return end_ - start_; } @@ -622,7 +619,6 @@ public: /// Can be used to save and revert back to slice state. struct Transaction { - @system pure nothrow @nogc: private: // The slice builder affected by the transaction. SliceBuilder* builder_ = null; @@ -639,7 +635,7 @@ public: /// ended either by commit()-ing or reverting through the destructor. /// /// Saves the current state of a slice. - this(ref SliceBuilder builder) + this(ref SliceBuilder builder) @system pure nothrow @nogc { builder_ = &builder; stackLevel_ = builder_.endStackUsed_; @@ -653,7 +649,7 @@ public: /// /// Does nothing for a default-initialized transaction (the transaction has not /// been started yet). - void commit() + void commit() @safe pure nothrow @nogc { assert(!committed_, "Can't commit a transaction more than once"); @@ -667,7 +663,7 @@ public: /// Destroy the transaction and revert it if it hasn't been committed yet. /// /// Does nothing for a default-initialized transaction. - ~this() + ~this() @safe pure nothrow @nogc { if(builder_ is null || committed_) { return; } assert(builder_.endStackUsed_ == stackLevel_ + 1, @@ -681,7 +677,7 @@ private: // Push the current end of the slice so we can revert to it if needed. // // Used by Transaction. - void push() @system + void push() @safe pure nothrow @nogc { assert(inProgress, "push called without begin"); assert(endStackUsed_ < endStack_.length, "Slice stack overflow"); @@ -692,7 +688,7 @@ private: // value, reverting changes since the old end was pushed. // // Used by Transaction. - void pop() @system + void pop() @safe pure nothrow @nogc { assert(inProgress, "pop called without begin"); assert(endStackUsed_ > 0, "Trying to pop an empty slice stack"); @@ -703,7 +699,7 @@ private: // changes made since pushing the old end. // // Used by Transaction. - void apply() @system + void apply() @safe pure nothrow @nogc { assert(inProgress, "apply called without begin"); assert(endStackUsed_ > 0, "Trying to apply an empty slice stack"); @@ -823,7 +819,7 @@ auto toUTF8(ubyte[] input, const UTFEncoding encoding) @safe pure nothrow } /// Determine if all characters (code points, not bytes) in a string are printable. -bool isPrintableValidUTF8(const char[] chars) @trusted pure nothrow @nogc +bool isPrintableValidUTF8(const char[] chars) @safe pure nothrow @nogc { // This is oversized (only 128 entries are necessary) simply because having 256 // entries improves performance... for some reason (alignment?) @@ -1041,7 +1037,7 @@ void test1Byte(R)() // assert(collectException(reader.peek(2))); } -unittest +@system unittest { testEndian!Reader(); testPeekPrefixForward!Reader(); diff --git a/source/dyaml/representer.d b/source/dyaml/representer.d index 916f8ce..8e2c7d8 100644 --- a/source/dyaml/representer.d +++ b/source/dyaml/representer.d @@ -48,7 +48,7 @@ final class Representer { private: // Representer functions indexed by types. - Node function(ref Node, Representer)[TypeInfo] representers_; + Node function(ref Node, Representer) @safe[TypeInfo] representers_; // Default style for scalar nodes. ScalarStyle defaultScalarStyle_ = ScalarStyle.Invalid; // Default style for collection nodes. @@ -82,7 +82,7 @@ final class Representer } ///Destroy the Representer. - pure @safe nothrow ~this() + ~this() pure @safe nothrow { representers_.destroy(); representers_ = null; @@ -222,8 +222,8 @@ final class Representer * } * -------------------- */ - void addRepresenter(T)(Node function(ref Node, Representer) representer) - @trusted pure + void addRepresenter(T)(Node function(ref Node, Representer) @safe representer) + @safe pure { assert((typeid(T) in representers_) is null, "Representer function for data type " ~ T.stringof ~ @@ -428,7 +428,7 @@ final class Representer package: //Represent a node based on its type, and return the represented result. - Node representData(ref Node data) @system + Node representData(ref Node data) @safe { //User types are wrapped in YAMLObject. auto type = data.isUserType ? data.as!YAMLObject.type : data.type; @@ -454,7 +454,7 @@ final class Representer } //Represent a node, serializing with specified Serializer. - void represent(ref Serializer serializer, ref Node node) @trusted + void represent(ref Serializer serializer, ref Node node) @safe { auto data = representData(node); serializer.serialize(data); @@ -478,12 +478,12 @@ Node representString(ref Node node, Representer representer) @safe } ///Represent a bytes _node as a binary scalar. -Node representBytes(ref Node node, Representer representer) @system +Node representBytes(ref Node node, Representer representer) @safe { const ubyte[] value = node.as!(ubyte[]); if(value is null){return representNull(node, representer);} - return representer.representScalar("tag:yaml.org,2002:binary", - cast(string)Base64.encode(value), + return representer.representScalar("tag:yaml.org,2002:binary", + Base64.encode(value).idup, ScalarStyle.Literal); } @@ -495,14 +495,14 @@ Node representBool(ref Node node, Representer representer) @safe } ///Represent a long _node as an integer scalar. -Node representLong(ref Node node, Representer representer) @system +Node representLong(ref Node node, Representer representer) @safe { return representer.representScalar("tag:yaml.org,2002:int", to!string(node.as!long)); } ///Represent a real _node as a floating point scalar. -Node representReal(ref Node node, Representer representer) @system +Node representReal(ref Node node, Representer representer) @safe { real f = node.as!real; string value = isNaN(f) ? ".nan": @@ -516,7 +516,7 @@ Node representReal(ref Node node, Representer representer) @system } ///Represent a SysTime _node as a timestamp. -Node representSysTime(ref Node node, Representer representer) @system +Node representSysTime(ref Node node, Representer representer) @safe { return representer.representScalar("tag:yaml.org,2002:timestamp", node.as!SysTime.toISOExtString()); @@ -545,15 +545,14 @@ Node representNodes(ref Node node, Representer representer) @safe } ///Represent a mapping _node as map/ordered map/pairs. -Node representPairs(ref Node node, Representer representer) @system +Node representPairs(ref Node node, Representer representer) @safe { auto pairs = node.as!(Node.Pair[]); - bool hasDuplicates(Node.Pair[] pairs) + bool hasDuplicates(Node.Pair[] pairs) @safe { //TODO this should be replaced by something with deterministic memory allocation. auto keys = redBlackTree!Node(); - scope(exit){keys.destroy();} foreach(ref pair; pairs) { if(pair.key in keys){return true;} @@ -562,7 +561,7 @@ Node representPairs(ref Node node, Representer representer) @system return false; } - Node[] mapToSequence(Node.Pair[] pairs) + Node[] mapToSequence(Node.Pair[] pairs) @safe { Node[] nodes; nodes.length = pairs.length; @@ -610,8 +609,8 @@ struct MyStruct } } -Node representMyStruct(ref Node node, Representer representer) @system -{ +Node representMyStruct(ref Node node, Representer representer) @safe +{ //The node is guaranteed to be MyStruct as we add representer for MyStruct. auto value = node.as!MyStruct; //Using custom scalar format, x:y:z. @@ -658,15 +657,15 @@ class MyClass } ///Useful for Node.as!string . - override string toString() @trusted + override string toString() @safe { return format("MyClass(%s, %s, %s)", x, y, z); } } //Same as representMyStruct. -Node representMyClass(ref Node node, Representer representer) @system -{ +Node representMyClass(ref Node node, Representer representer) @safe +{ //The node is guaranteed to be MyClass as we add representer for MyClass. auto value = node.as!MyClass; //Using custom scalar format, x:y:z. @@ -677,7 +676,7 @@ Node representMyClass(ref Node node, Representer representer) @system import dyaml.stream; -unittest +@safe unittest { foreach(r; [&representMyStruct, &representMyStructSeq, @@ -691,7 +690,7 @@ unittest } } -unittest +@safe unittest { auto dumper = Dumper(new YMemoryStream()); auto representer = new Representer; diff --git a/source/dyaml/resolver.d b/source/dyaml/resolver.d index 2f41c59..d107266 100644 --- a/source/dyaml/resolver.d +++ b/source/dyaml/resolver.d @@ -70,7 +70,7 @@ final class Resolver } ///Destroy the Resolver. - pure @safe nothrow ~this() + ~this() pure @safe nothrow { yamlImplicitResolvers_.destroy(); yamlImplicitResolvers_ = null; @@ -169,13 +169,13 @@ final class Resolver else if(kind == NodeID.Mapping) {return defaultMappingTag_;} assert(false, "This line of code should never be reached"); } - unittest + @safe unittest { writeln("D:YAML Resolver unittest"); auto resolver = new Resolver(); - bool tagMatch(string tag, string[] values) + bool tagMatch(string tag, string[] values) @safe { string expected = tag; foreach(value; values) diff --git a/source/dyaml/scanner.d b/source/dyaml/scanner.d index fb3d696..b68ea82 100644 --- a/source/dyaml/scanner.d +++ b/source/dyaml/scanner.d @@ -171,7 +171,7 @@ final class Scanner } /// Destroy the scanner. - @trusted ~this() + ~this() @trusted { tokens_.destroy(); indents_.destroy(); @@ -233,14 +233,14 @@ final class Scanner private: /// Build an error message in msgBuffer_ and return it as a string. - string buildMsg(S ...)(S args) @trusted pure nothrow @nogc + string buildMsg(S ...)(S args) @trusted { return cast(string)msgBuffer_.printNoGC(args); } /// Most scanning error messages have the same format; so build them with this /// function. - string expected(T)(string expected, T found) @safe pure nothrow @nogc + string expected(T)(string expected, T found) { return buildMsg("expected ", expected, ", but found ", found); } @@ -489,7 +489,7 @@ final class Scanner } /// Add DOCUMENT-START or DOCUMENT-END token. - void fetchDocumentIndicator(TokenID id)() @safe + void fetchDocumentIndicator(TokenID id)() if(id == TokenID.DocumentStart || id == TokenID.DocumentEnd) { // Set indentation to -1 . @@ -508,7 +508,7 @@ final class Scanner alias fetchDocumentIndicator!(TokenID.DocumentEnd) fetchDocumentEnd; /// Add FLOW-SEQUENCE-START or FLOW-MAPPING-START token. - void fetchFlowCollectionStart(TokenID id)() @trusted + void fetchFlowCollectionStart(TokenID id)() @safe { // '[' and '{' may start a simple key. savePossibleSimpleKey(); @@ -526,7 +526,7 @@ final class Scanner alias fetchFlowCollectionStart!(TokenID.FlowMappingStart) fetchFlowMappingStart; /// Add FLOW-SEQUENCE-START or FLOW-MAPPING-START token. - void fetchFlowCollectionEnd(TokenID id)() @safe + void fetchFlowCollectionEnd(TokenID id)() { // Reset possible simple key on the current level. removePossibleSimpleKey(); @@ -560,7 +560,7 @@ final class Scanner /// /// Params: type = String representing the token type we might need to add. /// id = Token type we might need to add. - void blockChecks(string type, TokenID id)() @safe + void blockChecks(string type, TokenID id)() { enum context = type ~ " keys are not allowed here"; // Are we allowed to start a key (not neccesarily a simple one)? @@ -659,7 +659,7 @@ final class Scanner } /// Add ALIAS or ANCHOR token. - void fetchAnchor_(TokenID id)() @trusted + void fetchAnchor_(TokenID id)() @safe if(id == TokenID.Alias || id == TokenID.Anchor) { // ALIAS/ANCHOR could be a simple key. @@ -677,7 +677,7 @@ final class Scanner alias fetchAnchor_!(TokenID.Anchor) fetchAnchor; /// Add TAG token. - void fetchTag() @trusted + void fetchTag() @safe { //TAG could start a simple key. savePossibleSimpleKey(); @@ -689,7 +689,7 @@ final class Scanner } /// Add block SCALAR token. - void fetchBlockScalar(ScalarStyle style)() @trusted + void fetchBlockScalar(ScalarStyle style)() @safe if(style == ScalarStyle.Literal || style == ScalarStyle.Folded) { // Reset possible simple key on the current level. @@ -707,7 +707,7 @@ final class Scanner alias fetchBlockScalar!(ScalarStyle.Folded) fetchFolded; /// Add quoted flow SCALAR token. - void fetchFlowScalar(ScalarStyle quotes)() @safe + void fetchFlowScalar(ScalarStyle quotes)() { // A flow scalar could be a simple key. savePossibleSimpleKey(); @@ -828,7 +828,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanAlphaNumericToSlice(string name)(const Mark startMark) @system + void scanAlphaNumericToSlice(string name)(const Mark startMark) { size_t length = 0; dchar c = reader_.peek(); @@ -855,7 +855,7 @@ final class Scanner /// /// Assumes that the caller is building a slice in Reader, and puts the scanned /// characters into that slice. - void scanToNextBreakToSlice() @system + void scanToNextBreakToSlice() @safe { uint length = 0; while(!searchAllBreaks.canFind(reader_.peek(length))) @@ -905,7 +905,7 @@ final class Scanner } /// Scan directive token. - Token scanDirective() @trusted + Token scanDirective() @safe { Mark startMark = reader_.mark; // Skip the '%'. @@ -949,7 +949,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanDirectiveNameToSlice(const Mark startMark) @system + void scanDirectiveNameToSlice(const Mark startMark) @safe { // Scan directive name. scanAlphaNumericToSlice!"a directive"(startMark); @@ -966,7 +966,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanYAMLDirectiveValueToSlice(const Mark startMark) @system + void scanYAMLDirectiveValueToSlice(const Mark startMark) @safe { findNextNonSpace(); @@ -999,7 +999,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanYAMLDirectiveNumberToSlice(const Mark startMark) @system + void scanYAMLDirectiveNumberToSlice(const Mark startMark) @safe { if(!isDigit(reader_.peek())) { @@ -1023,7 +1023,7 @@ final class Scanner /// Returns: Length of tag handle (which is before tag prefix) in scanned data /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - uint scanTagDirectiveValueToSlice(const Mark startMark) @system + uint scanTagDirectiveValueToSlice(const Mark startMark) @safe { findNextNonSpace(); const startLength = reader_.sliceBuilder.length; @@ -1042,7 +1042,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanTagDirectiveHandleToSlice(const Mark startMark) @system + void scanTagDirectiveHandleToSlice(const Mark startMark) @safe { scanTagHandleToSlice!"directive"(startMark); if(error_) { return; } @@ -1057,7 +1057,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanTagDirectivePrefixToSlice(const Mark startMark) @system + void scanTagDirectivePrefixToSlice(const Mark startMark) @safe { scanTagURIToSlice!"directive"(startMark); if(" \0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek())) { return; } @@ -1094,7 +1094,7 @@ final class Scanner /// Therefore we restrict aliases to ASCII alphanumeric characters. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - Token scanAnchor(const TokenID id) @trusted + Token scanAnchor(const TokenID id) @safe { const startMark = reader_.mark; const dchar i = reader_.get(); @@ -1130,7 +1130,7 @@ final class Scanner /// Scan a tag token. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - Token scanTag() @trusted + Token scanTag() @safe { const startMark = reader_.mark; dchar c = reader_.peek(1); @@ -1448,7 +1448,7 @@ final class Scanner /// /// Assumes that the caller is building a slice in Reader, and puts the scanned /// characters into that slice. - Tuple!(uint, Mark) scanBlockScalarIndentationToSlice() @system + Tuple!(uint, Mark) scanBlockScalarIndentationToSlice() @safe { uint maxIndent; Mark endMark = reader_.mark; @@ -1472,7 +1472,7 @@ final class Scanner /// /// Assumes that the caller is building a slice in Reader, and puts the scanned /// characters into that slice. - Mark scanBlockScalarBreaksToSlice(const uint indent) @trusted + Mark scanBlockScalarBreaksToSlice(const uint indent) @safe { Mark endMark = reader_.mark; @@ -1490,7 +1490,7 @@ final class Scanner /// Scan a qouted flow scalar token with specified quotes. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - Token scanFlowScalar(const ScalarStyle quotes) @trusted + Token scanFlowScalar(const ScalarStyle quotes) @safe { const startMark = reader_.mark; const quote = reader_.get(); @@ -1521,7 +1521,7 @@ final class Scanner /// /// In case of an error, error_ is set. Use throwIfError() to handle this. void scanFlowScalarNonSpacesToSlice(const ScalarStyle quotes, const Mark startMark) - @system + @safe { for(;;) with(ScalarStyle) { @@ -1635,7 +1635,7 @@ final class Scanner /// spaces into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanFlowScalarSpacesToSlice(const Mark startMark) @system + void scanFlowScalarSpacesToSlice(const Mark startMark) @safe { // Increase length as long as we see whitespace. size_t length = 0; @@ -1680,7 +1680,7 @@ final class Scanner /// line breaks into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - bool scanFlowScalarBreaksToSlice(const Mark startMark) @system + bool scanFlowScalarBreaksToSlice(const Mark startMark) @safe { // True if at least one line break was found. bool anyBreaks; @@ -1873,7 +1873,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanTagHandleToSlice(string name)(const Mark startMark) @system + void scanTagHandleToSlice(string name)(const Mark startMark) { dchar c = reader_.peek(); enum contextMsg = "While scanning a " ~ name; @@ -1910,7 +1910,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanTagURIToSlice(string name)(const Mark startMark) @trusted + void scanTagURIToSlice(string name)(const Mark startMark) { // Note: we do not check if URI is well-formed. dchar c = reader_.peek(); @@ -1952,7 +1952,7 @@ final class Scanner /// characters into that slice. /// /// In case of an error, error_ is set. Use throwIfError() to handle this. - void scanURIEscapesToSlice(string name)(const Mark startMark) @system + void scanURIEscapesToSlice(string name)(const Mark startMark) { // URI escapes encode a UTF-8 string. We store UTF-8 code units here for // decoding into UTF-32. @@ -1967,7 +1967,7 @@ final class Scanner // // Returns the number of bytes used by the dchar in bytes on success, // size_t.max on failure. - static size_t getDchar(char[] bytes, Reader reader_) + static size_t getDchar(char[] bytes, Reader reader_) @trusted { size_t nextChar; dchar c; @@ -1985,7 +1985,7 @@ final class Scanner reader_.sliceBuilder.write(c); if(bytes.length - nextChar > 0) { - core.stdc.string.memmove(bytes.ptr, bytes.ptr + nextChar, + core.stdc.string.memmove(&bytes[0], &bytes[nextChar], bytes.length - nextChar); } return bytes.length - nextChar; @@ -2081,7 +2081,7 @@ final class Scanner private: /// A nothrow function that converts a dchar[] to a string. -string utf32To8(C)(C[] str) @safe pure nothrow +string utf32To8(C)(C[] str) if(is(Unqual!C == dchar)) { try { return str.to!string; } diff --git a/source/dyaml/serializer.d b/source/dyaml/serializer.d index dd5ea0d..af463a0 100644 --- a/source/dyaml/serializer.d +++ b/source/dyaml/serializer.d @@ -82,7 +82,7 @@ struct Serializer } ///Destroy the Serializer. - @safe ~this() + ~this() @safe { emitter_.emit(streamEndEvent(Mark(), Mark())); YAMLVersion_.destroy(); @@ -119,7 +119,7 @@ struct Serializer * * Returns: True if the node is anchorable, false otherwise. */ - static bool anchorable(ref Node node) @safe + static bool anchorable(ref Node node) @safe { if(node.isScalar) { @@ -157,7 +157,7 @@ struct Serializer } ///Generate and return a new anchor. - string generateAnchor() @trusted + string generateAnchor() @safe { ++lastAnchorID_; auto appender = appender!string(); @@ -166,7 +166,7 @@ struct Serializer } ///Serialize a node and all its subnodes. - void serializeNode(ref Node node) @trusted + void serializeNode(ref Node node) @safe { //If the node has an anchor, emit an anchor (as aliasEvent) on the //first occurrence, save it in serializedNodes_, and emit an alias diff --git a/source/dyaml/stream.d b/source/dyaml/stream.d index eb58032..0b0142e 100644 --- a/source/dyaml/stream.d +++ b/source/dyaml/stream.d @@ -31,10 +31,11 @@ immutable ubyte[][NBOMS] ByteOrderMarks = interface YStream { void writeExact(const void* buffer, size_t size); - size_t write(const(ubyte)[] buffer); - size_t write(const(char)[] str); - void flush(); - @property bool writeable(); + void writeExact(const void[] buffer) @safe; + size_t write(const(ubyte)[] buffer) @safe; + size_t write(const(char)[] str) @safe; + void flush() @safe; + @property bool writeable() @safe; } class YMemoryStream : YStream @@ -46,20 +47,25 @@ class YMemoryStream : YStream data ~= cast(ubyte[])buffer[0 .. size]; } - size_t write(const(ubyte)[] buffer) + void writeExact(const void[] buffer) @trusted + { + data ~= cast(ubyte[])buffer; + } + + size_t write(const(ubyte)[] buffer) @safe { data ~= buffer; return buffer.length; } - size_t write(const(char)[] str) + size_t write(const(char)[] str) @safe { return write(cast(const(ubyte)[])str); } - void flush() {} + void flush() @safe {} - @property bool writeable() { return true; } + @property bool writeable() @safe { return true; } } class YFile : YStream @@ -67,17 +73,17 @@ class YFile : YStream static import std.stdio; std.stdio.File file; - this(string fn) + this(string fn) @safe { this.file = std.stdio.File(fn, "w"); } - this(std.stdio.File file) + this(std.stdio.File file) @safe { this.file = file; } - unittest + @system unittest { import std.stdio : stdout; auto stream = new YFile(stdout); @@ -89,26 +95,31 @@ class YFile : YStream this.file.rawWrite(cast(const) buffer[0 .. size]); } - size_t write(const(ubyte)[] buffer) + void writeExact(const void[] buffer) @trusted + { + this.file.rawWrite(buffer); + } + + size_t write(const(ubyte)[] buffer) @trusted { this.file.rawWrite(buffer); return buffer.length; } - size_t write(const(char)[] str) + size_t write(const(char)[] str) @trusted { - return write(cast(const(ubyte)[])str); + return write(cast(ubyte[])str); } - void flush() + void flush() @safe { this.file.flush(); } - @property bool writeable() { return true; } + @property bool writeable() @safe { return true; } } -unittest +@safe unittest { import dyaml.dumper, dyaml.loader, dyaml.node; import std.file : readText, remove; @@ -135,7 +146,7 @@ unittest remove("output.yaml"); } -unittest // #88, #89 +@safe unittest // #88, #89 { import dyaml.dumper, dyaml.loader; import std.file : remove, read; @@ -147,5 +158,5 @@ unittest // #88, #89 dumper.YAMLVersion = null; // supress directive dumper.dump(Loader.fromString("Hello world".dup).load); - assert (cast (char[]) fn.read()[0..3] == "Hel"); + assert (fn.read()[0..3] == "Hel"); } diff --git a/source/dyaml/test/common.d b/source/dyaml/test/common.d index 5bacc5d..743a0c0 100644 --- a/source/dyaml/test/common.d +++ b/source/dyaml/test/common.d @@ -19,6 +19,7 @@ import std.array; import std.conv; import std.file; import std.path; +import std.traits; import std.typecons; package: @@ -31,7 +32,7 @@ package: * unittestExt = Extensions of data files needed for the unittest. * skipExt = Extensions that must not be used for the unittest. */ -void run(F ...)(string testName, void function(bool, F) testFunction, +void run(D)(string testName, D testFunction, string[] unittestExt, string[] skipExt = []) { immutable string dataDir = __FILE_FULL_PATH__.dirName ~ "/../../../test/data"; @@ -54,16 +55,25 @@ void run(F ...)(string testName, void function(bool, F) testFunction, if(extensions.canFind(ext)){continue outer;} } - results ~= execute!F(testName, testFunction, filenames, verbose); + results ~= execute(testName, testFunction, filenames, verbose); } } else { - results ~= execute!F(testName, testFunction, cast(string[])[], verbose); + results ~= execute(testName, testFunction, cast(string[])[], verbose); } display(results, verbose); } +/** + * Prints an exception if verbosity is turned on. + * Params: e = Exception to print. + * verbose = Whether verbose mode is enabled. + */ +void printException(YAMLException e, bool verbose) @trusted +{ + if(verbose) { writeln(typeid(e).toString(), "\n", e); } +} private: @@ -85,7 +95,7 @@ alias Tuple!(string, "name", string[], "filenames", TestStatus, "kind", string, * * Returns: Test input base filenames and their extensions. */ -string[][string] findTestFilenames(const string dir) +string[][string] findTestFilenames(const string dir) @trusted { //Groups of extensions indexed by base names. string[][string] names; @@ -130,8 +140,8 @@ body * * Returns: Information about the results of the unittest. */ -Result execute(F ...)(const string testName, void function(bool, F) testFunction, - string[] filenames, const bool verbose) +Result execute(D)(const string testName, D testFunction, + string[] filenames, const bool verbose) @trusted { if(verbose) { @@ -144,6 +154,7 @@ Result execute(F ...)(const string testName, void function(bool, F) testFunction try { //Convert filenames to parameters tuple and call the test function. + alias F = Parameters!D[1..$]; F parameters; stringsToTuple!(F.length - 1, F)(parameters, filenames); testFunction(verbose, parameters); @@ -167,7 +178,7 @@ Result execute(F ...)(const string testName, void function(bool, F) testFunction * Params: results = Unittest results. * verbose = Print verbose output? */ -void display(Result[] results, const bool verbose) +void display(Result[] results, const bool verbose) @safe { if(results.length > 0 && !verbose){write("\n");} diff --git a/source/dyaml/test/compare.d b/source/dyaml/test/compare.d index 71faf35..e9e970f 100644 --- a/source/dyaml/test/compare.d +++ b/source/dyaml/test/compare.d @@ -19,7 +19,7 @@ import dyaml.token; /// Params: verbose = Print verbose output? /// dataFilename = YAML file to parse. /// canonicalFilename = Another file to parse, in canonical YAML format. -void testParser(bool verbose, string dataFilename, string canonicalFilename) +void testParser(bool verbose, string dataFilename, string canonicalFilename) @safe { auto dataEvents = Loader(dataFilename).parse(); auto canonicalEvents = Loader(canonicalFilename).parse(); @@ -38,7 +38,7 @@ void testParser(bool verbose, string dataFilename, string canonicalFilename) /// Params: verbose = Print verbose output? /// dataFilename = YAML file to load. /// canonicalFilename = Another file to load, in canonical YAML format. -void testLoader(bool verbose, string dataFilename, string canonicalFilename) +void testLoader(bool verbose, string dataFilename, string canonicalFilename) @safe { auto data = Loader(dataFilename).loadAll(); auto canonical = Loader(canonicalFilename).loadAll(); @@ -62,7 +62,7 @@ void testLoader(bool verbose, string dataFilename, string canonicalFilename) } -unittest +@safe unittest { writeln("D:YAML comparison unittest"); run("testParser", &testParser, ["data", "canonical"]); diff --git a/source/dyaml/test/constructor.d b/source/dyaml/test/constructor.d index 854a89e..792229d 100644 --- a/source/dyaml/test/constructor.d +++ b/source/dyaml/test/constructor.d @@ -23,7 +23,7 @@ import dyaml.test.common; Node[][string] expected; ///Initialize expected. -static this() +static this() @safe { expected["aliases-cdumper-bug"] = constructAliasesCDumperBug(); expected["construct-binary"] = constructBinary(); @@ -64,15 +64,15 @@ Node.Pair pair(A, B)(A a, B b) ///Test cases: -Node[] constructAliasesCDumperBug() +Node[] constructAliasesCDumperBug() @safe { return [Node(["today", "today"])]; } -Node[] constructBinary() +Node[] constructBinary() @safe { - auto canonical = cast(ubyte[])"GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;"; - auto generic = cast(ubyte[])"GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;"; + auto canonical = "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;".representation; + auto generic = "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;".representation; auto description = "The binary value above is a tiny arrow encoded as a gif image."; return [Node([pair("canonical", canonical), @@ -80,7 +80,7 @@ Node[] constructBinary() pair("description", description)])]; } -Node[] constructBool() +Node[] constructBool() @safe { const(bool) a = true; immutable(bool) b = true; @@ -97,13 +97,13 @@ Node[] constructBool() pair("but", [pair("y", "is a string"), pair("n", "is a string")])])]; } -Node[] constructCustom() +Node[] constructCustom() @safe { return [Node([Node(new TestClass(1, 2, 3)), Node(TestStruct(10))])]; } -Node[] constructFloat() +Node[] constructFloat() @safe { return [Node([pair("canonical", cast(real)685230.15), pair("exponential", cast(real)685230.15), @@ -113,7 +113,7 @@ Node[] constructFloat() pair("not a number", real.nan)])]; } -Node[] constructInt() +Node[] constructInt() @safe { return [Node([pair("canonical", 685230L), pair("decimal", 685230L), @@ -123,7 +123,7 @@ Node[] constructInt() pair("sexagesimal", 685230L)])]; } -Node[] constructMap() +Node[] constructMap() @safe { return [Node([pair("Block style", [pair("Clark", "Evans"), @@ -135,7 +135,7 @@ Node[] constructMap() pair("Oren", "Ben-Kiki")])])]; } -Node[] constructMerge() +Node[] constructMerge() @safe { return [Node([Node([pair("x", 1L), pair("y", 2L)]), Node([pair("x", 0L), pair("y", 2L)]), @@ -147,7 +147,7 @@ Node[] constructMerge() Node([pair("x", 1L), pair("label", "center/big"), pair("r", 10L), pair("y", 2L)])])]; } -Node[] constructNull() +Node[] constructNull() @safe { return [Node(YAMLNull()), Node([pair("empty", YAMLNull()), @@ -162,7 +162,7 @@ Node[] constructNull() Node(YAMLNull())])])]; } -Node[] constructOMap() +Node[] constructOMap() @safe { return [Node([pair("Bestiary", [pair("aardvark", "African pig-like ant eater. Ugly."), @@ -173,7 +173,7 @@ Node[] constructOMap() pair("three", 3L)])])]; } -Node[] constructPairs() +Node[] constructPairs() @safe { return [Node([pair("Block tasks", Node([pair("meeting", "with team."), @@ -185,7 +185,7 @@ Node[] constructPairs() pair("meeting", "with boss")], "tag:yaml.org,2002:pairs"))])]; } -Node[] constructSeq() +Node[] constructSeq() @safe { return [Node([pair("Block style", [Node("Mercury"), Node("Venus"), Node("Earth"), Node("Mars"), @@ -197,7 +197,7 @@ Node[] constructSeq() Node("Pluto")])])]; } -Node[] constructSet() +Node[] constructSet() @safe { return [Node([pair("baseball players", [Node("Mark McGwire"), Node("Sammy Sosa"), Node("Ken Griffey")]), @@ -205,22 +205,22 @@ Node[] constructSet() [Node("Boston Red Sox"), Node("Detroit Tigers"), Node("New York Yankees")])])]; } -Node[] constructStrASCII() +Node[] constructStrASCII() @safe { return [Node("ascii string")]; } -Node[] constructStr() +Node[] constructStr() @safe { return [Node([pair("string", "abcd")])]; } -Node[] constructStrUTF8() +Node[] constructStrUTF8() @safe { return [Node("\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430")]; } -Node[] constructTimestamp() +Node[] constructTimestamp() @safe { alias DT = DateTime; alias ST = SysTime; @@ -231,7 +231,7 @@ Node[] constructTimestamp() pair("date (00:00:00Z)", ST(DT(2002, 12, 14), UTC()))])]; } -Node[] constructValue() +Node[] constructValue() @safe { return[Node([pair("link with", [Node("library1.dll"), Node("library2.dll")])]), @@ -240,7 +240,7 @@ Node[] constructValue() Node([pair("=", "library2.dll"), pair("version", cast(real)2.3)])])])]; } -Node[] duplicateMergeKey() +Node[] duplicateMergeKey() @safe { return [Node([pair("foo", "bar"), pair("x", 1L), @@ -249,7 +249,7 @@ Node[] duplicateMergeKey() pair("t", 4L)])]; } -Node[] floatRepresenterBug() +Node[] floatRepresenterBug() @safe { return [Node([pair(cast(real)1.0, 1L), pair(real.infinity, 10L), @@ -257,12 +257,12 @@ Node[] floatRepresenterBug() pair(real.nan, 100L)])]; } -Node[] invalidSingleQuoteBug() +Node[] invalidSingleQuoteBug() @safe { return [Node([Node("foo \'bar\'"), Node("foo\n\'bar\'")])]; } -Node[] moreFloats() +Node[] moreFloats() @safe { return [Node([Node(cast(real)0.0), Node(cast(real)1.0), @@ -273,17 +273,17 @@ Node[] moreFloats() Node(real.nan)])]; } -Node[] negativeFloatBug() +Node[] negativeFloatBug() @safe { return [Node(cast(real)-1.0)]; } -Node[] singleDotFloatBug() +Node[] singleDotFloatBug() @safe { return [Node(".")]; } -Node[] timestampBugs() +Node[] timestampBugs() @safe { alias DT = DateTime; alias ST = SysTime; @@ -296,22 +296,22 @@ Node[] timestampBugs() Node(ST(DT(2005, 7, 8, 17, 35, 4), 5176000.dur!"hnsecs", UTC()))])]; } -Node[] utf16be() +Node[] utf16be() @safe { return [Node("UTF-16-BE")]; } -Node[] utf16le() +Node[] utf16le() @safe { return [Node("UTF-16-LE")]; } -Node[] utf8() +Node[] utf8() @safe { return [Node("UTF-8")]; } -Node[] utf8implicit() +Node[] utf8implicit() @safe { return [Node("implicit UTF-8")]; } @@ -321,7 +321,7 @@ class TestClass { int x, y, z; - this(int x, int y, int z) + this(int x, int y, int z) @safe { this.x = x; this.y = y; @@ -330,7 +330,7 @@ class TestClass //Any D:YAML type must have a custom opCmp operator. //This is used for ordering in mappings. - override int opCmp(Object o) + override int opCmp(Object o) @safe { TestClass s = cast(TestClass)o; if(s is null){return -1;} @@ -340,7 +340,7 @@ class TestClass return 0; } - override string toString() + override string toString() @safe { return format("TestClass(", x, ", ", y, ", ", z, ")"); } @@ -353,19 +353,19 @@ struct TestStruct //Any D:YAML type must have a custom opCmp operator. //This is used for ordering in mappings. - const int opCmp(ref const TestStruct s) + const int opCmp(ref const TestStruct s) @safe { return value - s.value; } } ///Constructor function for TestClass. -TestClass constructClass(ref Node node) +TestClass constructClass(ref Node node) @safe { return new TestClass(node["x"].as!int, node["y"].as!int, node["z"].as!int); } -Node representClass(ref Node node, Representer representer) +Node representClass(ref Node node, Representer representer) @safe { auto value = node.as!TestClass; auto pairs = [Node.Pair("x", value.x), @@ -377,13 +377,13 @@ Node representClass(ref Node node, Representer representer) } ///Constructor function for TestStruct. -TestStruct constructStruct(ref Node node) +TestStruct constructStruct(ref Node node) @safe { return TestStruct(to!int(node.as!string)); } ///Representer function for TestStruct. -Node representStruct(ref Node node, Representer representer) +Node representStruct(ref Node node, Representer representer) @safe { string[] keys, values; auto value = node.as!TestStruct; @@ -398,7 +398,7 @@ Node representStruct(ref Node node, Representer representer) * codeDummy = Dummy .code filename, used to determine that * .data file with the same name should be used in this test. */ -void testConstructor(bool verbose, string dataFilename, string codeDummy) +void testConstructor(bool verbose, string dataFilename, string codeDummy) @safe { string base = dataFilename.baseName.stripExtension; enforce((base in expected) !is null, @@ -436,7 +436,7 @@ void testConstructor(bool verbose, string dataFilename, string codeDummy) } -unittest +@safe unittest { writeln("D:YAML Constructor unittest"); run("testConstructor", &testConstructor, ["data", "code"]); diff --git a/source/dyaml/test/emitter.d b/source/dyaml/test/emitter.d index c85bb26..ad479c2 100644 --- a/source/dyaml/test/emitter.d +++ b/source/dyaml/test/emitter.d @@ -28,7 +28,7 @@ import dyaml.token; /// events2 = Second event array to compare. /// /// Returns: true if the events are equivalent, false otherwise. -bool compareEvents(Event[] events1, Event[] events2) +bool compareEvents(Event[] events1, Event[] events2) @system { if(events1.length != events2.length){return false;} @@ -79,7 +79,7 @@ bool compareEvents(Event[] events1, Event[] events2) /// dataFilename = YAML file to parse. /// canonicalFilename = Canonical YAML file used as dummy to determine /// which data files to load. -void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilename) +void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilename) @system { //Must exist due to Anchor, Tags reference counts. auto loader = Loader(dataFilename); @@ -108,7 +108,7 @@ void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilena /// /// Params: verbose = Print verbose output? /// canonicalFilename = Canonical YAML file to parse. -void testEmitterOnCanonical(bool verbose, string canonicalFilename) +void testEmitterOnCanonical(bool verbose, string canonicalFilename) @system { //Must exist due to Anchor, Tags reference counts. auto loader = Loader(canonicalFilename); @@ -141,7 +141,7 @@ void testEmitterOnCanonical(bool verbose, string canonicalFilename) /// dataFilename = YAML file to parse. /// canonicalFilename = Canonical YAML file used as dummy to determine /// which data files to load. -void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilename) +void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilename) @system { foreach(filename; [dataFilename, canonicalFilename]) { @@ -194,7 +194,7 @@ void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilena } } -unittest +@system unittest { writeln("D:YAML Emitter unittest"); run("testEmitterOnData", &testEmitterOnData, ["data", "canonical"]); diff --git a/source/dyaml/test/errors.d b/source/dyaml/test/errors.d index c8a3bc8..e6ea038 100644 --- a/source/dyaml/test/errors.d +++ b/source/dyaml/test/errors.d @@ -19,7 +19,7 @@ import dyaml.test.common; /// /// Params: verbose = Print verbose output? /// errorFilename = File name to read from. -void testLoaderError(bool verbose, string errorFilename) +void testLoaderError(bool verbose, string errorFilename) @safe { auto buffer = std.file.read(errorFilename); @@ -27,7 +27,7 @@ void testLoaderError(bool verbose, string errorFilename) try { nodes = Loader(buffer).loadAll(); } catch(YAMLException e) { - if(verbose) { writeln(typeid(e).toString(), "\n", e); } + printException(e, verbose); return; } assert(false, "Expected an exception"); @@ -37,7 +37,7 @@ void testLoaderError(bool verbose, string errorFilename) /// /// Params: verbose = Print verbose output? /// errorFilename = File name to read from. -void testLoaderErrorString(bool verbose, string errorFilename) +void testLoaderErrorString(bool verbose, string errorFilename) @safe { // Load file to a buffer, then pass that to the YAML loader. auto buffer = std.file.read(errorFilename); @@ -48,7 +48,7 @@ void testLoaderErrorString(bool verbose, string errorFilename) } catch(YAMLException e) { - if(verbose) { writeln(typeid(e).toString(), "\n", e); } + printException(e, verbose); return; } assert(false, "Expected an exception"); @@ -58,12 +58,12 @@ void testLoaderErrorString(bool verbose, string errorFilename) /// /// Params: verbose = Print verbose output? /// errorFilename = File name to read from. -void testLoaderErrorFilename(bool verbose, string errorFilename) +void testLoaderErrorFilename(bool verbose, string errorFilename) @safe { try { auto nodes = Loader(errorFilename).loadAll(); } catch(YAMLException e) { - if(verbose) { writeln(typeid(e).toString(), "\n", e); } + printException(e, verbose); return; } assert(false, "testLoaderErrorSingle(" ~ verbose.to!string ~ @@ -74,19 +74,18 @@ void testLoaderErrorFilename(bool verbose, string errorFilename) /// /// Params: verbose = Print verbose output? /// errorFilename = File name to read from. -void testLoaderErrorSingle(bool verbose, string errorFilename) +void testLoaderErrorSingle(bool verbose, string errorFilename) @safe { try { auto nodes = Loader(errorFilename).load(); } catch(YAMLException e) { - if(verbose) { writeln(typeid(e).toString(), "\n", e); } + printException(e, verbose); return; } assert(false, "Expected an exception"); } - -unittest +@safe unittest { writeln("D:YAML Errors unittest"); run("testLoaderError", &testLoaderError, ["loader-error"]); diff --git a/source/dyaml/test/inputoutput.d b/source/dyaml/test/inputoutput.d index 248826f..80a1a66 100644 --- a/source/dyaml/test/inputoutput.d +++ b/source/dyaml/test/inputoutput.d @@ -25,10 +25,10 @@ alias std.system.endian endian; /// Params: wrong = Get the incorrect BOM for this system. /// /// Returns: UTF-16 byte order mark. -wchar bom16(bool wrong = false) pure +wchar bom16(bool wrong = false) pure @safe { - wchar little = *(cast(wchar*)ByteOrderMarks[BOM.UTF16LE]); - wchar big = *(cast(wchar*)ByteOrderMarks[BOM.UTF16BE]); + wchar little = '\uFEFF'; + wchar big = '\uFFFE'; if(!wrong){return endian == Endian.littleEndian ? little : big;} return endian == Endian.littleEndian ? big : little; } @@ -38,10 +38,10 @@ wchar bom16(bool wrong = false) pure /// Params: wrong = Get the incorrect BOM for this system. /// /// Returns: UTF-32 byte order mark. -dchar bom32(bool wrong = false) pure +dchar bom32(bool wrong = false) pure @safe { - dchar little = *(cast(dchar*)ByteOrderMarks[BOM.UTF32LE]); - dchar big = *(cast(dchar*)ByteOrderMarks[BOM.UTF32BE]); + dchar little = '\uFEFF'; + dchar big = '\uFFFE'; if(!wrong){return endian == Endian.littleEndian ? little : big;} return endian == Endian.littleEndian ? big : little; } @@ -50,7 +50,7 @@ dchar bom32(bool wrong = false) pure /// /// Params: verbose = Print verbose output? /// unicodeFilename = File name to read from. -void testUnicodeInput(bool verbose, string unicodeFilename) +void testUnicodeInput(bool verbose, string unicodeFilename) @safe { string data = readText(unicodeFilename); string expected = data.split().join(" "); @@ -70,7 +70,7 @@ void testUnicodeInput(bool verbose, string unicodeFilename) /// /// Params: verbose = Print verbose output? /// unicodeFilename = File name to read from. -void testUnicodeInputErrors(bool verbose, string unicodeFilename) +void testUnicodeInputErrors(bool verbose, string unicodeFilename) @safe { string data = readText(unicodeFilename); foreach(buffer; [cast(void[])(data.to!(wchar[])), @@ -81,7 +81,7 @@ void testUnicodeInputErrors(bool verbose, string unicodeFilename) try { Loader(buffer).load(); } catch(YAMLException e) { - if(verbose) { writeln(typeid(e).toString(), "\n", e); } + printException(e, verbose); continue; } assert(false, "Expected an exception"); @@ -89,7 +89,7 @@ void testUnicodeInputErrors(bool verbose, string unicodeFilename) } -unittest +@safe unittest { writeln("D:YAML I/O unittest"); run("testUnicodeInput", &testUnicodeInput, ["unicode"]); diff --git a/source/dyaml/test/reader.d b/source/dyaml/test/reader.d index 1d887b5..597aff8 100644 --- a/source/dyaml/test/reader.d +++ b/source/dyaml/test/reader.d @@ -18,7 +18,7 @@ import dyaml.reader; // // Params: verbose = Print verbose output? // data = Stream to read. -void runReader(const bool verbose, void[] fileData) +void runReader(const bool verbose, ubyte[] fileData) @safe { try { @@ -27,7 +27,7 @@ void runReader(const bool verbose, void[] fileData) } catch(ReaderException e) { - if(verbose) { writeln(typeid(e).toString(), "\n", e); } + printException(e, verbose); return; } assert(false, "Expected an exception"); @@ -38,13 +38,13 @@ void runReader(const bool verbose, void[] fileData) /// /// Params: verbose = Print verbose output? /// errorFilename = File name to read from. -void testStreamError(bool verbose, string errorFilename) +void testStreamError(bool verbose, string errorFilename) @trusted { import std.file; - runReader(verbose, std.file.read(errorFilename)); + runReader(verbose, cast(ubyte[])std.file.read(errorFilename)); } -unittest +@safe unittest { writeln("D:YAML Reader unittest"); run("testStreamError", &testStreamError, ["stream-error"]); diff --git a/source/dyaml/test/representer.d b/source/dyaml/test/representer.d index 27250b0..969b53f 100644 --- a/source/dyaml/test/representer.d +++ b/source/dyaml/test/representer.d @@ -24,7 +24,7 @@ import dyaml.test.constructor; /// codeFilename = File name to determine test case from. /// Nothing is read from this file, it only exists /// to specify that we need a matching unittest. -void testRepresenterTypes(bool verbose, string codeFilename) +void testRepresenterTypes(bool verbose, string codeFilename) @trusted { string baseName = codeFilename.baseName.stripExtension; enforce((baseName in dyaml.test.constructor.expected) !is null, @@ -77,7 +77,7 @@ void testRepresenterTypes(bool verbose, string codeFilename) } } -unittest +@safe unittest { writeln("D:YAML Representer unittest"); run("testRepresenterTypes", &testRepresenterTypes, ["code"]); diff --git a/source/dyaml/test/resolver.d b/source/dyaml/test/resolver.d index 90055f0..2cd4157 100644 --- a/source/dyaml/test/resolver.d +++ b/source/dyaml/test/resolver.d @@ -23,7 +23,7 @@ import dyaml.test.common; * dataFilename = File with unittest data. * detectFilename = Dummy filename used to specify which data filenames to use. */ -void testImplicitResolver(bool verbose, string dataFilename, string detectFilename) +void testImplicitResolver(bool verbose, string dataFilename, string detectFilename) @safe { string correctTag; Node node; @@ -48,7 +48,7 @@ void testImplicitResolver(bool verbose, string dataFilename, string detectFilena } -unittest +@safe unittest { writeln("D:YAML Resolver unittest"); run("testImplicitResolver", &testImplicitResolver, ["data", "detect"]); diff --git a/source/dyaml/test/tokens.d b/source/dyaml/test/tokens.d index 13ad879..6dfd0eb 100644 --- a/source/dyaml/test/tokens.d +++ b/source/dyaml/test/tokens.d @@ -24,7 +24,7 @@ import dyaml.token; * dataFilename = File to scan. * tokensFilename = File containing expected tokens. */ -void testTokens(bool verbose, string dataFilename, string tokensFilename) +void testTokens(bool verbose, string dataFilename, string tokensFilename) @safe { //representations of YAML tokens in tokens file. auto replace = [TokenID.Directive : "%" , @@ -72,7 +72,7 @@ void testTokens(bool verbose, string dataFilename, string tokensFilename) * dataFilename = File to scan. * canonicalFilename = Another file to scan, in canonical YAML format. */ -void testScanner(bool verbose, string dataFilename, string canonicalFilename) +void testScanner(bool verbose, string dataFilename, string canonicalFilename) @safe { foreach(filename; [dataFilename, canonicalFilename]) { @@ -86,7 +86,7 @@ void testScanner(bool verbose, string dataFilename, string canonicalFilename) } } -unittest +@safe unittest { writeln("D:YAML tokens unittest"); run("testTokens", &testTokens, ["data", "tokens"]); diff --git a/source/dyaml/token.d b/source/dyaml/token.d index ef99acb..7a49d0b 100644 --- a/source/dyaml/token.d +++ b/source/dyaml/token.d @@ -97,16 +97,14 @@ struct Token static assert(Token.sizeof <= 32, "Token has unexpected size"); -@safe pure nothrow @nogc: - /// Construct a directive token. /// /// Params: start = Start position of the token. /// end = End position of the token. /// value = Value of the token. /// directive = Directive type (YAML or TAG in YAML 1.1). -Token directiveToken(const Mark start, const Mark end, char[] value, - DirectiveType directive, const uint nameEnd) +Token directiveToken(const Mark start, const Mark end, char[] value, + DirectiveType directive, const uint nameEnd) @safe pure nothrow @nogc { return Token(value, start, end, TokenID.Directive, ScalarStyle.init, Encoding.init, directive, nameEnd); @@ -127,7 +125,7 @@ Token simpleToken(TokenID id)(const Mark start, const Mark end) /// Params: start = Start position of the token. /// end = End position of the token. /// encoding = Encoding of the stream. -Token streamStartToken(const Mark start, const Mark end, const Encoding encoding) +Token streamStartToken(const Mark start, const Mark end, const Encoding encoding) @safe pure nothrow @nogc { return Token(null, start, end, TokenID.StreamStart, ScalarStyle.Invalid, encoding); } @@ -168,7 +166,7 @@ alias simpleValueToken!(TokenID.Anchor) anchorToken; /// end = End position of the token. /// value = Value of the token. /// style = Style of the token. -Token scalarToken(const Mark start, const Mark end, char[] value, const ScalarStyle style) +Token scalarToken(const Mark start, const Mark end, char[] value, const ScalarStyle style) @safe pure nothrow @nogc { return Token(value, start, end, TokenID.Scalar, style); } diff --git a/source/dyaml/unused.d b/source/dyaml/unused.d index c301efe..73864f7 100644 --- a/source/dyaml/unused.d +++ b/source/dyaml/unused.d @@ -47,7 +47,7 @@ auto decodeUTF(ubyte[] input, UTFEncoding encoding) @safe pure nothrow // result = A Result struct to put decoded result and any error messages to. // // On error, result.errorMessage will be set. - static void decode(C)(C[] input, ref Result result) @safe pure nothrow + static void decode(C)(C[] input, ref Result result) { // End of part of input that contains complete characters that can be decoded. const size_t end = endOfLastUTFSequence(input); @@ -107,7 +107,6 @@ auto decodeUTF(ubyte[] input, UTFEncoding encoding) @safe pure nothrow // Determine the end of last UTF-8 or UTF-16 sequence in a raw buffer. size_t endOfLastUTFSequence(C)(const C[] buffer) - @safe pure nothrow @nogc { static if(is(C == char)) {