diff --git a/std/io.zig b/std/io.zig index 5d73b4e7d..ff73c04f7 100644 --- a/std/io.zig +++ b/std/io.zig @@ -419,7 +419,7 @@ pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) typ }; } -pub const SliceStream = struct { +pub const SliceInStream = struct { const Self = this; pub const Error = error { }; pub const Stream = InStream(Error); @@ -447,7 +447,53 @@ pub const SliceStream = struct { return size; } +}; +/// This is a simple OutStream that writes to a slice, and returns an error +/// when it runs out of space. +pub const SliceOutStream = struct { + pub const Error = error{OutOfSpace}; + pub const Stream = OutStream(Error); + + pub stream: Stream, + + pos: usize, + slice: []u8, + + pub fn init(slice: []u8) SliceOutStream { + return SliceOutStream{ + .slice = slice, + .pos = 0, + .stream = Stream{ .writeFn = writeFn }, + }; + } + + pub fn getWritten(self: *const SliceOutStream) []const u8 { + return self.slice[0..self.pos]; + } + + pub fn reset(self: *SliceOutStream) void { + self.pos = 0; + } + + fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void { + const self = @fieldParentPtr(SliceOutStream, "stream", out_stream); + + assert(self.pos <= self.slice.len); + + const n = + if (self.pos + bytes.len <= self.slice.len) + bytes.len + else + self.slice.len - self.pos; + + std.mem.copy(u8, self.slice[self.pos..self.pos + n], bytes[0..n]); + self.pos += n; + + if (n < bytes.len) { + return Error.OutOfSpace; + } + } }; pub fn BufferedOutStream(comptime Error: type) type { diff --git a/std/io_test.zig b/std/io_test.zig index 8d5c35c5f..56f8a9a6a 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -2,6 +2,7 @@ const std = @import("index.zig"); const io = std.io; const DefaultPrng = std.rand.DefaultPrng; const assert = std.debug.assert; +const assertError = std.debug.assertError; const mem = std.mem; const os = std.os; const builtin = @import("builtin"); @@ -61,9 +62,9 @@ test "BufferOutStream" { assert(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n")); } -test "SliceStream" { +test "SliceInStream" { const bytes = []const u8 { 1, 2, 3, 4, 5, 6, 7 }; - var ss = io.SliceStream.init(bytes); + var ss = io.SliceInStream.init(bytes); var dest: [4]u8 = undefined; @@ -81,8 +82,8 @@ test "SliceStream" { test "PeekStream" { const bytes = []const u8 { 1, 2, 3, 4, 5, 6, 7, 8 }; - var ss = io.SliceStream.init(bytes); - var ps = io.PeekStream(2, io.SliceStream.Error).init(&ss.stream); + var ss = io.SliceInStream.init(bytes); + var ps = io.PeekStream(2, io.SliceInStream.Error).init(&ss.stream); var dest: [4]u8 = undefined; @@ -111,3 +112,23 @@ test "PeekStream" { assert(dest[0] == 12); assert(dest[1] == 11); } + +test "SliceOutStream" { + var buffer: [10]u8 = undefined; + var ss = io.SliceOutStream.init(buffer[0..]); + + try ss.stream.write("Hello"); + assert(mem.eql(u8, ss.getWritten(), "Hello")); + + try ss.stream.write("world"); + assert(mem.eql(u8, ss.getWritten(), "Helloworld")); + + assertError(ss.stream.write("!"), error.OutOfSpace); + assert(mem.eql(u8, ss.getWritten(), "Helloworld")); + + ss.reset(); + assert(ss.getWritten().len == 0); + + assertError(ss.stream.write("Hello world!"), error.OutOfSpace); + assert(mem.eql(u8, ss.getWritten(), "Hello worl")); +}