1 /** 2 * Object-oriented interfaces and classes for dealing with streams. The symbols 3 * defined in this module are only available when not in "BetterC" mode, as 4 * they require the use of the Garbage Collector. 5 */ 6 module streams.interfaces; 7 8 import streams.primitives; 9 10 version (D_BetterC) {} else { 11 12 /** 13 * Interface defining an input stream object that reads elements from some 14 * resource. 15 */ 16 interface InputStream(E) { 17 /** 18 * Reads elements from a resource and writes them to `buffer`. 19 * Params: 20 * buffer = The buffer to read elements into. 21 * Returns: The stream result. 22 */ 23 StreamResult readFromStream(E[] buffer); 24 } 25 26 /** 27 * Interface defining an output stream object that writes elements to some 28 * resource. 29 */ 30 interface OutputStream(E) { 31 /** 32 * Writes elements from `buffer` to a resource. 33 * Params: 34 * buffer = The buffer containing elements to write. 35 * Returns: The stream result. 36 */ 37 StreamResult writeToStream(E[] buffer); 38 } 39 40 /** 41 * Interface defining a stream that is closable. 42 */ 43 interface ClosableStream { 44 /** 45 * Closes the stream. 46 * Returns: An optional stream error, if closing the stream fails. 47 */ 48 OptionalStreamError closeStream(); 49 } 50 51 /** 52 * Interface defining a stream that is flushable. 53 */ 54 interface FlushableStream { 55 /** 56 * Flushes the stream. 57 * Returns: An optional stream error, if flushing the stream fails. 58 */ 59 OptionalStreamError flushStream(); 60 } 61 62 /** 63 * Input stream implementation that wraps around a primitive input stream. 64 */ 65 class InputStreamObject(S, E = StreamType!S) : InputStream!E if (isInputStream!(S, E)) { 66 private S stream; 67 68 /** 69 * Constructs the input stream wrapper with the given base stream. 70 * Params: 71 * stream = The stream to wrap in an object-oriented stream. 72 */ 73 this(S stream) { 74 this.stream = stream; 75 } 76 77 /** 78 * Reads up to `buffer.length` elements from the wrapped input stream, and 79 * writes them to `buffer`. 80 * Params: 81 * buffer = The buffer to read elements into. 82 * Returns: Either the number of elements read, or a stream error. 83 */ 84 StreamResult readFromStream(E[] buffer) { 85 return this.stream.readFromStream(buffer); 86 } 87 88 static if (isClosableStream!S) { 89 OptionalStreamError closeStream() { 90 return this.stream.closeStream(); 91 } 92 } 93 } 94 95 /** 96 * Gets a new object-oriented input stream implementation that wraps the given 97 * input stream. 98 * Params: 99 * stream = The stream to wrap. 100 * Returns: An input stream wrapper object. 101 */ 102 InputStreamObject!(S, E) inputStreamObjectFor(S, E = StreamType!S)(S stream) if (isInputStream!(S, E)) { 103 return new InputStreamObject!(S, E)(stream); 104 } 105 106 /** 107 * Output stream implementation that wraps around a primitive output stream. 108 */ 109 class OutputStreamObject(S, E = StreamType!S) : OutputStream!E if (isOutputStream!(S, E)) { 110 private S stream; 111 112 /** 113 * Constructs the output stream wrapper with a reference to a primitive 114 * output stream. 115 * Params: 116 * stream = The stream to wrap in an object-oriented stream. 117 */ 118 this(S stream) { 119 this.stream = stream; 120 } 121 122 /** 123 * Writes up to `buffer.length` elements to the wrapped output stream. 124 * Params: 125 * buffer = The buffer to write elements from. 126 * Returns: Either the number of elements written, or a stream error. 127 */ 128 StreamResult writeToStream(E[] buffer) { 129 return this.stream.writeToStream(buffer); 130 } 131 132 static if (isClosableStream!S) { 133 OptionalStreamError closeStream() { 134 return this.stream.closeStream(); 135 } 136 } 137 138 static if (isFlushableStream!S) { 139 OptionalStreamError flushStream() { 140 return this.stream.flushStream(); 141 } 142 } 143 } 144 145 /** 146 * Gets a new object-oriented output stream implementation that wraps the given 147 * output stream. 148 * Params: 149 * stream = The stream to wrap. 150 * Returns: An output stream wrapper object. 151 */ 152 OutputStreamObject!(S, E) outputStreamObjectFor(S, E = StreamType!S)(S stream) if (isOutputStream!(S, E)) { 153 return new OutputStreamObject!(S, E)(stream); 154 } 155 156 unittest { 157 import streams; 158 // Test input stream wrapper. 159 auto sIn1 = arrayInputStreamFor!ubyte([1, 2, 3, 4]); 160 auto wrapIn1 = new InputStreamObject!(typeof(&sIn1))(&sIn1); 161 ubyte[] buffer1 = new ubyte[4]; 162 assert(wrapIn1.readFromStream(buffer1) == StreamResult(4)); 163 assert(buffer1 == [1, 2, 3, 4]); 164 // Test using the function to make it easier. 165 sIn1.reset(); 166 wrapIn1 = inputStreamObjectFor(&sIn1); 167 assert(wrapIn1.readFromStream(buffer1[0 .. 2]) == StreamResult(2)); 168 assert(buffer1[0 .. 2] == [1, 2]); 169 170 // Test output stream wrapper. 171 auto sOut1 = byteArrayOutputStream(); 172 auto wrapOut1 = new OutputStreamObject!(typeof(&sOut1))(&sOut1); 173 assert(wrapOut1.writeToStream([1]) == StreamResult(1)); 174 assert(sOut1.toArrayRaw() == [1]); 175 wrapOut1 = outputStreamObjectFor(&sOut1); 176 assert(wrapOut1.writeToStream([2, 3, 4]) == StreamResult(3)); 177 assert(sOut1.toArrayRaw() == [1, 2, 3, 4]); 178 } 179 180 }