diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2018-02-05 07:38:24 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2018-02-05 07:38:24 -0500 |
| commit | b7bc259093ccad98cdc5661c493c0bdb4771e899 (patch) | |
| tree | 8f7730bdc0e79c240309ec4394b3c3e977d36653 /std/io.zig | |
| parent | 893f1088dfe40b0141ac6988a1ae6b165f7cc643 (diff) | |
| download | zig-b7bc259093ccad98cdc5661c493c0bdb4771e899.tar.gz zig-b7bc259093ccad98cdc5661c493c0bdb4771e899.zip | |
make OutStream and InStream take an error set param
Diffstat (limited to 'std/io.zig')
| -rw-r--r-- | std/io.zig | 284 |
1 files changed, 148 insertions, 136 deletions
diff --git a/std/io.zig b/std/io.zig index dbca37745a..50b70db645 100644 --- a/std/io.zig +++ b/std/io.zig @@ -61,18 +61,21 @@ pub fn getStdIn() GetStdIoErrs!File { /// Implementation of InStream trait for File pub const FileInStream = struct { file: &File, - stream: InStream, + stream: Stream, + + pub const Error = @typeOf(File.read).ReturnType.ErrorSet; + pub const Stream = InStream(Error); pub fn init(file: &File) FileInStream { return FileInStream { .file = file, - .stream = InStream { + .stream = Stream { .readFn = readFn, }, }; } - fn readFn(in_stream: &InStream, buffer: []u8) !usize { + fn readFn(in_stream: &Stream, buffer: []u8) Error!usize { const self = @fieldParentPtr(FileInStream, "stream", in_stream); return self.file.read(buffer); } @@ -81,18 +84,21 @@ pub const FileInStream = struct { /// Implementation of OutStream trait for File pub const FileOutStream = struct { file: &File, - stream: OutStream, + stream: Stream, + + pub const Error = File.WriteError; + pub const Stream = OutStream(Error); pub fn init(file: &File) FileOutStream { return FileOutStream { .file = file, - .stream = OutStream { + .stream = Stream { .writeFn = writeFn, }, }; } - fn writeFn(out_stream: &OutStream, bytes: []const u8) !void { + fn writeFn(out_stream: &Stream, bytes: []const u8) !void { const self = @fieldParentPtr(FileOutStream, "stream", out_stream); return self.file.write(bytes); } @@ -298,6 +304,8 @@ pub const File = struct { } } + pub const ReadError = error {}; + pub fn read(self: &File, buffer: []u8) !usize { if (is_posix) { var index: usize = 0; @@ -340,7 +348,7 @@ pub const File = struct { } } - const WriteError = os.WindowsWriteError || os.PosixWriteError; + pub const WriteError = os.WindowsWriteError || os.PosixWriteError; fn write(self: &File, bytes: []const u8) WriteError!void { if (is_posix) { @@ -353,161 +361,165 @@ pub const File = struct { } }; -pub const InStream = struct { - // TODO allow specifying the error set - /// Return the number of bytes read. If the number read is smaller than buf.len, it - /// means the stream reached the end. Reaching the end of a stream is not an error - /// condition. - readFn: fn(self: &InStream, buffer: []u8) error!usize, - - /// Replaces `buffer` contents by reading from the stream until it is finished. - /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and - /// the contents read from the stream are lost. - pub fn readAllBuffer(self: &InStream, buffer: &Buffer, max_size: usize) !void { - try buffer.resize(0); - - var actual_buf_len: usize = 0; - while (true) { - const dest_slice = buffer.toSlice()[actual_buf_len..]; - const bytes_read = try self.readFn(self, dest_slice); - actual_buf_len += bytes_read; - - if (bytes_read != dest_slice.len) { - buffer.shrink(actual_buf_len); - return; - } - - const new_buf_size = math.min(max_size, actual_buf_len + os.page_size); - if (new_buf_size == actual_buf_len) - return error.StreamTooLong; - try buffer.resize(new_buf_size); - } - } +pub fn InStream(comptime Error: type) type { + return struct { + const Self = this; - /// Allocates enough memory to hold all the contents of the stream. If the allocated - /// memory would be greater than `max_size`, returns `error.StreamTooLong`. - /// Caller owns returned memory. - /// If this function returns an error, the contents from the stream read so far are lost. - pub fn readAllAlloc(self: &InStream, allocator: &mem.Allocator, max_size: usize) ![]u8 { - var buf = Buffer.initNull(allocator); - defer buf.deinit(); + /// Return the number of bytes read. If the number read is smaller than buf.len, it + /// means the stream reached the end. Reaching the end of a stream is not an error + /// condition. + readFn: fn(self: &Self, buffer: []u8) Error!usize, - try self.readAllBuffer(&buf, max_size); - return buf.toOwnedSlice(); - } + /// Replaces `buffer` contents by reading from the stream until it is finished. + /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and + /// the contents read from the stream are lost. + pub fn readAllBuffer(self: &Self, buffer: &Buffer, max_size: usize) !void { + try buffer.resize(0); - /// Replaces `buffer` contents by reading from the stream until `delimiter` is found. - /// Does not include the delimiter in the result. - /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents - /// read from the stream so far are lost. - pub fn readUntilDelimiterBuffer(self: &InStream, buffer: &Buffer, delimiter: u8, max_size: usize) !void { - try buf.resize(0); + var actual_buf_len: usize = 0; + while (true) { + const dest_slice = buffer.toSlice()[actual_buf_len..]; + const bytes_read = try self.readFn(self, dest_slice); + actual_buf_len += bytes_read; - while (true) { - var byte: u8 = try self.readByte(); + if (bytes_read != dest_slice.len) { + buffer.shrink(actual_buf_len); + return; + } - if (byte == delimiter) { - return; + const new_buf_size = math.min(max_size, actual_buf_len + os.page_size); + if (new_buf_size == actual_buf_len) + return error.StreamTooLong; + try buffer.resize(new_buf_size); } + } - if (buf.len() == max_size) { - return error.StreamTooLong; - } + /// Allocates enough memory to hold all the contents of the stream. If the allocated + /// memory would be greater than `max_size`, returns `error.StreamTooLong`. + /// Caller owns returned memory. + /// If this function returns an error, the contents from the stream read so far are lost. + pub fn readAllAlloc(self: &Self, allocator: &mem.Allocator, max_size: usize) ![]u8 { + var buf = Buffer.initNull(allocator); + defer buf.deinit(); - try buf.appendByte(byte); + try self.readAllBuffer(&buf, max_size); + return buf.toOwnedSlice(); } - } - /// Allocates enough memory to read until `delimiter`. If the allocated - /// memory would be greater than `max_size`, returns `error.StreamTooLong`. - /// Caller owns returned memory. - /// If this function returns an error, the contents from the stream read so far are lost. - pub fn readUntilDelimiterAlloc(self: &InStream, allocator: &mem.Allocator, - delimiter: u8, max_size: usize) ![]u8 - { - var buf = Buffer.initNull(allocator); - defer buf.deinit(); - - try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size); - return buf.toOwnedSlice(); - } + /// Replaces `buffer` contents by reading from the stream until `delimiter` is found. + /// Does not include the delimiter in the result. + /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents + /// read from the stream so far are lost. + pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void { + try buf.resize(0); - /// Returns the number of bytes read. If the number read is smaller than buf.len, it - /// means the stream reached the end. Reaching the end of a stream is not an error - /// condition. - pub fn read(self: &InStream, buffer: []u8) !usize { - return self.readFn(self, buffer); - } + while (true) { + var byte: u8 = try self.readByte(); - /// Same as `read` but end of stream returns `error.EndOfStream`. - pub fn readNoEof(self: &InStream, buf: []u8) !void { - const amt_read = try self.read(buf); - if (amt_read < buf.len) return error.EndOfStream; - } + if (byte == delimiter) { + return; + } - /// Reads 1 byte from the stream or returns `error.EndOfStream`. - pub fn readByte(self: &InStream) !u8 { - var result: [1]u8 = undefined; - try self.readNoEof(result[0..]); - return result[0]; - } + if (buf.len() == max_size) { + return error.StreamTooLong; + } - /// Same as `readByte` except the returned byte is signed. - pub fn readByteSigned(self: &InStream) !i8 { - return @bitCast(i8, try self.readByte()); - } + try buf.appendByte(byte); + } + } - pub fn readIntLe(self: &InStream, comptime T: type) !T { - return self.readInt(builtin.Endian.Little, T); - } + /// Allocates enough memory to read until `delimiter`. If the allocated + /// memory would be greater than `max_size`, returns `error.StreamTooLong`. + /// Caller owns returned memory. + /// If this function returns an error, the contents from the stream read so far are lost. + pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator, + delimiter: u8, max_size: usize) ![]u8 + { + var buf = Buffer.initNull(allocator); + defer buf.deinit(); + + try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size); + return buf.toOwnedSlice(); + } - pub fn readIntBe(self: &InStream, comptime T: type) !T { - return self.readInt(builtin.Endian.Big, T); - } + /// Returns the number of bytes read. If the number read is smaller than buf.len, it + /// means the stream reached the end. Reaching the end of a stream is not an error + /// condition. + pub fn read(self: &Self, buffer: []u8) !usize { + return self.readFn(self, buffer); + } - pub fn readInt(self: &InStream, endian: builtin.Endian, comptime T: type) !T { - var bytes: [@sizeOf(T)]u8 = undefined; - try self.readNoEof(bytes[0..]); - return mem.readInt(bytes, T, endian); - } + /// Same as `read` but end of stream returns `error.EndOfStream`. + pub fn readNoEof(self: &Self, buf: []u8) !void { + const amt_read = try self.read(buf); + if (amt_read < buf.len) return error.EndOfStream; + } - pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) !T { - assert(size <= @sizeOf(T)); - assert(size <= 8); - var input_buf: [8]u8 = undefined; - const input_slice = input_buf[0..size]; - try self.readNoEof(input_slice); - return mem.readInt(input_slice, T, endian); - } + /// Reads 1 byte from the stream or returns `error.EndOfStream`. + pub fn readByte(self: &Self) !u8 { + var result: [1]u8 = undefined; + try self.readNoEof(result[0..]); + return result[0]; + } + /// Same as `readByte` except the returned byte is signed. + pub fn readByteSigned(self: &Self) !i8 { + return @bitCast(i8, try self.readByte()); + } -}; + pub fn readIntLe(self: &Self, comptime T: type) !T { + return self.readInt(builtin.Endian.Little, T); + } -pub const OutStream = struct { - // TODO allow specifying the error set - writeFn: fn(self: &OutStream, bytes: []const u8) error!void, + pub fn readIntBe(self: &Self, comptime T: type) !T { + return self.readInt(builtin.Endian.Big, T); + } - pub fn print(self: &OutStream, comptime format: []const u8, args: ...) !void { - return std.fmt.format(self, error, self.writeFn, format, args); - } + pub fn readInt(self: &Self, endian: builtin.Endian, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readInt(bytes, T, endian); + } - pub fn write(self: &OutStream, bytes: []const u8) !void { - return self.writeFn(self, bytes); - } + pub fn readVarInt(self: &Self, endian: builtin.Endian, comptime T: type, size: usize) !T { + assert(size <= @sizeOf(T)); + assert(size <= 8); + var input_buf: [8]u8 = undefined; + const input_slice = input_buf[0..size]; + try self.readNoEof(input_slice); + return mem.readInt(input_slice, T, endian); + } + }; +} - pub fn writeByte(self: &OutStream, byte: u8) !void { - const slice = (&byte)[0..1]; - return self.writeFn(self, slice); - } +pub fn OutStream(comptime Error: type) type { + return struct { + const Self = this; + + writeFn: fn(self: &Self, bytes: []const u8) Error!void, - pub fn writeByteNTimes(self: &OutStream, byte: u8, n: usize) !void { - const slice = (&byte)[0..1]; - var i: usize = 0; - while (i < n) : (i += 1) { - try self.writeFn(self, slice); + pub fn print(self: &Self, comptime format: []const u8, args: ...) !void { + return std.fmt.format(self, error, self.writeFn, format, args); } - } -}; + + pub fn write(self: &Self, bytes: []const u8) !void { + return self.writeFn(self, bytes); + } + + pub fn writeByte(self: &Self, byte: u8) !void { + const slice = (&byte)[0..1]; + return self.writeFn(self, slice); + } + + pub fn writeByteNTimes(self: &Self, byte: u8, n: usize) !void { + const slice = (&byte)[0..1]; + var i: usize = 0; + while (i < n) : (i += 1) { + try self.writeFn(self, slice); + } + } + }; +} /// `path` may need to be copied in memory to add a null terminating byte. In this case /// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed |
