1 /** 
2  * A collection of helper functions that augment the basic `read` and `write`
3  * functions of input and output streams.
4  */
5 module streams.functions;
6 
7 import streams.primitives;
8 
9 import std.traits;
10 
11 /**
12  * Continously reads an input stream into an in-memory buffer, until 0 elements
13  * could be read, or an error occurs.
14  * Params:
15  *   stream = The stream to read from.
16  *   bufferSize = The size of the internal buffer to use for reading.
17  * Returns: The full contents of the stream.
18  */
19 DataType[] readAll(StreamType, DataType)(
20     ref StreamType stream,
21     uint bufferSize = 8192
22 ) if (isInputStream!(StreamType, DataType)) {
23     import std.array : Appender, appender;
24     Appender!(DataType[]) app = appender!(DataType[])();
25     DataType[] buffer = new DataType[bufferSize];
26     int itemsRead;
27     while ((itemsRead = stream.read(buffer)) > 0) {
28         app ~= buffer[0 .. itemsRead];
29     }
30     return app[];
31 }
32 
33 unittest {
34     import streams;
35     import std.file;
36 
37     auto s1 = FileInputStream("LICENSE");
38     ulong expectedSize = getSize("LICENSE");
39     ubyte[] data = readAll!(FileInputStream, ubyte)(s1);
40     assert(data.length == expectedSize);
41 }
42 
43 /** 
44  * Transfers elements from an input stream to an output stream, doing so
45  * continuously until the input stream reads 0 elements or an error occurs.
46  * The streams are not closed after transfer completes.
47  * Params:
48  *   input = The input stream to read from.
49  *   output = The output stream to write to.
50  *   bufferSize = The size of the internal buffer to use for reading.
51  */
52 void transferTo(InputStreamType, OutputStreamType, DataType)(
53     ref InputStreamType input,
54     ref OutputStreamType output,
55     uint bufferSize = 8192
56 ) if (isInputStream!(InputStreamType, DataType) && isOutputStream!(OutputStreamType, DataType)) {
57     DataType[] buffer = new DataType[bufferSize];
58     int itemsRead;
59     while ((itemsRead = input.read(buffer)) > 0) {
60         int written = output.write(buffer[0 .. itemsRead]);
61         if (written != itemsRead) {
62             throw new StreamException("Failed to transfer bytes.");
63         }
64     }
65 }
66 
67 unittest {
68     import streams;
69     import std.file;
70 
71     auto sIn = FileInputStream("LICENSE");
72     auto sOut = FileOutputStream("LICENSE-COPY");
73     scope(exit) {
74         std.file.remove("LICENSE-COPY");
75     }
76     transferTo!(FileInputStream, FileOutputStream, ubyte)(sIn, sOut);
77     sIn.close();
78     sOut.close();
79     assert(getSize("LICENSE") == getSize("LICENSE-COPY"));
80 }