1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
const Limited = @This();
const std = @import("../../std.zig");
const Reader = std.Io.Reader;
const Writer = std.Io.Writer;
const Limit = std.Io.Limit;
unlimited: *Reader,
remaining: Limit,
interface: Reader,
pub fn init(reader: *Reader, limit: Limit, buffer: []u8) Limited {
return .{
.unlimited = reader,
.remaining = limit,
.interface = .{
.vtable = &.{
.stream = stream,
.discard = discard,
},
.buffer = buffer,
.seek = 0,
.end = 0,
},
};
}
fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
const l: *Limited = @fieldParentPtr("interface", r);
if (l.remaining == .nothing) return error.EndOfStream;
const combined_limit = limit.min(l.remaining);
const n = try l.unlimited.stream(w, combined_limit);
l.remaining = l.remaining.subtract(n).?;
return n;
}
test stream {
var orig_buf: [10]u8 = undefined;
@memcpy(&orig_buf, "test bytes");
var fixed: std.Io.Reader = .fixed(&orig_buf);
var limit_buf: [1]u8 = undefined;
var limited: std.Io.Reader.Limited = .init(&fixed, @enumFromInt(4), &limit_buf);
var result_buf: [10]u8 = undefined;
var fixed_writer: std.Io.Writer = .fixed(&result_buf);
const streamed = try limited.interface.stream(&fixed_writer, @enumFromInt(7));
try std.testing.expect(streamed == 4);
try std.testing.expectEqualStrings("test", result_buf[0..streamed]);
}
fn discard(r: *Reader, limit: Limit) Reader.Error!usize {
const l: *Limited = @fieldParentPtr("interface", r);
if (l.remaining == .nothing) return error.EndOfStream;
const combined_limit = limit.min(l.remaining);
const n = try l.unlimited.discard(combined_limit);
l.remaining = l.remaining.subtract(n).?;
return n;
}
test "end of stream, read, hit limit exactly" {
var f: Reader = .fixed("i'm dying");
var l = f.limited(.limited(4), &.{});
const r = &l.interface;
var buf: [2]u8 = undefined;
try r.readSliceAll(&buf);
try r.readSliceAll(&buf);
try std.testing.expectError(error.EndOfStream, l.interface.readSliceAll(&buf));
}
test "end of stream, read, hit limit after partial read" {
var f: Reader = .fixed("i'm dying");
var l = f.limited(.limited(5), &.{});
const r = &l.interface;
var buf: [2]u8 = undefined;
try r.readSliceAll(&buf);
try r.readSliceAll(&buf);
try std.testing.expectError(error.EndOfStream, l.interface.readSliceAll(&buf));
}
test "end of stream, discard, hit limit exactly" {
var f: Reader = .fixed("i'm dying");
var l = f.limited(.limited(4), &.{});
const r = &l.interface;
try r.discardAll(2);
try r.discardAll(2);
try std.testing.expectError(error.EndOfStream, l.interface.discardAll(2));
}
test "end of stream, discard, hit limit after partial read" {
var f: Reader = .fixed("i'm dying");
var l = f.limited(.limited(5), &.{});
const r = &l.interface;
try r.discardAll(2);
try r.discardAll(2);
try std.testing.expectError(error.EndOfStream, l.interface.discardAll(2));
}
|