1 module aurorafw.core.io.stream; 2 3 import core.exception; 4 import std.exception; 5 6 version (unittest) import aurorafw.unit.assertion; 7 8 enum Seek 9 { 10 SET, /// beginning of the stream 11 CUR, /// current position 12 END /// end of the stream 13 } 14 15 class StreamException : Exception 16 { 17 mixin basicExceptionCtors; 18 } 19 20 interface IStream 21 { 22 /** 23 * A property that returns the length of the stream 24 * 25 * Returns: The length of the stream in bytes 26 */ 27 @property ulong length(); 28 29 /** 30 * Current position 31 * 32 * Returns: The current positon in the stream 33 */ 34 @property ulong tell(); 35 36 /** 37 * Check if empty 38 * 39 * Returns: True if the stream is empty 40 */ 41 @property bool empty(); 42 43 /** 44 * Seekable 45 * 46 * Returns: True if the stream is seekable 47 */ 48 @property bool seekable(); 49 50 /** 51 * Sets the current position in the stream 52 * 53 * Returns: The current positon in the stream 54 * 55 * Params: 56 * pos = The number of bytes to offset from origin 57 * origin = Position used as reference for the offset. 58 */ 59 ulong seek(in long pos, in Seek origin = Seek.SET); 60 61 /** 62 * Skip n positions in the stream 63 * 64 * Returns: The current position in the stream 65 * 66 * Params: 67 * n = The number of bytes to skip 68 */ 69 ulong skip(ulong n); 70 71 /** 72 * Writable 73 * 74 * Returns: True if the stream is writeble 75 */ 76 @property bool writable(); 77 78 /** 79 * Writes an unsigned byte to the stream 80 * 81 * Params: 82 * b = The ubyte to write to the stream 83 */ 84 void write(in ubyte b); 85 86 /** 87 * Writes an array of unsigned bytes to the stream 88 * 89 * Params: 90 * b = The array of ubyte to write to the stream 91 */ 92 void write(in ubyte[] b); 93 94 /** 95 * Readable 96 * 97 * Returns: True if the stream is readable 98 */ 99 @property bool readable(); 100 101 /** 102 * Reads an unsigned byte from the stream 103 * 104 * Returns: The unsigned byte read from the stream 105 */ 106 ubyte read(); 107 108 /** 109 * Reads an array of ubytes from the stream 110 * 111 * Returns: The array of unsigned bytes read from the stream 112 * 113 * Params: 114 * n = The number of bytes to read from the stream 115 */ 116 ubyte[] read(in size_t n); 117 118 /** 119 * Reads the entire stream 120 * 121 * Returns: The array of unsigned bytes read from the stream 122 */ 123 ubyte[] data(); 124 } 125 126 version (unittest) 127 { 128 // assuming the content of the stream is "abc" 129 // and the function leave the stream at the beginning 130 package void unittest_readable_stream(IStream s) 131 { 132 assertTrue(s.seekable); 133 assertTrue(s.readable); 134 135 assertEquals(3, s.length); 136 assertFalse(s.empty); 137 138 assertEquals(0, s.seek(0, Seek.SET)); 139 assertEquals("abc", s.data); 140 assertEquals(0, s.seek(0, Seek.SET)); 141 142 assertEquals('a', s.read()); 143 assertEquals("b", s.read(1)); 144 assertEquals(1, s.seek(-1, Seek.CUR)); 145 assertEquals("bc", s.data); 146 assertEquals(2, s.seek(-1, Seek.END)); 147 assertEquals('c', s.read()); 148 expectThrows!StreamException(s.read()); 149 150 assertTrue(s.empty); 151 assertEmpty(s.data); 152 153 assertEquals(0, s.seek(0, Seek.SET)); 154 } 155 156 package void unittest_writable_stream(IStream s) 157 { 158 assertTrue(s.seekable); 159 assertTrue(s.writable); 160 ubyte[] arr = ['4', '5']; 161 s.seek(0, Seek.END); 162 s.write(arr); 163 s.write('6'); 164 if (s.readable) 165 { 166 s.seek(-3, Seek.END); 167 assertEquals(arr ~ '6', s.data); 168 } 169 170 assertEquals(0, s.seek(0, Seek.SET)); 171 } 172 }