1 module dyaml.stream;
2 
3 enum BOM
4 {
5     UTF8,           /// UTF-8
6     UTF16LE,        /// UTF-16 Little Endian
7     UTF16BE,        /// UTF-16 Big Endian
8     UTF32LE,        /// UTF-32 Little Endian
9     UTF32BE,        /// UTF-32 Big Endian
10 }
11 
12 import std.system;
13 
14 private enum int NBOMS = 5;
15 immutable Endian[NBOMS] BOMEndian =
16 [
17     std.system.endian,
18     Endian.littleEndian, Endian.bigEndian,
19     Endian.littleEndian, Endian.bigEndian
20 ];
21 
22 immutable ubyte[][NBOMS] ByteOrderMarks =
23 [
24     [0xEF, 0xBB, 0xBF],
25     [0xFF, 0xFE],
26     [0xFE, 0xFF],
27     [0xFF, 0xFE, 0x00, 0x00],
28     [0x00, 0x00, 0xFE, 0xFF]
29 ];
30 
31 interface YStream
32 {
33     void writeExact(const void* buffer, size_t size);
34     size_t write(const(ubyte)[] buffer);
35     size_t write(const(char)[] str);
36     void flush();
37     @property bool writeable();
38 }
39 
40 class YMemoryStream : YStream
41 {
42     ubyte[] data;
43 
44     void writeExact(const void* buffer, size_t size)
45     {
46         data ~= cast(ubyte[])buffer[0 .. size];
47     }
48 
49     size_t write(const(ubyte)[] buffer)
50     {
51         data ~= buffer;
52         return buffer.length;
53     }
54 
55     size_t write(const(char)[] str)
56     {
57         return write(cast(const(ubyte)[])str);
58     }
59 
60     void flush() {}
61 
62     @property bool writeable() { return true; }
63 }
64 
65 class YFile : YStream
66 {
67     static import std.stdio;
68     std.stdio.File file;
69 
70     this(string fn)
71     {
72         this.file = std.stdio.File(fn, "w");
73     }
74 
75     this(std.stdio.File file)
76     {
77         this.file = file;
78     }
79 
80     unittest
81     {
82         import std.stdio : stdout;
83         auto stream = new YFile(stdout);
84         stream.write("Test writing to stdout through YFile stream\n");
85     }
86 
87     void writeExact(const void* buffer, size_t size)
88     {
89         this.file.rawWrite(cast(const) buffer[0 .. size]);
90     }
91 
92     size_t write(const(ubyte)[] buffer)
93     {
94         this.file.rawWrite(buffer);
95         return buffer.length;
96     }
97 
98     size_t write(const(char)[] str)
99     {
100         return write(cast(const(ubyte)[])str);
101     }
102 
103     void flush()
104     {
105         this.file.flush();
106     }
107 
108     @property bool writeable() { return true; }
109 }
110 
111 unittest
112 {
113     import dyaml.dumper, dyaml.loader, dyaml.node;
114     import std.file : readText, remove;
115 
116     char[] test =  ("Hello World : [Hello, World]\n" ~
117                     "Answer: 42").dup;
118     //Read the input.
119     Node expected = Loader.fromString(test).load();
120     assert(expected["Hello World"][0] == "Hello");
121     assert(expected["Hello World"][1] == "World");
122     assert(expected["Answer"].as!int == 42);
123 
124     //Dump the loaded document to output.yaml.
125     Dumper("output.yaml").dump(expected);
126 
127     // Load the file and verify that it was saved correctly.
128     Node actual = Loader("output.yaml").load();
129     assert(actual["Hello World"][0] == "Hello");
130     assert(actual["Hello World"][1] == "World");
131     assert(actual["Answer"].as!int == 42);
132     assert(actual == expected);
133 
134     // Clean up.
135     remove("output.yaml");
136 }