Merge branch 'burner-stream_replacement'

This commit is contained in:
Ferdinand Majerech 2016-04-30 14:31:44 +02:00
commit b2ad1b41b3
11 changed files with 109 additions and 118 deletions

View file

@ -12,9 +12,10 @@
module dyaml.dumper; module dyaml.dumper;
import std.stream; //import std.stream;
import std.typecons; import std.typecons;
import dyaml.stream;
import dyaml.anchor; import dyaml.anchor;
import dyaml.emitter; import dyaml.emitter;
import dyaml.encoding; import dyaml.encoding;
@ -59,7 +60,7 @@ import dyaml.tagdirective;
* Write to memory: * Write to memory:
* -------------------- * --------------------
* import std.stream; * import std.stream;
* auto stream = new MemoryStream(); * auto stream = new YMemoryStream();
* auto node = Node([1, 2, 3, 4, 5]); * auto node = Node([1, 2, 3, 4, 5]);
* Dumper(stream).dump(node); * Dumper(stream).dump(node);
* -------------------- * --------------------
@ -83,20 +84,20 @@ struct Dumper
unittest unittest
{ {
auto node = Node([1, 2, 3, 4, 5]); auto node = Node([1, 2, 3, 4, 5]);
Dumper(new MemoryStream()).dump(node); Dumper(new YMemoryStream()).dump(node);
} }
unittest unittest
{ {
auto node1 = Node([1, 2, 3, 4, 5]); auto node1 = Node([1, 2, 3, 4, 5]);
auto node2 = Node("This document contains only one string"); auto node2 = Node("This document contains only one string");
Dumper(new MemoryStream()).dump(node1, node2); Dumper(new YMemoryStream()).dump(node1, node2);
} }
unittest unittest
{ {
import std.stream; //import std.stream;
auto stream = new MemoryStream(); auto stream = new YMemoryStream();
auto node = Node([1, 2, 3, 4, 5]); auto node = Node([1, 2, 3, 4, 5]);
Dumper(stream).dump(node); Dumper(stream).dump(node);
} }
@ -106,7 +107,7 @@ struct Dumper
auto node = Node([1, 2, 3, 4, 5]); auto node = Node([1, 2, 3, 4, 5]);
auto representer = new Representer(); auto representer = new Representer();
auto resolver = new Resolver(); auto resolver = new Resolver();
auto dumper = Dumper(new MemoryStream()); auto dumper = Dumper(new YMemoryStream());
dumper.representer = representer; dumper.representer = representer;
dumper.resolver = resolver; dumper.resolver = resolver;
dumper.dump(node); dumper.dump(node);
@ -119,7 +120,7 @@ struct Dumper
Representer representer_; Representer representer_;
//Stream to write to. //Stream to write to.
Stream stream_; YStream stream_;
//True if this Dumper owns stream_ and needs to destroy it in the destructor. //True if this Dumper owns stream_ and needs to destroy it in the destructor.
bool weOwnStream_ = false; bool weOwnStream_ = false;
@ -160,8 +161,10 @@ struct Dumper
this(string filename) @trusted this(string filename) @trusted
{ {
name_ = filename; name_ = filename;
try{this(new File(filename, FileMode.OutNew));} //try{this(new File(filename, FileMode.OutNew));}
catch(StreamException e) try{this(new YFile(filename));}
//catch(StreamException e)
catch(Exception e)
{ {
throw new YAMLException("Unable to open file " ~ filename ~ throw new YAMLException("Unable to open file " ~ filename ~
" for YAML dumping: " ~ e.msg); " for YAML dumping: " ~ e.msg);
@ -171,7 +174,7 @@ struct Dumper
} }
///Construct a Dumper writing to a _stream. This is useful to e.g. write to memory. ///Construct a Dumper writing to a _stream. This is useful to e.g. write to memory.
this(Stream stream) @safe this(YStream stream) @safe
{ {
resolver_ = new Resolver(); resolver_ = new Resolver();
representer_ = new Representer(); representer_ = new Representer();

View file

@ -18,12 +18,12 @@ import std.conv;
import std.exception; import std.exception;
import std.format; import std.format;
import std.range; import std.range;
import std.stream;
import std.string; import std.string;
import std.system; import std.system;
import std.typecons; import std.typecons;
import std.utf; import std.utf;
import dyaml.stream;
import dyaml.anchor; import dyaml.anchor;
import dyaml.encoding; import dyaml.encoding;
import dyaml.escapes; import dyaml.escapes;
@ -81,7 +81,7 @@ struct Emitter
[TagDirective("!", "!"), TagDirective("!!", "tag:yaml.org,2002:")]; [TagDirective("!", "!"), TagDirective("!!", "tag:yaml.org,2002:")];
///Stream to write to. ///Stream to write to.
Stream stream_; YStream stream_;
///Encoding can be overriden by STREAM-START. ///Encoding can be overriden by STREAM-START.
Encoding encoding_ = Encoding.UTF_8; Encoding encoding_ = Encoding.UTF_8;
@ -163,12 +163,12 @@ struct Emitter
/** /**
* Construct an emitter. * Construct an emitter.
* *
* Params: stream = Stream to write to. Must be writable. * Params: stream = YStream to write to. Must be writable.
* canonical = Write scalars in canonical form? * canonical = Write scalars in canonical form?
* indent = Indentation width. * indent = Indentation width.
* lineBreak = Line break character/s. * lineBreak = Line break character/s.
*/ */
this(Stream stream, const bool canonical, const int indent, const int width, this(YStream stream, const bool canonical, const int indent, const int width,
const LineBreak lineBreak) @trusted const LineBreak lineBreak) @trusted
in{assert(stream.writeable, "Can't emit YAML to a non-writable stream");} in{assert(stream.writeable, "Can't emit YAML to a non-writable stream");}
body body
@ -252,7 +252,7 @@ struct Emitter
stream_.writeExact(buffer.ptr, buffer.length * dchar.sizeof); stream_.writeExact(buffer.ptr, buffer.length * dchar.sizeof);
break; break;
} }
catch(WriteException e) catch(Exception e)
{ {
throw new Error("Unable to write to stream: " ~ e.msg); throw new Error("Unable to write to stream: " ~ e.msg);
} }
@ -331,7 +331,7 @@ struct Emitter
void expectStreamStart() @trusted void expectStreamStart() @trusted
{ {
enforce(eventTypeIs(EventID.StreamStart), enforce(eventTypeIs(EventID.StreamStart),
new Error("Expected StreamStart, but got " ~ event_.idString)); new Error("Expected YStreamStart, but got " ~ event_.idString));
encoding_ = event_.encoding; encoding_ = event_.encoding;
writeStreamStart(); writeStreamStart();
@ -350,7 +350,7 @@ struct Emitter
void expectDocumentStart(Flag!"first" first)() @trusted void expectDocumentStart(Flag!"first" first)() @trusted
{ {
enforce(eventTypeIs(EventID.DocumentStart) || eventTypeIs(EventID.StreamEnd), enforce(eventTypeIs(EventID.DocumentStart) || eventTypeIs(EventID.StreamEnd),
new Error("Expected DocumentStart or StreamEnd, but got " new Error("Expected DocumentStart or YStreamEnd, but got "
~ event_.idString)); ~ event_.idString));
if(event_.id == EventID.DocumentStart) if(event_.id == EventID.DocumentStart)

View file

@ -24,7 +24,7 @@ import dyaml.scanner;
import dyaml.token; import dyaml.token;
/** Loads YAML documents from files or streams. /** Loads YAML documents from files or char[].
* *
* User specified Constructor and/or Resolver can be used to support new * User specified Constructor and/or Resolver can be used to support new
* tags / data types. * tags / data types.
@ -140,12 +140,6 @@ struct Loader
} }
} }
deprecated("Loader.fromString(string) is deprecated. Use Loader.fromString(char[]) instead.")
static Loader fromString(string data)
{
return Loader(cast(ubyte[])data.dup);
}
/** Construct a Loader to load YAML from a string (char []). /** Construct a Loader to load YAML from a string (char []).
* *
* Params: data = String to load YAML from. $(B will) be overwritten during * Params: data = String to load YAML from. $(B will) be overwritten during
@ -168,25 +162,6 @@ struct Loader
assert(Loader.fromString(cast(char[])"42").load().as!int == 42); assert(Loader.fromString(cast(char[])"42").load().as!int == 42);
} }
import std.stream;
deprecated("Loader(Stream) is deprecated. Use Loader(ubyte[]) instead.")
this(Stream stream) @safe
{
try
{
import dyaml.streamcompat;
auto streamBytes = streamToBytesGC(stream);
reader_ = new Reader(streamBytes);
scanner_ = new Scanner(reader_);
parser_ = new Parser(scanner_);
}
catch(YAMLException e)
{
throw new YAMLException("Unable to open stream %s for YAML loading: %s"
.format(name_, e.msg));
}
}
/** Construct a Loader to load YAML from a buffer. /** Construct a Loader to load YAML from a buffer.
* *
* Params: yamlData = Buffer with YAML data to load. This may be e.g. a file * Params: yamlData = Buffer with YAML data to load. This may be e.g. a file

View file

@ -993,7 +993,7 @@ void testEndian(R)()
void testPeekPrefixForward(R)() void testPeekPrefixForward(R)()
{ {
import std.stream; import dyaml.stream;
writeln(typeid(R).toString() ~ ": peek/prefix/forward unittest"); writeln(typeid(R).toString() ~ ": peek/prefix/forward unittest");
ubyte[] data = ByteOrderMarks[BOM.UTF8] ~ cast(ubyte[])"data"; ubyte[] data = ByteOrderMarks[BOM.UTF8] ~ cast(ubyte[])"data";
auto reader = new R(data); auto reader = new R(data);
@ -1011,7 +1011,7 @@ void testPeekPrefixForward(R)()
void testUTF(R)() void testUTF(R)()
{ {
import std.stream; import dyaml.stream;
writeln(typeid(R).toString() ~ ": UTF formats unittest"); writeln(typeid(R).toString() ~ ": UTF formats unittest");
dchar[] data = cast(dchar[])"data"; dchar[] data = cast(dchar[])"data";
void utf_test(T)(T[] data, BOM bom) void utf_test(T)(T[] data, BOM bom)

View file

@ -676,7 +676,7 @@ Node representMyClass(ref Node node, Representer representer) @system
return representer.representScalar("!myclass.tag", scalar); return representer.representScalar("!myclass.tag", scalar);
} }
import std.stream; import dyaml.stream;
unittest unittest
{ {
@ -684,7 +684,7 @@ unittest
&representMyStructSeq, &representMyStructSeq,
&representMyStructMap]) &representMyStructMap])
{ {
auto dumper = Dumper(new MemoryStream()); auto dumper = Dumper(new YMemoryStream());
auto representer = new Representer; auto representer = new Representer;
representer.addRepresenter!MyStruct(r); representer.addRepresenter!MyStruct(r);
dumper.representer = representer; dumper.representer = representer;
@ -694,7 +694,7 @@ unittest
unittest unittest
{ {
auto dumper = Dumper(new MemoryStream()); auto dumper = Dumper(new YMemoryStream());
auto representer = new Representer; auto representer = new Representer;
representer.addRepresenter!MyClass(&representMyClass); representer.addRepresenter!MyClass(&representMyClass);
dumper.representer = representer; dumper.representer = representer;

74
source/dyaml/stream.d Normal file
View file

@ -0,0 +1,74 @@
module dyaml.stream;
enum BOM {
UTF8, /// UTF-8
UTF16LE, /// UTF-16 Little Endian
UTF16BE, /// UTF-16 Big Endian
UTF32LE, /// UTF-32 Little Endian
UTF32BE, /// UTF-32 Big Endian
}
import std.system;
private enum int NBOMS = 5;
immutable Endian[NBOMS] BOMEndian =
[ std.system.endian,
Endian.littleEndian, Endian.bigEndian,
Endian.littleEndian, Endian.bigEndian
];
immutable ubyte[][NBOMS] ByteOrderMarks =
[ [0xEF, 0xBB, 0xBF],
[0xFF, 0xFE],
[0xFE, 0xFF],
[0xFF, 0xFE, 0x00, 0x00],
[0x00, 0x00, 0xFE, 0xFF]
];
interface YStream {
void writeExact(const void* buffer, size_t size);
size_t write(const(ubyte)[] buffer);
void flush();
@property bool writeable();
}
class YMemoryStream : YStream {
ubyte[] data;
void writeExact(const void* buffer, size_t size) {
data ~= cast(ubyte[])buffer[0 .. size];
}
size_t write(const(ubyte)[] buffer) {
data ~= buffer;
return buffer.length;
}
void flush() {}
@property bool writeable() { return true; }
}
class YFile : YStream {
static import std.stdio;
std.stdio.File file;
this(string fn) {
this.file = std.stdio.File(fn, "w");
}
void writeExact(const void* buffer, size_t size) {
this.file.write(cast(const ubyte[])buffer[0 .. size]);
}
size_t write(const(ubyte)[] buffer) {
this.file.write(buffer);
return buffer.length;
}
void flush() {
this.file.flush();
}
@property bool writeable() { return true; }
}

View file

@ -1,62 +0,0 @@
// Copyright Ferdinand Majerech 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
/// Backward compatibility with std.stream (which was used by D:YAML API in the past).
module dyaml.streamcompat;
import std.stream;
import tinyendian;
/// A streamToBytes wrapper that allocates memory using the GC.
///
/// See_Also: streamToBytes
ubyte[] streamToBytesGC(Stream stream) @trusted nothrow
{
try return stream.streamToBytes(new ubyte[stream.available]);
catch(Exception e)
{
assert(false, "Unexpected exception in streamToBytesGC: " ~ e.msg);
}
}
/// Read all data from a Stream into an array of bytes.
///
/// Params:
///
/// stream = Stream to read from. Must be readable and seekable.
/// memory = Memory to use. Must be long enough to store the entire stream
/// (memory.length >= stream.available).
///
/// Returns: A slice of memory containing all contents of the stream on success.
/// NULL if unable to read the entire stream.
ubyte[] streamToBytes(Stream stream, ubyte[] memory) @system nothrow
{
try
{
assert(stream.readable && stream.seekable,
"Can't read YAML from a stream that is not readable and seekable");
assert(memory.length >= stream.available,
"Not enough memory passed to streamToBytes");
auto buffer = memory[0 .. stream.available];
size_t bytesRead = 0;
for(; bytesRead < buffer.length;)
{
// Returns 0 on eof
const bytes = stream.readBlock(&buffer[bytesRead], buffer.length - bytesRead);
// Reached EOF before reading buffer.length bytes.
if(bytes == 0) { return null; }
bytesRead += bytes;
}
return buffer;
}
catch(Exception e)
{
assert(false, "Unexpected exception in streamToBytes " ~ e.msg);
}
}

View file

@ -11,7 +11,6 @@ version(unittest)
public import std.conv; public import std.conv;
public import std.stdio; public import std.stdio;
public import std.stream;
public import dyaml.all; public import dyaml.all;
import core.exception; import core.exception;
@ -24,8 +23,6 @@ import std.typecons;
package: package:
alias std.stream.File File;
/** /**
* Run an unittest. * Run an unittest.
* *

View file

@ -15,6 +15,7 @@ import std.file;
import std.range; import std.range;
import std.typecons; import std.typecons;
import dyaml.stream;
import dyaml.dumper; import dyaml.dumper;
import dyaml.event; import dyaml.event;
import dyaml.testcommon; import dyaml.testcommon;
@ -83,7 +84,7 @@ void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilena
//Must exist due to Anchor, Tags reference counts. //Must exist due to Anchor, Tags reference counts.
auto loader = Loader(dataFilename); auto loader = Loader(dataFilename);
auto events = cast(Event[])loader.parse(); auto events = cast(Event[])loader.parse();
auto emitStream = new MemoryStream; auto emitStream = new YMemoryStream;
Dumper(emitStream).emit(events); Dumper(emitStream).emit(events);
if(verbose) if(verbose)
@ -114,7 +115,7 @@ void testEmitterOnCanonical(bool verbose, string canonicalFilename)
auto events = cast(Event[])loader.parse(); auto events = cast(Event[])loader.parse();
foreach(canonical; [false, true]) foreach(canonical; [false, true])
{ {
auto emitStream = new MemoryStream; auto emitStream = new YMemoryStream;
auto dumper = Dumper(emitStream); auto dumper = Dumper(emitStream);
dumper.canonical = canonical; dumper.canonical = canonical;
dumper.emit(events); dumper.emit(events);
@ -174,7 +175,7 @@ void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilena
} }
styledEvents ~= event; styledEvents ~= event;
} }
auto emitStream = new MemoryStream; auto emitStream = new YMemoryStream;
Dumper(emitStream).emit(styledEvents); Dumper(emitStream).emit(styledEvents);
if(verbose) if(verbose)
{ {

View file

@ -15,6 +15,7 @@ import std.file;
import std.system; import std.system;
import dyaml.testcommon; import dyaml.testcommon;
import dyaml.stream;
alias std.system.endian endian; alias std.system.endian endian;

View file

@ -48,7 +48,9 @@ void testRepresenterTypes(bool verbose, string codeFilename)
} }
} }
auto emitStream = new MemoryStream; import dyaml.stream;
auto emitStream = new YMemoryStream;
auto representer = new Representer; auto representer = new Representer;
representer.addRepresenter!TestClass(&representClass); representer.addRepresenter!TestClass(&representClass);
representer.addRepresenter!TestStruct(&representStruct); representer.addRepresenter!TestStruct(&representStruct);