1 /** 2 * Copyright: Copyright Jason White, 2014-2016 3 * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 * Authors: Jason White 5 */ 6 module io.stream; 7 8 public import io.stream.types; 9 public import io.stream.traits; 10 public import io.stream.shim; 11 12 import std.traits : isArray; 13 14 /** 15 * Reads exactly the number of bytes requested from the stream. Throws 16 * an exception if it cannot be done. Returns the filled buffer. 17 * 18 * Note that, because it can potentially take multiple system calls to 19 * complete the read, the read is not guaranteed to be atomic with 20 * respect to other reads. 21 * 22 * Throws: ReadException if the given buffer cannot be completely filled. 23 */ 24 T[] readExactly(Stream, T)(auto ref Stream stream, T[] buf) 25 if (isSource!(Stream)) 26 { 27 ubyte[] byteBuf = cast(ubyte[])buf; 28 29 size_t totalRead = 0; 30 while (totalRead < byteBuf.length) 31 { 32 if (immutable n = stream.read(byteBuf[totalRead .. $])) 33 totalRead += n; 34 else 35 throw new ReadException( 36 "Failed to fill entire buffer from stream" 37 ); 38 } 39 40 return buf; 41 } 42 43 /** 44 * Writes exactly the given buffer and no less. Throws an exception if 45 * it cannot be done. 46 * 47 * Note that, because it can potentially take multiple system calls to 48 * complete the write, the write is not guaranteed to be atomic with 49 * respect to other writes. 50 * 51 * Throws: WriteException if the given buffer cannot be completely written. 52 */ 53 void writeExactly(Stream, T)(auto ref Stream stream, in T[] buf) 54 if (isSink!Stream) 55 { 56 const(ubyte)[] byteBuf = cast(const(ubyte)[])buf; 57 58 size_t total = 0; 59 60 while (total < byteBuf.length) 61 { 62 if (immutable n = stream.write(byteBuf[total .. $])) 63 total += n; 64 else 65 throw new WriteException( 66 "Failed to write entire buffer to stream" 67 ); 68 } 69 } 70 71 // Ditto 72 void writeExactly(Stream, T)(auto ref Stream stream, const auto ref T value) 73 if (isSink!Stream && !isArray!T) 74 { 75 stream.writeExactly((cast(ubyte*)&value)[0 .. T.sizeof]); 76 } 77 78 /** 79 * Reads the rest of the stream. 80 */ 81 T[] readAll(T=ubyte, Stream)(auto ref Stream stream, long upTo = long.max) 82 if (isSource!Stream && isSeekable!Stream) 83 { 84 import std.algorithm : min; 85 import std.array : uninitializedArray; 86 87 immutable remaining = min((stream.length - stream.position)/T.sizeof, upTo); 88 89 auto buf = uninitializedArray!(T[])(remaining); 90 91 immutable bytesRead = stream.read(buf); 92 93 return buf[0 .. bytesRead/T.sizeof]; 94 } 95 96 /** 97 * Set the position (in bytes) of a stream. 98 */ 99 @property void position(Stream)(auto ref Stream stream, long offset) 100 if (isSeekable!Stream) 101 { 102 stream.seekTo(offset, From.start); 103 } 104 105 /** 106 * Gets the position (in bytes) of a stream. 107 */ 108 @property auto position(Stream)(auto ref Stream stream) 109 if (isSeekable!Stream) 110 { 111 return stream.seekTo(0, From.here); 112 } 113 114 /** 115 * Skip the specified number of bytes forward or backward. 116 * 117 * Returns: The position (in bytes) in the stream after the seek. 118 */ 119 long skip(Stream)(auto ref Stream stream, long offset) 120 if (isSeekable!Stream) 121 { 122 return stream.seekTo(offset, From.here); 123 }