1 /** 2 Stream 3 4 Copyright: (c) Enalye 2017 5 License: Zlib 6 Authors: Enalye 7 */ 8 9 module atelier.core.stream; 10 11 import std.array; 12 import std.conv; 13 import std..string; 14 import std.bitmanip; 15 16 /// Binary stream to write onto. 17 class OutStream { 18 private Appender!(const ubyte[]) _buffer; 19 20 /// Ctor. 21 this() { 22 _buffer = appender!(const ubyte[])(); 23 } 24 25 @property { 26 /// Raw buffer. 27 const(ubyte)[] data() const { 28 return _buffer.data; 29 } 30 /// Total size of the buffer. 31 size_t length() const { 32 return _buffer.data.length; 33 } 34 } 35 36 /// Append a string. 37 void write(string values) { 38 write!(char[])(cast(char[]) values); 39 } 40 41 /// Append a wstring. 42 void write(wstring values) { 43 write!(wchar[])(cast(wchar[]) values); 44 } 45 46 /// Append a dstring. 47 void write(dstring values) { 48 write!(dchar[])(cast(dchar[]) values); 49 } 50 51 /// Append an array. 52 void write(T : T[])(T[] values) { 53 //Values size. 54 ubyte[ushort.sizeof] sizeValues = nativeToBigEndian!ushort(cast(ushort) values.length); 55 foreach (ubyte b; sizeValues) 56 _buffer.append!ubyte(b); 57 //Values array. 58 foreach (T v; values) 59 foreach (ubyte b; nativeToBigEndian(v)) 60 _buffer.append!ubyte(b); 61 } 62 63 /// Append a value. 64 void write(T)(T value) { 65 //Value size. 66 ubyte[ushort.sizeof] sizeValues = nativeToBigEndian!ushort(1u); 67 foreach (ubyte b; sizeValues) 68 _buffer.append!ubyte(b); 69 //Value array. 70 foreach (ubyte b; nativeToBigEndian(value)) 71 _buffer.append!ubyte(b); 72 } 73 } 74 75 /// Binary stream to read from. 76 class InStream { 77 private ubyte[] _buffer; 78 79 @property { 80 /// Raw buffer. 81 void data(ubyte[] buffer) { 82 _buffer = buffer; 83 } 84 /// Ditto 85 ref ubyte[] data() { 86 return _buffer; 87 } 88 89 /// Total size of the buffer. 90 size_t length(size_t len) { 91 return _buffer.length = len; 92 } 93 /// Ditto 94 size_t length() const { 95 return _buffer.length; 96 } 97 } 98 99 /// Sets a raw buffer. 100 void set(const ubyte[] buffer) { 101 _buffer = buffer.dup; 102 } 103 104 /// Extract a string. 105 string read(T : string)() { 106 return read!(char[])(); 107 } 108 109 /// Extract a wstring. 110 wstring read(T : wstring)() { 111 return read!(wchar[])(); 112 } 113 114 /// Extract a dstring. 115 dstring read(T : dstring)() { 116 return read!(dchar[])(); 117 } 118 119 /// Extract an array. 120 T[] read(T : T[])() { 121 T[] values; 122 const ushort size = _buffer.read!ushort(); 123 if (size == 0) 124 return values; 125 foreach (_; 0 .. size) 126 values ~= _buffer.read!T(); 127 return values; 128 } 129 130 /// Extract a value. 131 T read(T)() { 132 const ushort size = _buffer.read!ushort(); 133 if (size != 1uL) 134 throw new Exception("Stream data does not match."); 135 return _buffer.read!T(); 136 } 137 } 138 139 unittest { 140 auto o = new OutStream; 141 auto i = new InStream; 142 143 o.write!int(179); 144 o.write!(int[])([1, 2, 3, 0, 4, 5]); 145 o.write!string("hello"); 146 o.write!bool(true); 147 i.set(o.data); 148 149 assert(i.read!int() == 179, "Stream module failure"); 150 assert(i.read!(int[])() == [1, 2, 3, 0, 4, 5], "Stream module failure"); 151 assert(i.read!string() == "hello", "Stream module failure"); 152 assert(i.read!bool() == true, "Stream module failure"); 153 }