| ... | ... | @@ -846,37 +846,44 @@ pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 846 | 846 | /// Appends to `w` contents by reading from the stream until `delimiter` is |
| 847 | 847 | /// found. Does not write the delimiter itself. |
| 848 | 848 | /// |
| 849 | | /// Returns number of bytes streamed. |
| 850 | | pub fn readDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize { |
| 851 | | const amount, const to = try r.readAny(w, delimiter, .unlimited); |
| 852 | | return switch (to) { |
| 853 | | .delimiter => amount, |
| 854 | | .limit => unreachable, |
| 855 | | .end => error.EndOfStream, |
| 849 | /// Returns number of bytes streamed, which may be zero, or error.EndOfStream |
| 850 | /// if the delimiter was not found. |
| 851 | /// |
| 852 | /// See also: |
| 853 | /// * `streamDelimiterEnding` |
| 854 | /// * `streamDelimiterLimit` |
| 855 | pub fn streamDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize { |
| 856 | const n = streamDelimiterLimit(r, w, delimiter, .unlimited) catch |err| switch (err) { |
| 857 | error.StreamTooLong => unreachable, // unlimited is passed |
| 858 | else => |e| return e, |
| 856 | 859 | }; |
| 860 | if (r.seek == r.end) return error.EndOfStream; |
| 861 | return n; |
| 857 | 862 | } |
| 858 | 863 | |
| 859 | 864 | /// Appends to `w` contents by reading from the stream until `delimiter` is found. |
| 860 | 865 | /// Does not write the delimiter itself. |
| 861 | 866 | /// |
| 862 | | /// Succeeds if stream ends before delimiter found. |
| 867 | /// Returns number of bytes streamed, which may be zero. End of stream can be |
| 868 | /// detected by checking if the next byte in the stream is the delimiter. |
| 863 | 869 | /// |
| 864 | | /// Returns number of bytes streamed. The end is not signaled to the writer. |
| 865 | | pub fn readDelimiterEnding( |
| 870 | /// See also: |
| 871 | /// * `streamDelimiter` |
| 872 | /// * `streamDelimiterLimit` |
| 873 | pub fn streamDelimiterEnding( |
| 866 | 874 | r: *Reader, |
| 867 | 875 | w: *Writer, |
| 868 | 876 | delimiter: u8, |
| 869 | 877 | ) StreamRemainingError!usize { |
| 870 | | const amount, const to = try r.readAny(w, delimiter, .unlimited); |
| 871 | | return switch (to) { |
| 872 | | .delimiter, .end => amount, |
| 873 | | .limit => unreachable, |
| 878 | return streamDelimiterLimit(r, w, delimiter, .unlimited) catch |err| switch (err) { |
| 879 | error.StreamTooLong => unreachable, // unlimited is passed |
| 880 | else => |e| return e, |
| 874 | 881 | }; |
| 875 | 882 | } |
| 876 | 883 | |
| 877 | | pub const StreamDelimiterLimitedError = StreamRemainingError || error{ |
| 878 | | /// Stream ended before the delimiter was found. |
| 879 | | EndOfStream, |
| 884 | pub const StreamDelimiterLimitError = error{ |
| 885 | ReadFailed, |
| 886 | WriteFailed, |
| 880 | 887 | /// The delimiter was not found within the limit. |
| 881 | 888 | StreamTooLong, |
| 882 | 889 | }; |
| ... | ... | @@ -884,45 +891,31 @@ pub const StreamDelimiterLimitedError = StreamRemainingError || error{ |
| 884 | 891 | /// Appends to `w` contents by reading from the stream until `delimiter` is found. |
| 885 | 892 | /// Does not write the delimiter itself. |
| 886 | 893 | /// |
| 887 | | /// Returns number of bytes streamed. |
| 888 | | pub fn readDelimiterLimit( |
| 894 | /// Returns number of bytes streamed, which may be zero. End of stream can be |
| 895 | /// detected by checking if the next byte in the stream is the delimiter. |
| 896 | pub fn streamDelimiterLimit( |
| 889 | 897 | r: *Reader, |
| 890 | 898 | w: *Writer, |
| 891 | 899 | delimiter: u8, |
| 892 | 900 | limit: Limit, |
| 893 | | ) StreamDelimiterLimitedError!usize { |
| 894 | | const amount, const to = try r.readAny(w, delimiter, limit); |
| 895 | | return switch (to) { |
| 896 | | .delimiter => amount, |
| 897 | | .limit => error.StreamTooLong, |
| 898 | | .end => error.EndOfStream, |
| 899 | | }; |
| 900 | | } |
| 901 | | |
| 902 | | fn readAny( |
| 903 | | r: *Reader, |
| 904 | | w: *Writer, |
| 905 | | delimiter: ?u8, |
| 906 | | limit: Limit, |
| 907 | | ) StreamRemainingError!struct { usize, enum { delimiter, limit, end } } { |
| 908 | | var amount: usize = 0; |
| 909 | | var remaining = limit; |
| 910 | | while (remaining.nonzero()) { |
| 911 | | const available = remaining.slice(r.peekGreedy(1) catch |err| switch (err) { |
| 912 | | error.ReadFailed => |e| return e, |
| 913 | | error.EndOfStream => return .{ amount, .end }, |
| 901 | ) StreamDelimiterLimitError!usize { |
| 902 | var remaining = @intFromEnum(limit); |
| 903 | while (remaining != 0) { |
| 904 | const available = Limit.limited(remaining).slice(r.peekGreedy(1) catch |err| switch (err) { |
| 905 | error.ReadFailed => return error.ReadFailed, |
| 906 | error.EndOfStream => return @intFromEnum(limit) - remaining, |
| 914 | 907 | }); |
| 915 | | if (delimiter) |d| if (std.mem.indexOfScalar(u8, available, d)) |delimiter_index| { |
| 908 | if (std.mem.indexOfScalar(u8, available, delimiter)) |delimiter_index| { |
| 916 | 909 | try w.writeAll(available[0..delimiter_index]); |
| 917 | | r.toss(delimiter_index + 1); |
| 918 | | return .{ amount + delimiter_index, .delimiter }; |
| 919 | | }; |
| 910 | r.toss(delimiter_index); |
| 911 | remaining -= delimiter_index; |
| 912 | return @intFromEnum(limit) - remaining; |
| 913 | } |
| 920 | 914 | try w.writeAll(available); |
| 921 | 915 | r.toss(available.len); |
| 922 | | amount += available.len; |
| 923 | | remaining = remaining.subtract(available.len).?; |
| 916 | remaining -= available.len; |
| 924 | 917 | } |
| 925 | | return .{ amount, .limit }; |
| 918 | return error.StreamTooLong; |
| 926 | 919 | } |
| 927 | 920 | |
| 928 | 921 | /// Reads from the stream until specified byte is found, discarding all data, |
| ... | ... | @@ -1348,15 +1341,33 @@ test peekDelimiterExclusive { |
| 1348 | 1341 | try testing.expectEqualStrings("c", try r.peekDelimiterExclusive('\n')); |
| 1349 | 1342 | } |
| 1350 | 1343 | |
| 1351 | | test readDelimiter { |
| 1352 | | return error.Unimplemented; |
| 1344 | test streamDelimiter { |
| 1345 | var out_buffer: [10]u8 = undefined; |
| 1346 | var r: Reader = .fixed("foo\nbars"); |
| 1347 | var w: Writer = .fixed(&out_buffer); |
| 1348 | // Short streams are possible with this function but not with fixed. |
| 1349 | try testing.expectEqual(3, try r.streamDelimiter(&w, '\n')); |
| 1350 | try testing.expectEqualStrings("foo", w.buffered()); |
| 1351 | try testing.expectEqual(0, try r.streamDelimiter(&w, '\n')); |
| 1352 | r.toss(1); |
| 1353 | try testing.expectError(error.EndOfStream, r.streamDelimiter(&w, '\n')); |
| 1353 | 1354 | } |
| 1354 | 1355 | |
| 1355 | | test readDelimiterEnding { |
| 1356 | | return error.Unimplemented; |
| 1356 | test streamDelimiterEnding { |
| 1357 | var out_buffer: [10]u8 = undefined; |
| 1358 | var r: Reader = .fixed("foo\nbars"); |
| 1359 | var w: Writer = .fixed(&out_buffer); |
| 1360 | // Short streams are possible with this function but not with fixed. |
| 1361 | try testing.expectEqual(3, try r.streamDelimiterEnding(&w, '\n')); |
| 1362 | try testing.expectEqualStrings("foo", w.buffered()); |
| 1363 | r.toss(1); |
| 1364 | try testing.expectEqual(4, try r.streamDelimiterEnding(&w, '\n')); |
| 1365 | try testing.expectEqualStrings("foobars", w.buffered()); |
| 1366 | try testing.expectEqual(0, try r.streamDelimiterEnding(&w, '\n')); |
| 1367 | try testing.expectEqual(0, try r.streamDelimiterEnding(&w, '\n')); |
| 1357 | 1368 | } |
| 1358 | 1369 | |
| 1359 | | test readDelimiterLimit { |
| 1370 | test streamDelimiterLimit { |
| 1360 | 1371 | return error.Unimplemented; |
| 1361 | 1372 | } |
| 1362 | 1373 | |