From b990d5f0acf423869f89f70899cf4db788a2a8df Mon Sep 17 00:00:00 2001 From: Caolan McMahon Date: Mon, 6 Dec 2021 10:29:39 +0000 Subject: [PATCH] have .next() return a reader for the next netstring instead of bool --- README.md | 3 +-- src/netstring.zig | 41 ++++++++++++++++++----------------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index be867ad..e4a8c84 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,8 @@ pub fn main() !void { var parser = netstring.netStringParser(input.reader()); // Repeat while the parser can find another netstring - while (try parser.next()) { + while (try parser.next()) |reader| { // Read the current netstring and print it - const reader = parser.reader(); const msg = try reader.readAllAlloc(std.heap.page_allocator, 4096); std.debug.print("{s}\n", .{msg}); } diff --git a/src/netstring.zig b/src/netstring.zig index 03f78d9..007c857 100644 --- a/src/netstring.zig +++ b/src/netstring.zig @@ -14,9 +14,8 @@ pub fn NetStringParser(comptime ReaderType: type) type { const Error = ReaderType.Error; const Reader = std.io.Reader(*@This(), Error, read); - /// Aligns reader at beginning of next netstring. Returns true if - /// another netstring was found, false if not. - pub fn next(self: *@This()) !bool { + /// Moves input to beginning of next netstring and returns a Reader for it. + pub fn next(self: *@This()) !?Reader { var r = self.child_reader.reader(); // move stream to end of current netstring if (self.child_reader.bytes_read < self.end) { @@ -27,16 +26,16 @@ pub fn NetStringParser(comptime ReaderType: type) type { if (size_str) |s| { const size = try std.fmt.parseUnsigned(usize, s, 10); self.end = self.child_reader.bytes_read + size + 1; - return true; + return self.reader(); } else { - return false; + return null; } } /// Reads bytes from the current netstring returning number of bytes read. /// If the number of bytes read is 0 it means the stream reached the end /// of the current netstring. - pub fn read(self: *@This(), buf: []u8) Error!usize { + fn read(self: *@This(), buf: []u8) Error!usize { // read until one byte before end because of tailing comma if (self.child_reader.bytes_read + 1 >= self.end) { return 0; @@ -51,7 +50,7 @@ pub fn NetStringParser(comptime ReaderType: type) type { /// Returns a std.io.Reader for the current netstring. Calling `next()` /// on this parser will move the reader onto the next netstring. This /// must be done before the first netstring can be read. - pub fn reader(self: *@This()) Reader { + fn reader(self: *@This()) Reader { return .{ .context = self }; } }; @@ -66,77 +65,73 @@ test "parse empty input stream" { var p = netStringParser(input.reader()); var msg: [1024]u8 = undefined; try testing.expectEqual(@intCast(usize, 0), try p.reader().read(&msg)); - try testing.expectEqual(false, try p.next()); + try testing.expectEqual(try p.next(), null); } test "parse single netstring" { var input = std.io.fixedBufferStream("5:hello,"); var p = netStringParser(input.reader()); var msg: [1024]u8 = undefined; - const r = p.reader(); - try testing.expectEqual(true, try p.next()); + const r = (try p.next()).?; const bytes = try r.read(&msg); try testing.expectEqual(@intCast(usize, 5), bytes); try testing.expectEqualSlices(u8, "hello", msg[0..bytes]); try testing.expectEqual(@intCast(usize, 0), try r.read(&msg)); - try testing.expectEqual(false, try p.next()); + try testing.expectEqual(try p.next(), null); } test "parse multiple netstrings" { var input = std.io.fixedBufferStream("5:hello,1:,,7: world!,"); var p = netStringParser(input.reader()); var msg: [1024]u8 = undefined; - const r = p.reader(); - try testing.expectEqual(true, try p.next()); { + const r = (try p.next()).?; const bytes = try r.read(&msg); try testing.expectEqual(@intCast(usize, 5), bytes); try testing.expectEqualSlices(u8, "hello", msg[0..bytes]); try testing.expectEqual(@intCast(usize, 0), try r.read(&msg)); } - try testing.expectEqual(true, try p.next()); { + const r = (try p.next()).?; const bytes = try r.read(&msg); try testing.expectEqual(@intCast(usize, 1), bytes); try testing.expectEqualSlices(u8, ",", msg[0..bytes]); try testing.expectEqual(@intCast(usize, 0), try r.read(&msg)); } - try testing.expectEqual(true, try p.next()); { + const r = (try p.next()).?; const bytes = try r.read(&msg); try testing.expectEqual(@intCast(usize, 7), bytes); try testing.expectEqualSlices(u8, " world!", msg[0..bytes]); try testing.expectEqual(@intCast(usize, 0), try r.read(&msg)); } - try testing.expectEqual(false, try p.next()); + try testing.expectEqual(try p.next(), null); } test "calling next before completely reading current netstring" { var input = std.io.fixedBufferStream("3:foo,3:bar,"); var p = netStringParser(input.reader()); var msg: [1]u8 = undefined; - const r = p.reader(); - try testing.expectEqual(true, try p.next()); { + const r = (try p.next()).?; const bytes = try r.read(&msg); try testing.expectEqual(@intCast(usize, 1), bytes); try testing.expectEqualSlices(u8, "f", msg[0..bytes]); } - try testing.expectEqual(true, try p.next()); { + const r = (try p.next()).?; const bytes = try r.read(&msg); try testing.expectEqual(@intCast(usize, 1), bytes); try testing.expectEqualSlices(u8, "b", msg[0..bytes]); + // attempt to keep reading past current netstring + try testing.expectEqual(try p.next(), null); + try testing.expectEqual(@intCast(usize, 0), try r.read(&msg)); } - try testing.expectEqual(false, try p.next()); - try testing.expectEqual(@intCast(usize, 0), try r.read(&msg)); } test "invalid input" { var input = std.io.fixedBufferStream("hello"); var p = netStringParser(input.reader()); var msg: [1024]u8 = undefined; - const r = p.reader(); try testing.expectError(error.InvalidCharacter, p.next()); - try testing.expectEqual(@intCast(usize, 0), try r.read(&msg)); } -- 2.45.2