1 /** 
2  * A collection of array-backed streams for in-memory reading and writing.
3  */
4 module streams.types.array;
5 
6 /** 
7  * An input stream that reads from an array of items.
8  */
9 struct ArrayInputStream(DataType) {
10     private DataType[] array;
11     private uint currentIndex = 0;
12 
13     int read(DataType[] buffer) {
14         if (this.currentIndex >= this.array.length) return 0;
15         uint bufferLength = cast(uint) buffer.length;
16         uint lengthRemaining = cast(uint) this.array.length - this.currentIndex;
17         uint lengthToRead = lengthRemaining < bufferLength ? lengthRemaining : bufferLength;
18         buffer[0 .. lengthToRead] = this.array[this.currentIndex .. this.currentIndex + lengthToRead];
19         this.currentIndex += lengthToRead;
20         return lengthToRead;
21     }
22 
23     void reset() {
24         this.currentIndex = 0;
25     }
26 }
27 
28 unittest {
29     import streams.primitives;
30 
31     assert(isSomeInputStream!(ArrayInputStream!int));
32     assert(isInputStream!(ArrayInputStream!ubyte, ubyte));
33 
34     auto s1 = ArrayInputStream!int([1, 2, 3, 4, 5]);
35     int[] buffer = new int[2];
36     assert(s1.read(buffer) == 2);
37     assert(buffer == [1, 2]);
38     assert(s1.read(buffer) == 2);
39     assert(buffer == [3, 4]);
40     assert(s1.read(buffer) == 1);
41     assert(buffer == [5, 4]);
42 }
43 
44 /** 
45  * Creates and returns an array input stream wrapped around the given array
46  * of elements.
47  * Params:
48  *   array = The array to stream.
49  * Returns: The array input stream.
50  */
51 ArrayInputStream!T inputStreamFor(T)(T[] array) {
52     return ArrayInputStream!T(array);
53 }
54 
55 /** 
56  * An output stream that writes to an internal array. The resulting array can
57  * be obtained with `toArray()`.
58  */
59 struct ArrayOutputStream(DataType) {
60     import std.array : Appender, appender;
61 
62     private Appender!(DataType[]) app;
63 
64     int write(DataType[] buffer) {
65         this.app ~= buffer;
66         return cast(int) buffer.length;
67     }
68 
69     /** 
70      * Gets the internal array to which elements have been appended.
71      * Returns: The internal array.
72      */
73     DataType[] toArray() {
74         return this.app[];
75     }
76 
77     void reset() {
78         this.app = appender!(DataType[])();
79     }
80 }
81 
82 unittest {
83     import streams.primitives;
84 
85     assert(isSomeOutputStream!(ArrayOutputStream!bool));
86 
87     auto s1 = ArrayOutputStream!float();
88     float[] buffer = [0.5, 1, 1.5];
89     assert(s1.write(buffer) == 3);
90     buffer = [2, 2.5, 3];
91     assert(s1.write(buffer) == 3);
92     assert(s1.toArray() == [0.5, 1, 1.5, 2, 2.5, 3]);
93 
94     auto s2 = ArrayOutputStream!ubyte();
95     ubyte[] buffer1 = [1, 2, 3];
96     s2.write(buffer1);
97     ubyte[] data = s2.toArray();
98     assert(data == [1, 2, 3]);
99 }