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 }