authorgravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2020-06-08 22:34:50-06:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-09 13:36:17-04:00
loga282ac7a9119cd0961ea17e29c4a0e9b0baf60d0
treea5e8b62dafcdc4fa17ad0dc6ccedf3865a2dd4bc
parent4302f276ed3083b4f261f9e50a9546c9877d2785

Support Reader for InStream


18 files changed, 757 insertions(+), 681 deletions(-)

lib/std/elf.zig-1
...@@ -5,7 +5,6 @@ const os = std.os;...@@ -5,7 +5,6 @@ const os = std.os;
5const math = std.math;5const math = std.math;
6const mem = std.mem;6const mem = std.mem;
7const debug = std.debug;7const debug = std.debug;
8const InStream = std.stream.InStream;
9const File = std.fs.File;8const File = std.fs.File;
109
11pub const AT_NULL = 0;10pub const AT_NULL = 0;
lib/std/fifo.zig+9-5
...@@ -216,11 +216,15 @@ pub fn LinearFifo(...@@ -216,11 +216,15 @@ pub fn LinearFifo(
216 }216 }
217217
218 /// Same as `read` except it returns an error union218 /// Same as `read` except it returns an error union
219 /// The purpose of this function existing is to match `std.io.InStream` API.219 /// The purpose of this function existing is to match `std.io.Reader` API.
220 fn readFn(self: *Self, dest: []u8) error{}!usize {220 fn readFn(self: *Self, dest: []u8) error{}!usize {
221 return self.read(dest);221 return self.read(dest);
222 }222 }
223223
224 pub fn reader(self: *Self) std.io.Reader(*Self, error{}, readFn) {
225 return .{ .context = self };
226 }
227 /// Deprecated: `use reader`
224 pub fn inStream(self: *Self) std.io.InStream(*Self, error{}, readFn) {228 pub fn inStream(self: *Self) std.io.InStream(*Self, error{}, readFn) {
225 return .{ .context = self };229 return .{ .context = self };
226 }230 }
...@@ -431,10 +435,10 @@ test "LinearFifo(u8, .Dynamic)" {...@@ -431,10 +435,10 @@ test "LinearFifo(u8, .Dynamic)" {
431 {435 {
432 try fifo.outStream().writeAll("This is a test");436 try fifo.outStream().writeAll("This is a test");
433 var result: [30]u8 = undefined;437 var result: [30]u8 = undefined;
434 testing.expectEqualSlices(u8, "This", (try fifo.inStream().readUntilDelimiterOrEof(&result, ' ')).?);438 testing.expectEqualSlices(u8, "This", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
435 testing.expectEqualSlices(u8, "is", (try fifo.inStream().readUntilDelimiterOrEof(&result, ' ')).?);439 testing.expectEqualSlices(u8, "is", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
436 testing.expectEqualSlices(u8, "a", (try fifo.inStream().readUntilDelimiterOrEof(&result, ' ')).?);440 testing.expectEqualSlices(u8, "a", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
437 testing.expectEqualSlices(u8, "test", (try fifo.inStream().readUntilDelimiterOrEof(&result, ' ')).?);441 testing.expectEqualSlices(u8, "test", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
438 }442 }
439}443}
440444
lib/std/fs/file.zig+7-1
...@@ -642,8 +642,14 @@ pub const File = struct {...@@ -642,8 +642,14 @@ pub const File = struct {
642 }642 }
643 }643 }
644644
645 pub const InStream = io.InStream(File, ReadError, read);645 pub const Reader = io.Reader(File, ReadError, read);
646 /// Deprecated: use `Reader`
647 pub const InStream = Reader;
646648
649 pub fn reader(file: File) io.Reader(File, ReadError, read) {
650 return .{ .context = file };
651 }
652 /// Deprecated: use `reader`
647 pub fn inStream(file: File) io.InStream(File, ReadError, read) {653 pub fn inStream(file: File) io.InStream(File, ReadError, read) {
648 return .{ .context = file };654 return .{ .context = file };
649 }655 }
lib/std/io.zig+18-8
...@@ -101,7 +101,9 @@ pub fn getStdIn() File {...@@ -101,7 +101,9 @@ pub fn getStdIn() File {
101 };101 };
102}102}
103103
104pub const InStream = @import("io/in_stream.zig").InStream;104pub const Reader = @import("io/reader.zig").Reader;
105/// Deprecated: use `Reader`
106pub const InStream = Reader;
105pub const Writer = @import("io/writer.zig").Writer;107pub const Writer = @import("io/writer.zig").Writer;
106/// Deprecated: use `Writer`108/// Deprecated: use `Writer`
107pub const OutStream = Writer;109pub const OutStream = Writer;
...@@ -114,8 +116,12 @@ pub const BufferedOutStream = BufferedWriter;...@@ -114,8 +116,12 @@ pub const BufferedOutStream = BufferedWriter;
114/// Deprecated: use `bufferedWriter`116/// Deprecated: use `bufferedWriter`
115pub const bufferedOutStream = bufferedWriter;117pub const bufferedOutStream = bufferedWriter;
116118
117pub const BufferedInStream = @import("io/buffered_in_stream.zig").BufferedInStream;119pub const BufferedReader = @import("io/buffered_reader.zig").BufferedReader;
118pub const bufferedInStream = @import("io/buffered_in_stream.zig").bufferedInStream;120pub const bufferedReader = @import("io/buffered_reader.zig").bufferedReader;
121/// Deprecated: use `BufferedReader`
122pub const BufferedInStream = BufferedReader;
123/// Deprecated: use `bufferedReader`
124pub const bufferedInStream = bufferedReader;
119125
120pub const PeekStream = @import("io/peek_stream.zig").PeekStream;126pub const PeekStream = @import("io/peek_stream.zig").PeekStream;
121pub const peekStream = @import("io/peek_stream.zig").peekStream;127pub const peekStream = @import("io/peek_stream.zig").peekStream;
...@@ -144,8 +150,12 @@ pub const MultiOutStream = MultiWriter;...@@ -144,8 +150,12 @@ pub const MultiOutStream = MultiWriter;
144/// Deprecated: use `multiWriter`150/// Deprecated: use `multiWriter`
145pub const multiOutStream = multiWriter;151pub const multiOutStream = multiWriter;
146152
147pub const BitInStream = @import("io/bit_in_stream.zig").BitInStream;153pub const BitReader = @import("io/bit_reader.zig").BitReader;
148pub const bitInStream = @import("io/bit_in_stream.zig").bitInStream;154pub const bitReader = @import("io/bit_reader.zig").bitReader;
155/// Deprecated: use `BitReader`
156pub const BitInStream = BitReader;
157/// Deprecated: use `bitReader`
158pub const bitInStream = bitReader;
149159
150pub const BitWriter = @import("io/bit_writer.zig").BitWriter;160pub const BitWriter = @import("io/bit_writer.zig").BitWriter;
151pub const bitWriter = @import("io/bit_writer.zig").bitWriter;161pub const bitWriter = @import("io/bit_writer.zig").bitWriter;
...@@ -184,15 +194,15 @@ test "null_writer" {...@@ -184,15 +194,15 @@ test "null_writer" {
184}194}
185195
186test "" {196test "" {
187 _ = @import("io/bit_in_stream.zig");197 _ = @import("io/bit_reader.zig");
188 _ = @import("io/bit_writer.zig");198 _ = @import("io/bit_writer.zig");
189 _ = @import("io/buffered_atomic_file.zig");199 _ = @import("io/buffered_atomic_file.zig");
190 _ = @import("io/buffered_in_stream.zig");200 _ = @import("io/buffered_reader.zig");
191 _ = @import("io/buffered_writer.zig");201 _ = @import("io/buffered_writer.zig");
192 _ = @import("io/c_writer.zig");202 _ = @import("io/c_writer.zig");
193 _ = @import("io/counting_writer.zig");203 _ = @import("io/counting_writer.zig");
194 _ = @import("io/fixed_buffer_stream.zig");204 _ = @import("io/fixed_buffer_stream.zig");
195 _ = @import("io/in_stream.zig");205 _ = @import("io/reader.zig");
196 _ = @import("io/writer.zig");206 _ = @import("io/writer.zig");
197 _ = @import("io/peek_stream.zig");207 _ = @import("io/peek_stream.zig");
198 _ = @import("io/seekable_stream.zig");208 _ = @import("io/seekable_stream.zig");
lib/std/io/bit_in_stream.zig+4-242
...@@ -1,243 +1,5 @@...@@ -1,243 +1,5 @@
1const std = @import("../std.zig");1/// Deprecated: use `std.io.bit_reader.BitReader`
2const builtin = std.builtin;2pub const BitInStream = @import("./bit_reader.zig").BitReader;
3const io = std.io;
4const assert = std.debug.assert;
5const testing = std.testing;
6const trait = std.meta.trait;
7const meta = std.meta;
8const math = std.math;
93
10/// Creates a stream which allows for reading bit fields from another stream4/// Deprecated: use `std.io.bit_reader.bitReader`
11pub fn BitInStream(endian: builtin.Endian, comptime InStreamType: type) type {5pub const bitInStream = @import("./bit_reader.zig").bitReader;
12 return struct {
13 in_stream: InStreamType,
14 bit_buffer: u7,
15 bit_count: u3,
16
17 pub const Error = InStreamType.Error;
18 pub const InStream = io.InStream(*Self, Error, read);
19
20 const Self = @This();
21 const u8_bit_count = comptime meta.bitCount(u8);
22 const u7_bit_count = comptime meta.bitCount(u7);
23 const u4_bit_count = comptime meta.bitCount(u4);
24
25 pub fn init(in_stream: InStreamType) Self {
26 return Self{
27 .in_stream = in_stream,
28 .bit_buffer = 0,
29 .bit_count = 0,
30 };
31 }
32
33 /// Reads `bits` bits from the stream and returns a specified unsigned int type
34 /// containing them in the least significant end, returning an error if the
35 /// specified number of bits could not be read.
36 pub fn readBitsNoEof(self: *Self, comptime U: type, bits: usize) !U {
37 var n: usize = undefined;
38 const result = try self.readBits(U, bits, &n);
39 if (n < bits) return error.EndOfStream;
40 return result;
41 }
42
43 /// Reads `bits` bits from the stream and returns a specified unsigned int type
44 /// containing them in the least significant end. The number of bits successfully
45 /// read is placed in `out_bits`, as reaching the end of the stream is not an error.
46 pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
47 comptime assert(trait.isUnsignedInt(U));
48
49 //by extending the buffer to a minimum of u8 we can cover a number of edge cases
50 // related to shifting and casting.
51 const u_bit_count = comptime meta.bitCount(U);
52 const buf_bit_count = bc: {
53 assert(u_bit_count >= bits);
54 break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
55 };
56 const Buf = std.meta.Int(false, buf_bit_count);
57 const BufShift = math.Log2Int(Buf);
58
59 out_bits.* = @as(usize, 0);
60 if (U == u0 or bits == 0) return 0;
61 var out_buffer = @as(Buf, 0);
62
63 if (self.bit_count > 0) {
64 const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;
65 const shift = u7_bit_count - n;
66 switch (endian) {
67 .Big => {
68 out_buffer = @as(Buf, self.bit_buffer >> shift);
69 if (n >= u7_bit_count)
70 self.bit_buffer = 0
71 else
72 self.bit_buffer <<= n;
73 },
74 .Little => {
75 const value = (self.bit_buffer << shift) >> shift;
76 out_buffer = @as(Buf, value);
77 if (n >= u7_bit_count)
78 self.bit_buffer = 0
79 else
80 self.bit_buffer >>= n;
81 },
82 }
83 self.bit_count -= n;
84 out_bits.* = n;
85 }
86 //at this point we know bit_buffer is empty
87
88 //copy bytes until we have enough bits, then leave the rest in bit_buffer
89 while (out_bits.* < bits) {
90 const n = bits - out_bits.*;
91 const next_byte = self.in_stream.readByte() catch |err| {
92 if (err == error.EndOfStream) {
93 return @intCast(U, out_buffer);
94 }
95 //@BUG: See #1810. Not sure if the bug is that I have to do this for some
96 // streams, or that I don't for streams with emtpy errorsets.
97 return @errSetCast(Error, err);
98 };
99
100 switch (endian) {
101 .Big => {
102 if (n >= u8_bit_count) {
103 out_buffer <<= @intCast(u3, u8_bit_count - 1);
104 out_buffer <<= 1;
105 out_buffer |= @as(Buf, next_byte);
106 out_bits.* += u8_bit_count;
107 continue;
108 }
109
110 const shift = @intCast(u3, u8_bit_count - n);
111 out_buffer <<= @intCast(BufShift, n);
112 out_buffer |= @as(Buf, next_byte >> shift);
113 out_bits.* += n;
114 self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));
115 self.bit_count = shift;
116 },
117 .Little => {
118 if (n >= u8_bit_count) {
119 out_buffer |= @as(Buf, next_byte) << @intCast(BufShift, out_bits.*);
120 out_bits.* += u8_bit_count;
121 continue;
122 }
123
124 const shift = @intCast(u3, u8_bit_count - n);
125 const value = (next_byte << shift) >> shift;
126 out_buffer |= @as(Buf, value) << @intCast(BufShift, out_bits.*);
127 out_bits.* += n;
128 self.bit_buffer = @truncate(u7, next_byte >> @intCast(u3, n));
129 self.bit_count = shift;
130 },
131 }
132 }
133
134 return @intCast(U, out_buffer);
135 }
136
137 pub fn alignToByte(self: *Self) void {
138 self.bit_buffer = 0;
139 self.bit_count = 0;
140 }
141
142 pub fn read(self: *Self, buffer: []u8) Error!usize {
143 var out_bits: usize = undefined;
144 var out_bits_total = @as(usize, 0);
145 //@NOTE: I'm not sure this is a good idea, maybe alignToByte should be forced
146 if (self.bit_count > 0) {
147 for (buffer) |*b, i| {
148 b.* = try self.readBits(u8, u8_bit_count, &out_bits);
149 out_bits_total += out_bits;
150 }
151 const incomplete_byte = @boolToInt(out_bits_total % u8_bit_count > 0);
152 return (out_bits_total / u8_bit_count) + incomplete_byte;
153 }
154
155 return self.in_stream.read(buffer);
156 }
157
158 pub fn inStream(self: *Self) InStream {
159 return .{ .context = self };
160 }
161 };
162}
163
164pub fn bitInStream(
165 comptime endian: builtin.Endian,
166 underlying_stream: var,
167) BitInStream(endian, @TypeOf(underlying_stream)) {
168 return BitInStream(endian, @TypeOf(underlying_stream)).init(underlying_stream);
169}
170
171test "api coverage" {
172 const mem_be = [_]u8{ 0b11001101, 0b00001011 };
173 const mem_le = [_]u8{ 0b00011101, 0b10010101 };
174
175 var mem_in_be = io.fixedBufferStream(&mem_be);
176 var bit_stream_be = bitInStream(.Big, mem_in_be.inStream());
177
178 var out_bits: usize = undefined;
179
180 const expect = testing.expect;
181 const expectError = testing.expectError;
182
183 expect(1 == try bit_stream_be.readBits(u2, 1, &out_bits));
184 expect(out_bits == 1);
185 expect(2 == try bit_stream_be.readBits(u5, 2, &out_bits));
186 expect(out_bits == 2);
187 expect(3 == try bit_stream_be.readBits(u128, 3, &out_bits));
188 expect(out_bits == 3);
189 expect(4 == try bit_stream_be.readBits(u8, 4, &out_bits));
190 expect(out_bits == 4);
191 expect(5 == try bit_stream_be.readBits(u9, 5, &out_bits));
192 expect(out_bits == 5);
193 expect(1 == try bit_stream_be.readBits(u1, 1, &out_bits));
194 expect(out_bits == 1);
195
196 mem_in_be.pos = 0;
197 bit_stream_be.bit_count = 0;
198 expect(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits));
199 expect(out_bits == 15);
200
201 mem_in_be.pos = 0;
202 bit_stream_be.bit_count = 0;
203 expect(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits));
204 expect(out_bits == 16);
205
206 _ = try bit_stream_be.readBits(u0, 0, &out_bits);
207
208 expect(0 == try bit_stream_be.readBits(u1, 1, &out_bits));
209 expect(out_bits == 0);
210 expectError(error.EndOfStream, bit_stream_be.readBitsNoEof(u1, 1));
211
212 var mem_in_le = io.fixedBufferStream(&mem_le);
213 var bit_stream_le = bitInStream(.Little, mem_in_le.inStream());
214
215 expect(1 == try bit_stream_le.readBits(u2, 1, &out_bits));
216 expect(out_bits == 1);
217 expect(2 == try bit_stream_le.readBits(u5, 2, &out_bits));
218 expect(out_bits == 2);
219 expect(3 == try bit_stream_le.readBits(u128, 3, &out_bits));
220 expect(out_bits == 3);
221 expect(4 == try bit_stream_le.readBits(u8, 4, &out_bits));
222 expect(out_bits == 4);
223 expect(5 == try bit_stream_le.readBits(u9, 5, &out_bits));
224 expect(out_bits == 5);
225 expect(1 == try bit_stream_le.readBits(u1, 1, &out_bits));
226 expect(out_bits == 1);
227
228 mem_in_le.pos = 0;
229 bit_stream_le.bit_count = 0;
230 expect(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits));
231 expect(out_bits == 15);
232
233 mem_in_le.pos = 0;
234 bit_stream_le.bit_count = 0;
235 expect(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits));
236 expect(out_bits == 16);
237
238 _ = try bit_stream_le.readBits(u0, 0, &out_bits);
239
240 expect(0 == try bit_stream_le.readBits(u1, 1, &out_bits));
241 expect(out_bits == 0);
242 expectError(error.EndOfStream, bit_stream_le.readBitsNoEof(u1, 1));
243}
lib/std/io/bit_reader.zig created+250
...@@ -0,0 +1,250 @@
1const std = @import("../std.zig");
2const builtin = std.builtin;
3const io = std.io;
4const assert = std.debug.assert;
5const testing = std.testing;
6const trait = std.meta.trait;
7const meta = std.meta;
8const math = std.math;
9
10/// Creates a stream which allows for reading bit fields from another stream
11pub fn BitReader(endian: builtin.Endian, comptime ReaderType: type) type {
12 return struct {
13 forward_reader: ReaderType,
14 bit_buffer: u7,
15 bit_count: u3,
16
17 pub const Error = ReaderType.Error;
18 pub const Reader = io.Reader(*Self, Error, read);
19 /// Deprecated: use `Reader`
20 pub const InStream = io.InStream(*Self, Error, read);
21
22 const Self = @This();
23 const u8_bit_count = comptime meta.bitCount(u8);
24 const u7_bit_count = comptime meta.bitCount(u7);
25 const u4_bit_count = comptime meta.bitCount(u4);
26
27 pub fn init(forward_reader: ReaderType) Self {
28 return Self{
29 .forward_reader = forward_reader,
30 .bit_buffer = 0,
31 .bit_count = 0,
32 };
33 }
34
35 /// Reads `bits` bits from the stream and returns a specified unsigned int type
36 /// containing them in the least significant end, returning an error if the
37 /// specified number of bits could not be read.
38 pub fn readBitsNoEof(self: *Self, comptime U: type, bits: usize) !U {
39 var n: usize = undefined;
40 const result = try self.readBits(U, bits, &n);
41 if (n < bits) return error.EndOfStream;
42 return result;
43 }
44
45 /// Reads `bits` bits from the stream and returns a specified unsigned int type
46 /// containing them in the least significant end. The number of bits successfully
47 /// read is placed in `out_bits`, as reaching the end of the stream is not an error.
48 pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
49 comptime assert(trait.isUnsignedInt(U));
50
51 //by extending the buffer to a minimum of u8 we can cover a number of edge cases
52 // related to shifting and casting.
53 const u_bit_count = comptime meta.bitCount(U);
54 const buf_bit_count = bc: {
55 assert(u_bit_count >= bits);
56 break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
57 };
58 const Buf = std.meta.Int(false, buf_bit_count);
59 const BufShift = math.Log2Int(Buf);
60
61 out_bits.* = @as(usize, 0);
62 if (U == u0 or bits == 0) return 0;
63 var out_buffer = @as(Buf, 0);
64
65 if (self.bit_count > 0) {
66 const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;
67 const shift = u7_bit_count - n;
68 switch (endian) {
69 .Big => {
70 out_buffer = @as(Buf, self.bit_buffer >> shift);
71 if (n >= u7_bit_count)
72 self.bit_buffer = 0
73 else
74 self.bit_buffer <<= n;
75 },
76 .Little => {
77 const value = (self.bit_buffer << shift) >> shift;
78 out_buffer = @as(Buf, value);
79 if (n >= u7_bit_count)
80 self.bit_buffer = 0
81 else
82 self.bit_buffer >>= n;
83 },
84 }
85 self.bit_count -= n;
86 out_bits.* = n;
87 }
88 //at this point we know bit_buffer is empty
89
90 //copy bytes until we have enough bits, then leave the rest in bit_buffer
91 while (out_bits.* < bits) {
92 const n = bits - out_bits.*;
93 const next_byte = self.forward_reader.readByte() catch |err| {
94 if (err == error.EndOfStream) {
95 return @intCast(U, out_buffer);
96 }
97 //@BUG: See #1810. Not sure if the bug is that I have to do this for some
98 // streams, or that I don't for streams with emtpy errorsets.
99 return @errSetCast(Error, err);
100 };
101
102 switch (endian) {
103 .Big => {
104 if (n >= u8_bit_count) {
105 out_buffer <<= @intCast(u3, u8_bit_count - 1);
106 out_buffer <<= 1;
107 out_buffer |= @as(Buf, next_byte);
108 out_bits.* += u8_bit_count;
109 continue;
110 }
111
112 const shift = @intCast(u3, u8_bit_count - n);
113 out_buffer <<= @intCast(BufShift, n);
114 out_buffer |= @as(Buf, next_byte >> shift);
115 out_bits.* += n;
116 self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));
117 self.bit_count = shift;
118 },
119 .Little => {
120 if (n >= u8_bit_count) {
121 out_buffer |= @as(Buf, next_byte) << @intCast(BufShift, out_bits.*);
122 out_bits.* += u8_bit_count;
123 continue;
124 }
125
126 const shift = @intCast(u3, u8_bit_count - n);
127 const value = (next_byte << shift) >> shift;
128 out_buffer |= @as(Buf, value) << @intCast(BufShift, out_bits.*);
129 out_bits.* += n;
130 self.bit_buffer = @truncate(u7, next_byte >> @intCast(u3, n));
131 self.bit_count = shift;
132 },
133 }
134 }
135
136 return @intCast(U, out_buffer);
137 }
138
139 pub fn alignToByte(self: *Self) void {
140 self.bit_buffer = 0;
141 self.bit_count = 0;
142 }
143
144 pub fn read(self: *Self, buffer: []u8) Error!usize {
145 var out_bits: usize = undefined;
146 var out_bits_total = @as(usize, 0);
147 //@NOTE: I'm not sure this is a good idea, maybe alignToByte should be forced
148 if (self.bit_count > 0) {
149 for (buffer) |*b, i| {
150 b.* = try self.readBits(u8, u8_bit_count, &out_bits);
151 out_bits_total += out_bits;
152 }
153 const incomplete_byte = @boolToInt(out_bits_total % u8_bit_count > 0);
154 return (out_bits_total / u8_bit_count) + incomplete_byte;
155 }
156
157 return self.forward_reader.read(buffer);
158 }
159
160 pub fn reader(self: *Self) Reader {
161 return .{ .context = self };
162 }
163
164 /// Deprecated: use `reader`
165 pub fn inStream(self: *Self) InStream {
166 return .{ .context = self };
167 }
168 };
169}
170
171pub fn bitReader(
172 comptime endian: builtin.Endian,
173 underlying_stream: var,
174) BitReader(endian, @TypeOf(underlying_stream)) {
175 return BitReader(endian, @TypeOf(underlying_stream)).init(underlying_stream);
176}
177
178test "api coverage" {
179 const mem_be = [_]u8{ 0b11001101, 0b00001011 };
180 const mem_le = [_]u8{ 0b00011101, 0b10010101 };
181
182 var mem_in_be = io.fixedBufferStream(&mem_be);
183 var bit_stream_be = bitReader(.Big, mem_in_be.reader());
184
185 var out_bits: usize = undefined;
186
187 const expect = testing.expect;
188 const expectError = testing.expectError;
189
190 expect(1 == try bit_stream_be.readBits(u2, 1, &out_bits));
191 expect(out_bits == 1);
192 expect(2 == try bit_stream_be.readBits(u5, 2, &out_bits));
193 expect(out_bits == 2);
194 expect(3 == try bit_stream_be.readBits(u128, 3, &out_bits));
195 expect(out_bits == 3);
196 expect(4 == try bit_stream_be.readBits(u8, 4, &out_bits));
197 expect(out_bits == 4);
198 expect(5 == try bit_stream_be.readBits(u9, 5, &out_bits));
199 expect(out_bits == 5);
200 expect(1 == try bit_stream_be.readBits(u1, 1, &out_bits));
201 expect(out_bits == 1);
202
203 mem_in_be.pos = 0;
204 bit_stream_be.bit_count = 0;
205 expect(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits));
206 expect(out_bits == 15);
207
208 mem_in_be.pos = 0;
209 bit_stream_be.bit_count = 0;
210 expect(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits));
211 expect(out_bits == 16);
212
213 _ = try bit_stream_be.readBits(u0, 0, &out_bits);
214
215 expect(0 == try bit_stream_be.readBits(u1, 1, &out_bits));
216 expect(out_bits == 0);
217 expectError(error.EndOfStream, bit_stream_be.readBitsNoEof(u1, 1));
218
219 var mem_in_le = io.fixedBufferStream(&mem_le);
220 var bit_stream_le = bitReader(.Little, mem_in_le.reader());
221
222 expect(1 == try bit_stream_le.readBits(u2, 1, &out_bits));
223 expect(out_bits == 1);
224 expect(2 == try bit_stream_le.readBits(u5, 2, &out_bits));
225 expect(out_bits == 2);
226 expect(3 == try bit_stream_le.readBits(u128, 3, &out_bits));
227 expect(out_bits == 3);
228 expect(4 == try bit_stream_le.readBits(u8, 4, &out_bits));
229 expect(out_bits == 4);
230 expect(5 == try bit_stream_le.readBits(u9, 5, &out_bits));
231 expect(out_bits == 5);
232 expect(1 == try bit_stream_le.readBits(u1, 1, &out_bits));
233 expect(out_bits == 1);
234
235 mem_in_le.pos = 0;
236 bit_stream_le.bit_count = 0;
237 expect(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits));
238 expect(out_bits == 15);
239
240 mem_in_le.pos = 0;
241 bit_stream_le.bit_count = 0;
242 expect(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits));
243 expect(out_bits == 16);
244
245 _ = try bit_stream_le.readBits(u0, 0, &out_bits);
246
247 expect(0 == try bit_stream_le.readBits(u1, 1, &out_bits));
248 expect(out_bits == 0);
249 expectError(error.EndOfStream, bit_stream_le.readBitsNoEof(u1, 1));
250}
lib/std/io/buffered_in_stream.zig+4-85
...@@ -1,86 +1,5 @@...@@ -1,86 +1,5 @@
1const std = @import("../std.zig");1/// Deprecated: use `std.io.buffered_reader.BufferedReader`
2const io = std.io;2pub const BufferedInStream = @import("./buffered_reader.zig").BufferedReader;
3const assert = std.debug.assert;
4const testing = std.testing;
53
6pub fn BufferedInStream(comptime buffer_size: usize, comptime InStreamType: type) type {4/// Deprecated: use `std.io.buffered_reader.bufferedReader`
7 return struct {5pub const bufferedInStream = @import("./buffered_reader.zig").bufferedReader;
8 unbuffered_in_stream: InStreamType,
9 fifo: FifoType = FifoType.init(),
10
11 pub const Error = InStreamType.Error;
12 pub const InStream = io.InStream(*Self, Error, read);
13
14 const Self = @This();
15 const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
16
17 pub fn read(self: *Self, dest: []u8) Error!usize {
18 var dest_index: usize = 0;
19 while (dest_index < dest.len) {
20 const written = self.fifo.read(dest[dest_index..]);
21 if (written == 0) {
22 // fifo empty, fill it
23 const writable = self.fifo.writableSlice(0);
24 assert(writable.len > 0);
25 const n = try self.unbuffered_in_stream.read(writable);
26 if (n == 0) {
27 // reading from the unbuffered stream returned nothing
28 // so we have nothing left to read.
29 return dest_index;
30 }
31 self.fifo.update(n);
32 }
33 dest_index += written;
34 }
35 return dest.len;
36 }
37
38 pub fn inStream(self: *Self) InStream {
39 return .{ .context = self };
40 }
41 };
42}
43
44pub fn bufferedInStream(underlying_stream: var) BufferedInStream(4096, @TypeOf(underlying_stream)) {
45 return .{ .unbuffered_in_stream = underlying_stream };
46}
47
48test "io.BufferedInStream" {
49 const OneByteReadInStream = struct {
50 str: []const u8,
51 curr: usize,
52
53 const Error = error{NoError};
54 const Self = @This();
55 const InStream = io.InStream(*Self, Error, read);
56
57 fn init(str: []const u8) Self {
58 return Self{
59 .str = str,
60 .curr = 0,
61 };
62 }
63
64 fn read(self: *Self, dest: []u8) Error!usize {
65 if (self.str.len <= self.curr or dest.len == 0)
66 return 0;
67
68 dest[0] = self.str[self.curr];
69 self.curr += 1;
70 return 1;
71 }
72
73 fn inStream(self: *Self) InStream {
74 return .{ .context = self };
75 }
76 };
77
78 const str = "This is a test";
79 var one_byte_stream = OneByteReadInStream.init(str);
80 var buf_in_stream = bufferedInStream(one_byte_stream.inStream());
81 const stream = buf_in_stream.inStream();
82
83 const res = try stream.readAllAlloc(testing.allocator, str.len + 1);
84 defer testing.allocator.free(res);
85 testing.expectEqualSlices(u8, str, res);
86}
lib/std/io/buffered_reader.zig created+93
...@@ -0,0 +1,93 @@
1const std = @import("../std.zig");
2const io = std.io;
3const assert = std.debug.assert;
4const testing = std.testing;
5
6pub fn BufferedReader(comptime buffer_size: usize, comptime ReaderType: type) type {
7 return struct {
8 unbuffered_reader: ReaderType,
9 fifo: FifoType = FifoType.init(),
10
11 pub const Error = ReaderType.Error;
12 pub const Reader = io.Reader(*Self, Error, read);
13 /// Deprecated: use `Reader`
14 pub const InStream = Reader;
15
16 const Self = @This();
17 const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
18
19 pub fn read(self: *Self, dest: []u8) Error!usize {
20 var dest_index: usize = 0;
21 while (dest_index < dest.len) {
22 const written = self.fifo.read(dest[dest_index..]);
23 if (written == 0) {
24 // fifo empty, fill it
25 const writable = self.fifo.writableSlice(0);
26 assert(writable.len > 0);
27 const n = try self.unbuffered_reader.read(writable);
28 if (n == 0) {
29 // reading from the unbuffered stream returned nothing
30 // so we have nothing left to read.
31 return dest_index;
32 }
33 self.fifo.update(n);
34 }
35 dest_index += written;
36 }
37 return dest.len;
38 }
39
40 pub fn reader(self: *Self) Reader {
41 return .{ .context = self };
42 }
43
44 /// Deprecated: use `reader`
45 pub fn inStream(self: *Self) InStream {
46 return .{ .context = self };
47 }
48 };
49}
50
51pub fn bufferedReader(underlying_stream: var) BufferedReader(4096, @TypeOf(underlying_stream)) {
52 return .{ .unbuffered_reader = underlying_stream };
53}
54
55test "io.BufferedReader" {
56 const OneByteReadReader = struct {
57 str: []const u8,
58 curr: usize,
59
60 const Error = error{NoError};
61 const Self = @This();
62 const Reader = io.Reader(*Self, Error, read);
63
64 fn init(str: []const u8) Self {
65 return Self{
66 .str = str,
67 .curr = 0,
68 };
69 }
70
71 fn read(self: *Self, dest: []u8) Error!usize {
72 if (self.str.len <= self.curr or dest.len == 0)
73 return 0;
74
75 dest[0] = self.str[self.curr];
76 self.curr += 1;
77 return 1;
78 }
79
80 fn reader(self: *Self) Reader {
81 return .{ .context = self };
82 }
83 };
84
85 const str = "This is a test";
86 var one_byte_stream = OneByteReadReader.init(str);
87 var buf_reader = bufferedReader(one_byte_stream.reader());
88 const stream = buf_reader.reader();
89
90 const res = try stream.readAllAlloc(testing.allocator, str.len + 1);
91 defer testing.allocator.free(res);
92 testing.expectEqualSlices(u8, str, res);
93}
lib/std/io/fixed_buffer_stream.zig+12-5
...@@ -4,8 +4,8 @@ const testing = std.testing;...@@ -4,8 +4,8 @@ const testing = std.testing;
4const mem = std.mem;4const mem = std.mem;
5const assert = std.debug.assert;5const assert = std.debug.assert;
66
7/// This turns a byte buffer into an `io.OutStream`, `io.InStream`, or `io.SeekableStream`.7/// This turns a byte buffer into an `io.Writer`, `io.Reader`, or `io.SeekableStream`.
8/// If the supplied byte buffer is const, then `io.OutStream` is not available.8/// If the supplied byte buffer is const, then `io.Writer` is not available.
9pub fn FixedBufferStream(comptime Buffer: type) type {9pub fn FixedBufferStream(comptime Buffer: type) type {
10 return struct {10 return struct {
11 /// `Buffer` is either a `[]u8` or `[]const u8`.11 /// `Buffer` is either a `[]u8` or `[]const u8`.
...@@ -17,6 +17,8 @@ pub fn FixedBufferStream(comptime Buffer: type) type {...@@ -17,6 +17,8 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
17 pub const SeekError = error{};17 pub const SeekError = error{};
18 pub const GetSeekPosError = error{};18 pub const GetSeekPosError = error{};
1919
20 pub const Reader = io.Reader(*Self, ReadError, read);
21 /// Deprecated: use `Reader`
20 pub const InStream = io.InStream(*Self, ReadError, read);22 pub const InStream = io.InStream(*Self, ReadError, read);
21 pub const Writer = io.Writer(*Self, WriteError, write);23 pub const Writer = io.Writer(*Self, WriteError, write);
22 /// Deprecated: use `Writer`24 /// Deprecated: use `Writer`
...@@ -34,6 +36,11 @@ pub fn FixedBufferStream(comptime Buffer: type) type {...@@ -34,6 +36,11 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
3436
35 const Self = @This();37 const Self = @This();
3638
39 pub fn reader(self: *Self) Reader {
40 return .{ .context = self };
41 }
42
43 /// Deprecated: use `inStream`
37 pub fn inStream(self: *Self) InStream {44 pub fn inStream(self: *Self) InStream {
38 return .{ .context = self };45 return .{ .context = self };
39 }46 }
...@@ -165,14 +172,14 @@ test "FixedBufferStream input" {...@@ -165,14 +172,14 @@ test "FixedBufferStream input" {
165172
166 var dest: [4]u8 = undefined;173 var dest: [4]u8 = undefined;
167174
168 var read = try fbs.inStream().read(dest[0..4]);175 var read = try fbs.reader().read(dest[0..4]);
169 testing.expect(read == 4);176 testing.expect(read == 4);
170 testing.expect(mem.eql(u8, dest[0..4], bytes[0..4]));177 testing.expect(mem.eql(u8, dest[0..4], bytes[0..4]));
171178
172 read = try fbs.inStream().read(dest[0..4]);179 read = try fbs.reader().read(dest[0..4]);
173 testing.expect(read == 3);180 testing.expect(read == 3);
174 testing.expect(mem.eql(u8, dest[0..3], bytes[4..7]));181 testing.expect(mem.eql(u8, dest[0..3], bytes[4..7]));
175182
176 read = try fbs.inStream().read(dest[0..4]);183 read = try fbs.reader().read(dest[0..4]);
177 testing.expect(read == 0);184 testing.expect(read == 0);
178}185}
lib/std/io/in_stream.zig+2-296
...@@ -1,296 +1,2 @@...@@ -1,296 +1,2 @@
1const std = @import("../std.zig");1/// Deprecated: use `std.io.reader.Reader`
2const builtin = std.builtin;2pub const InStream = @import("./reader.zig").Reader;
3const math = std.math;
4const assert = std.debug.assert;
5const mem = std.mem;
6const testing = std.testing;
7
8pub fn InStream(
9 comptime Context: type,
10 comptime ReadError: type,
11 /// Returns the number of bytes read. It may be less than buffer.len.
12 /// If the number of bytes read is 0, it means end of stream.
13 /// End of stream is not an error condition.
14 comptime readFn: fn (context: Context, buffer: []u8) ReadError!usize,
15) type {
16 return struct {
17 pub const Error = ReadError;
18
19 context: Context,
20
21 const Self = @This();
22
23 /// Returns the number of bytes read. It may be less than buffer.len.
24 /// If the number of bytes read is 0, it means end of stream.
25 /// End of stream is not an error condition.
26 pub fn read(self: Self, buffer: []u8) Error!usize {
27 return readFn(self.context, buffer);
28 }
29
30 /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
31 /// means the stream reached the end. Reaching the end of a stream is not an error
32 /// condition.
33 pub fn readAll(self: Self, buffer: []u8) Error!usize {
34 var index: usize = 0;
35 while (index != buffer.len) {
36 const amt = try self.read(buffer[index..]);
37 if (amt == 0) return index;
38 index += amt;
39 }
40 return index;
41 }
42
43 /// Returns the number of bytes read. If the number read would be smaller than buf.len,
44 /// error.EndOfStream is returned instead.
45 pub fn readNoEof(self: Self, buf: []u8) !void {
46 const amt_read = try self.readAll(buf);
47 if (amt_read < buf.len) return error.EndOfStream;
48 }
49
50 pub const readAllBuffer = @compileError("deprecated; use readAllArrayList()");
51
52 /// Appends to the `std.ArrayList` contents by reading from the stream until end of stream is found.
53 /// If the number of bytes appended would exceed `max_append_size`, `error.StreamTooLong` is returned
54 /// and the `std.ArrayList` has exactly `max_append_size` bytes appended.
55 pub fn readAllArrayList(self: Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void {
56 try array_list.ensureCapacity(math.min(max_append_size, 4096));
57 const original_len = array_list.items.len;
58 var start_index: usize = original_len;
59 while (true) {
60 array_list.expandToCapacity();
61 const dest_slice = array_list.span()[start_index..];
62 const bytes_read = try self.readAll(dest_slice);
63 start_index += bytes_read;
64
65 if (start_index - original_len > max_append_size) {
66 array_list.shrink(original_len + max_append_size);
67 return error.StreamTooLong;
68 }
69
70 if (bytes_read != dest_slice.len) {
71 array_list.shrink(start_index);
72 return;
73 }
74
75 // This will trigger ArrayList to expand superlinearly at whatever its growth rate is.
76 try array_list.ensureCapacity(start_index + 1);
77 }
78 }
79
80 /// Allocates enough memory to hold all the contents of the stream. If the allocated
81 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
82 /// Caller owns returned memory.
83 /// If this function returns an error, the contents from the stream read so far are lost.
84 pub fn readAllAlloc(self: Self, allocator: *mem.Allocator, max_size: usize) ![]u8 {
85 var array_list = std.ArrayList(u8).init(allocator);
86 defer array_list.deinit();
87 try self.readAllArrayList(&array_list, max_size);
88 return array_list.toOwnedSlice();
89 }
90
91 /// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found.
92 /// Does not include the delimiter in the result.
93 /// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the
94 /// `std.ArrayList` is populated with `max_size` bytes from the stream.
95 pub fn readUntilDelimiterArrayList(
96 self: Self,
97 array_list: *std.ArrayList(u8),
98 delimiter: u8,
99 max_size: usize,
100 ) !void {
101 array_list.shrink(0);
102 while (true) {
103 var byte: u8 = try self.readByte();
104
105 if (byte == delimiter) {
106 return;
107 }
108
109 if (array_list.items.len == max_size) {
110 return error.StreamTooLong;
111 }
112
113 try array_list.append(byte);
114 }
115 }
116
117 /// Allocates enough memory to read until `delimiter`. If the allocated
118 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
119 /// Caller owns returned memory.
120 /// If this function returns an error, the contents from the stream read so far are lost.
121 pub fn readUntilDelimiterAlloc(
122 self: Self,
123 allocator: *mem.Allocator,
124 delimiter: u8,
125 max_size: usize,
126 ) ![]u8 {
127 var array_list = std.ArrayList(u8).init(allocator);
128 defer array_list.deinit();
129 try self.readUntilDelimiterArrayList(&array_list, delimiter, max_size);
130 return array_list.toOwnedSlice();
131 }
132
133 /// Reads from the stream until specified byte is found. If the buffer is not
134 /// large enough to hold the entire contents, `error.StreamTooLong` is returned.
135 /// If end-of-stream is found, returns the rest of the stream. If this
136 /// function is called again after that, returns null.
137 /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
138 /// delimiter byte is not included in the returned slice.
139 pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) !?[]u8 {
140 var index: usize = 0;
141 while (true) {
142 const byte = self.readByte() catch |err| switch (err) {
143 error.EndOfStream => {
144 if (index == 0) {
145 return null;
146 } else {
147 return buf[0..index];
148 }
149 },
150 else => |e| return e,
151 };
152
153 if (byte == delimiter) return buf[0..index];
154 if (index >= buf.len) return error.StreamTooLong;
155
156 buf[index] = byte;
157 index += 1;
158 }
159 }
160
161 /// Reads from the stream until specified byte is found, discarding all data,
162 /// including the delimiter.
163 /// If end-of-stream is found, this function succeeds.
164 pub fn skipUntilDelimiterOrEof(self: Self, delimiter: u8) !void {
165 while (true) {
166 const byte = self.readByte() catch |err| switch (err) {
167 error.EndOfStream => return,
168 else => |e| return e,
169 };
170 if (byte == delimiter) return;
171 }
172 }
173
174 /// Reads 1 byte from the stream or returns `error.EndOfStream`.
175 pub fn readByte(self: Self) !u8 {
176 var result: [1]u8 = undefined;
177 const amt_read = try self.read(result[0..]);
178 if (amt_read < 1) return error.EndOfStream;
179 return result[0];
180 }
181
182 /// Same as `readByte` except the returned byte is signed.
183 pub fn readByteSigned(self: Self) !i8 {
184 return @bitCast(i8, try self.readByte());
185 }
186
187 /// Reads exactly `num_bytes` bytes and returns as an array.
188 /// `num_bytes` must be comptime-known
189 pub fn readBytesNoEof(self: Self, comptime num_bytes: usize) ![num_bytes]u8 {
190 var bytes: [num_bytes]u8 = undefined;
191 try self.readNoEof(&bytes);
192 return bytes;
193 }
194
195 /// Reads a native-endian integer
196 pub fn readIntNative(self: Self, comptime T: type) !T {
197 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
198 return mem.readIntNative(T, &bytes);
199 }
200
201 /// Reads a foreign-endian integer
202 pub fn readIntForeign(self: Self, comptime T: type) !T {
203 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
204 return mem.readIntForeign(T, &bytes);
205 }
206
207 pub fn readIntLittle(self: Self, comptime T: type) !T {
208 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
209 return mem.readIntLittle(T, &bytes);
210 }
211
212 pub fn readIntBig(self: Self, comptime T: type) !T {
213 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
214 return mem.readIntBig(T, &bytes);
215 }
216
217 pub fn readInt(self: Self, comptime T: type, endian: builtin.Endian) !T {
218 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
219 return mem.readInt(T, &bytes, endian);
220 }
221
222 pub fn readVarInt(self: Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
223 assert(size <= @sizeOf(ReturnType));
224 var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
225 const bytes = bytes_buf[0..size];
226 try self.readNoEof(bytes);
227 return mem.readVarInt(ReturnType, bytes, endian);
228 }
229
230 pub fn skipBytes(self: Self, num_bytes: u64) !void {
231 var i: u64 = 0;
232 while (i < num_bytes) : (i += 1) {
233 _ = try self.readByte();
234 }
235 }
236
237 /// Reads `slice.len` bytes from the stream and returns if they are the same as the passed slice
238 pub fn isBytes(self: Self, slice: []const u8) !bool {
239 var i: usize = 0;
240 var matches = true;
241 while (i < slice.len) : (i += 1) {
242 if (slice[i] != try self.readByte()) {
243 matches = false;
244 }
245 }
246 return matches;
247 }
248
249 pub fn readStruct(self: Self, comptime T: type) !T {
250 // Only extern and packed structs have defined in-memory layout.
251 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
252 var res: [1]T = undefined;
253 try self.readNoEof(mem.sliceAsBytes(res[0..]));
254 return res[0];
255 }
256
257 /// Reads an integer with the same size as the given enum's tag type. If the integer matches
258 /// an enum tag, casts the integer to the enum tag and returns it. Otherwise, returns an error.
259 /// TODO optimization taking advantage of most fields being in order
260 pub fn readEnum(self: Self, comptime Enum: type, endian: builtin.Endian) !Enum {
261 const E = error{
262 /// An integer was read, but it did not match any of the tags in the supplied enum.
263 InvalidValue,
264 };
265 const type_info = @typeInfo(Enum).Enum;
266 const tag = try self.readInt(type_info.tag_type, endian);
267
268 inline for (std.meta.fields(Enum)) |field| {
269 if (tag == field.value) {
270 return @field(Enum, field.name);
271 }
272 }
273
274 return E.InvalidValue;
275 }
276 };
277}
278
279test "InStream" {
280 var buf = "a\x02".*;
281 const in_stream = std.io.fixedBufferStream(&buf).inStream();
282 testing.expect((try in_stream.readByte()) == 'a');
283 testing.expect((try in_stream.readEnum(enum(u8) {
284 a = 0,
285 b = 99,
286 c = 2,
287 d = 3,
288 }, undefined)) == .c);
289 testing.expectError(error.EndOfStream, in_stream.readByte());
290}
291
292test "InStream.isBytes" {
293 const in_stream = std.io.fixedBufferStream("foobar").inStream();
294 testing.expectEqual(true, try in_stream.isBytes("foo"));
295 testing.expectEqual(false, try in_stream.isBytes("qux"));
296}
lib/std/io/peek_stream.zig+20-13
...@@ -5,24 +5,26 @@ const testing = std.testing;...@@ -5,24 +5,26 @@ const testing = std.testing;
55
6/// Creates a stream which supports 'un-reading' data, so that it can be read again.6/// Creates a stream which supports 'un-reading' data, so that it can be read again.
7/// This makes look-ahead style parsing much easier.7/// This makes look-ahead style parsing much easier.
8/// TODO merge this with `std.io.BufferedInStream`: https://github.com/ziglang/zig/issues/45018/// TODO merge this with `std.io.BufferedReader`: https://github.com/ziglang/zig/issues/4501
9pub fn PeekStream(9pub fn PeekStream(
10 comptime buffer_type: std.fifo.LinearFifoBufferType,10 comptime buffer_type: std.fifo.LinearFifoBufferType,
11 comptime InStreamType: type,11 comptime ReaderType: type,
12) type {12) type {
13 return struct {13 return struct {
14 unbuffered_in_stream: InStreamType,14 unbuffered_in_stream: ReaderType,
15 fifo: FifoType,15 fifo: FifoType,
1616
17 pub const Error = InStreamType.Error;17 pub const Error = ReaderType.Error;
18 pub const InStream = io.InStream(*Self, Error, read);18 pub const Reader = io.Reader(*Self, Error, read);
19 /// Deprecated: use `Reader`
20 pub const InStream = Reader;
1921
20 const Self = @This();22 const Self = @This();
21 const FifoType = std.fifo.LinearFifo(u8, buffer_type);23 const FifoType = std.fifo.LinearFifo(u8, buffer_type);
2224
23 pub usingnamespace switch (buffer_type) {25 pub usingnamespace switch (buffer_type) {
24 .Static => struct {26 .Static => struct {
25 pub fn init(base: InStreamType) Self {27 pub fn init(base: ReaderType) Self {
26 return .{28 return .{
27 .unbuffered_in_stream = base,29 .unbuffered_in_stream = base,
28 .fifo = FifoType.init(),30 .fifo = FifoType.init(),
...@@ -30,7 +32,7 @@ pub fn PeekStream(...@@ -30,7 +32,7 @@ pub fn PeekStream(
30 }32 }
31 },33 },
32 .Slice => struct {34 .Slice => struct {
33 pub fn init(base: InStreamType, buf: []u8) Self {35 pub fn init(base: ReaderType, buf: []u8) Self {
34 return .{36 return .{
35 .unbuffered_in_stream = base,37 .unbuffered_in_stream = base,
36 .fifo = FifoType.init(buf),38 .fifo = FifoType.init(buf),
...@@ -38,7 +40,7 @@ pub fn PeekStream(...@@ -38,7 +40,7 @@ pub fn PeekStream(
38 }40 }
39 },41 },
40 .Dynamic => struct {42 .Dynamic => struct {
41 pub fn init(base: InStreamType, allocator: *mem.Allocator) Self {43 pub fn init(base: ReaderType, allocator: *mem.Allocator) Self {
42 return .{44 return .{
43 .unbuffered_in_stream = base,45 .unbuffered_in_stream = base,
44 .fifo = FifoType.init(allocator),46 .fifo = FifoType.init(allocator),
...@@ -65,6 +67,11 @@ pub fn PeekStream(...@@ -65,6 +67,11 @@ pub fn PeekStream(
65 return dest_index;67 return dest_index;
66 }68 }
6769
70 pub fn reader(self: *Self) Reader {
71 return .{ .context = self };
72 }
73
74 /// Deprecated: use `reader`
68 pub fn inStream(self: *Self) InStream {75 pub fn inStream(self: *Self) InStream {
69 return .{ .context = self };76 return .{ .context = self };
70 }77 }
...@@ -81,31 +88,31 @@ pub fn peekStream(...@@ -81,31 +88,31 @@ pub fn peekStream(
81test "PeekStream" {88test "PeekStream" {
82 const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };89 const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
83 var fbs = io.fixedBufferStream(&bytes);90 var fbs = io.fixedBufferStream(&bytes);
84 var ps = peekStream(2, fbs.inStream());91 var ps = peekStream(2, fbs.reader());
8592
86 var dest: [4]u8 = undefined;93 var dest: [4]u8 = undefined;
8794
88 try ps.putBackByte(9);95 try ps.putBackByte(9);
89 try ps.putBackByte(10);96 try ps.putBackByte(10);
9097
91 var read = try ps.inStream().read(dest[0..4]);98 var read = try ps.reader().read(dest[0..4]);
92 testing.expect(read == 4);99 testing.expect(read == 4);
93 testing.expect(dest[0] == 10);100 testing.expect(dest[0] == 10);
94 testing.expect(dest[1] == 9);101 testing.expect(dest[1] == 9);
95 testing.expect(mem.eql(u8, dest[2..4], bytes[0..2]));102 testing.expect(mem.eql(u8, dest[2..4], bytes[0..2]));
96103
97 read = try ps.inStream().read(dest[0..4]);104 read = try ps.reader().read(dest[0..4]);
98 testing.expect(read == 4);105 testing.expect(read == 4);
99 testing.expect(mem.eql(u8, dest[0..4], bytes[2..6]));106 testing.expect(mem.eql(u8, dest[0..4], bytes[2..6]));
100107
101 read = try ps.inStream().read(dest[0..4]);108 read = try ps.reader().read(dest[0..4]);
102 testing.expect(read == 2);109 testing.expect(read == 2);
103 testing.expect(mem.eql(u8, dest[0..2], bytes[6..8]));110 testing.expect(mem.eql(u8, dest[0..2], bytes[6..8]));
104111
105 try ps.putBackByte(11);112 try ps.putBackByte(11);
106 try ps.putBackByte(12);113 try ps.putBackByte(12);
107114
108 read = try ps.inStream().read(dest[0..4]);115 read = try ps.reader().read(dest[0..4]);
109 testing.expect(read == 2);116 testing.expect(read == 2);
110 testing.expect(dest[0] == 12);117 testing.expect(dest[0] == 12);
111 testing.expect(dest[1] == 11);118 testing.expect(dest[1] == 11);
lib/std/io/reader.zig created+296
...@@ -0,0 +1,296 @@
1const std = @import("../std.zig");
2const builtin = std.builtin;
3const math = std.math;
4const assert = std.debug.assert;
5const mem = std.mem;
6const testing = std.testing;
7
8pub fn Reader(
9 comptime Context: type,
10 comptime ReadError: type,
11 /// Returns the number of bytes read. It may be less than buffer.len.
12 /// If the number of bytes read is 0, it means end of stream.
13 /// End of stream is not an error condition.
14 comptime readFn: fn (context: Context, buffer: []u8) ReadError!usize,
15) type {
16 return struct {
17 pub const Error = ReadError;
18
19 context: Context,
20
21 const Self = @This();
22
23 /// Returns the number of bytes read. It may be less than buffer.len.
24 /// If the number of bytes read is 0, it means end of stream.
25 /// End of stream is not an error condition.
26 pub fn read(self: Self, buffer: []u8) Error!usize {
27 return readFn(self.context, buffer);
28 }
29
30 /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
31 /// means the stream reached the end. Reaching the end of a stream is not an error
32 /// condition.
33 pub fn readAll(self: Self, buffer: []u8) Error!usize {
34 var index: usize = 0;
35 while (index != buffer.len) {
36 const amt = try self.read(buffer[index..]);
37 if (amt == 0) return index;
38 index += amt;
39 }
40 return index;
41 }
42
43 /// Returns the number of bytes read. If the number read would be smaller than buf.len,
44 /// error.EndOfStream is returned instead.
45 pub fn readNoEof(self: Self, buf: []u8) !void {
46 const amt_read = try self.readAll(buf);
47 if (amt_read < buf.len) return error.EndOfStream;
48 }
49
50 pub const readAllBuffer = @compileError("deprecated; use readAllArrayList()");
51
52 /// Appends to the `std.ArrayList` contents by reading from the stream until end of stream is found.
53 /// If the number of bytes appended would exceed `max_append_size`, `error.StreamTooLong` is returned
54 /// and the `std.ArrayList` has exactly `max_append_size` bytes appended.
55 pub fn readAllArrayList(self: Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void {
56 try array_list.ensureCapacity(math.min(max_append_size, 4096));
57 const original_len = array_list.items.len;
58 var start_index: usize = original_len;
59 while (true) {
60 array_list.expandToCapacity();
61 const dest_slice = array_list.span()[start_index..];
62 const bytes_read = try self.readAll(dest_slice);
63 start_index += bytes_read;
64
65 if (start_index - original_len > max_append_size) {
66 array_list.shrink(original_len + max_append_size);
67 return error.StreamTooLong;
68 }
69
70 if (bytes_read != dest_slice.len) {
71 array_list.shrink(start_index);
72 return;
73 }
74
75 // This will trigger ArrayList to expand superlinearly at whatever its growth rate is.
76 try array_list.ensureCapacity(start_index + 1);
77 }
78 }
79
80 /// Allocates enough memory to hold all the contents of the stream. If the allocated
81 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
82 /// Caller owns returned memory.
83 /// If this function returns an error, the contents from the stream read so far are lost.
84 pub fn readAllAlloc(self: Self, allocator: *mem.Allocator, max_size: usize) ![]u8 {
85 var array_list = std.ArrayList(u8).init(allocator);
86 defer array_list.deinit();
87 try self.readAllArrayList(&array_list, max_size);
88 return array_list.toOwnedSlice();
89 }
90
91 /// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found.
92 /// Does not include the delimiter in the result.
93 /// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the
94 /// `std.ArrayList` is populated with `max_size` bytes from the stream.
95 pub fn readUntilDelimiterArrayList(
96 self: Self,
97 array_list: *std.ArrayList(u8),
98 delimiter: u8,
99 max_size: usize,
100 ) !void {
101 array_list.shrink(0);
102 while (true) {
103 var byte: u8 = try self.readByte();
104
105 if (byte == delimiter) {
106 return;
107 }
108
109 if (array_list.items.len == max_size) {
110 return error.StreamTooLong;
111 }
112
113 try array_list.append(byte);
114 }
115 }
116
117 /// Allocates enough memory to read until `delimiter`. If the allocated
118 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
119 /// Caller owns returned memory.
120 /// If this function returns an error, the contents from the stream read so far are lost.
121 pub fn readUntilDelimiterAlloc(
122 self: Self,
123 allocator: *mem.Allocator,
124 delimiter: u8,
125 max_size: usize,
126 ) ![]u8 {
127 var array_list = std.ArrayList(u8).init(allocator);
128 defer array_list.deinit();
129 try self.readUntilDelimiterArrayList(&array_list, delimiter, max_size);
130 return array_list.toOwnedSlice();
131 }
132
133 /// Reads from the stream until specified byte is found. If the buffer is not
134 /// large enough to hold the entire contents, `error.StreamTooLong` is returned.
135 /// If end-of-stream is found, returns the rest of the stream. If this
136 /// function is called again after that, returns null.
137 /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
138 /// delimiter byte is not included in the returned slice.
139 pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) !?[]u8 {
140 var index: usize = 0;
141 while (true) {
142 const byte = self.readByte() catch |err| switch (err) {
143 error.EndOfStream => {
144 if (index == 0) {
145 return null;
146 } else {
147 return buf[0..index];
148 }
149 },
150 else => |e| return e,
151 };
152
153 if (byte == delimiter) return buf[0..index];
154 if (index >= buf.len) return error.StreamTooLong;
155
156 buf[index] = byte;
157 index += 1;
158 }
159 }
160
161 /// Reads from the stream until specified byte is found, discarding all data,
162 /// including the delimiter.
163 /// If end-of-stream is found, this function succeeds.
164 pub fn skipUntilDelimiterOrEof(self: Self, delimiter: u8) !void {
165 while (true) {
166 const byte = self.readByte() catch |err| switch (err) {
167 error.EndOfStream => return,
168 else => |e| return e,
169 };
170 if (byte == delimiter) return;
171 }
172 }
173
174 /// Reads 1 byte from the stream or returns `error.EndOfStream`.
175 pub fn readByte(self: Self) !u8 {
176 var result: [1]u8 = undefined;
177 const amt_read = try self.read(result[0..]);
178 if (amt_read < 1) return error.EndOfStream;
179 return result[0];
180 }
181
182 /// Same as `readByte` except the returned byte is signed.
183 pub fn readByteSigned(self: Self) !i8 {
184 return @bitCast(i8, try self.readByte());
185 }
186
187 /// Reads exactly `num_bytes` bytes and returns as an array.
188 /// `num_bytes` must be comptime-known
189 pub fn readBytesNoEof(self: Self, comptime num_bytes: usize) ![num_bytes]u8 {
190 var bytes: [num_bytes]u8 = undefined;
191 try self.readNoEof(&bytes);
192 return bytes;
193 }
194
195 /// Reads a native-endian integer
196 pub fn readIntNative(self: Self, comptime T: type) !T {
197 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
198 return mem.readIntNative(T, &bytes);
199 }
200
201 /// Reads a foreign-endian integer
202 pub fn readIntForeign(self: Self, comptime T: type) !T {
203 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
204 return mem.readIntForeign(T, &bytes);
205 }
206
207 pub fn readIntLittle(self: Self, comptime T: type) !T {
208 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
209 return mem.readIntLittle(T, &bytes);
210 }
211
212 pub fn readIntBig(self: Self, comptime T: type) !T {
213 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
214 return mem.readIntBig(T, &bytes);
215 }
216
217 pub fn readInt(self: Self, comptime T: type, endian: builtin.Endian) !T {
218 const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8);
219 return mem.readInt(T, &bytes, endian);
220 }
221
222 pub fn readVarInt(self: Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
223 assert(size <= @sizeOf(ReturnType));
224 var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
225 const bytes = bytes_buf[0..size];
226 try self.readNoEof(bytes);
227 return mem.readVarInt(ReturnType, bytes, endian);
228 }
229
230 pub fn skipBytes(self: Self, num_bytes: u64) !void {
231 var i: u64 = 0;
232 while (i < num_bytes) : (i += 1) {
233 _ = try self.readByte();
234 }
235 }
236
237 /// Reads `slice.len` bytes from the stream and returns if they are the same as the passed slice
238 pub fn isBytes(self: Self, slice: []const u8) !bool {
239 var i: usize = 0;
240 var matches = true;
241 while (i < slice.len) : (i += 1) {
242 if (slice[i] != try self.readByte()) {
243 matches = false;
244 }
245 }
246 return matches;
247 }
248
249 pub fn readStruct(self: Self, comptime T: type) !T {
250 // Only extern and packed structs have defined in-memory layout.
251 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
252 var res: [1]T = undefined;
253 try self.readNoEof(mem.sliceAsBytes(res[0..]));
254 return res[0];
255 }
256
257 /// Reads an integer with the same size as the given enum's tag type. If the integer matches
258 /// an enum tag, casts the integer to the enum tag and returns it. Otherwise, returns an error.
259 /// TODO optimization taking advantage of most fields being in order
260 pub fn readEnum(self: Self, comptime Enum: type, endian: builtin.Endian) !Enum {
261 const E = error{
262 /// An integer was read, but it did not match any of the tags in the supplied enum.
263 InvalidValue,
264 };
265 const type_info = @typeInfo(Enum).Enum;
266 const tag = try self.readInt(type_info.tag_type, endian);
267
268 inline for (std.meta.fields(Enum)) |field| {
269 if (tag == field.value) {
270 return @field(Enum, field.name);
271 }
272 }
273
274 return E.InvalidValue;
275 }
276 };
277}
278
279test "Reader" {
280 var buf = "a\x02".*;
281 const reader = std.io.fixedBufferStream(&buf).reader();
282 testing.expect((try reader.readByte()) == 'a');
283 testing.expect((try reader.readEnum(enum(u8) {
284 a = 0,
285 b = 99,
286 c = 2,
287 d = 3,
288 }, undefined)) == .c);
289 testing.expectError(error.EndOfStream, reader.readByte());
290}
291
292test "Reader.isBytes" {
293 const reader = std.io.fixedBufferStream("foobar").reader();
294 testing.expectEqual(true, try reader.isBytes("foo"));
295 testing.expectEqual(false, try reader.isBytes("qux"));
296}
lib/std/io/seekable_stream.zig-1
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const InStream = std.io.InStream;
32
4pub fn SeekableStream(3pub fn SeekableStream(
5 comptime Context: type,4 comptime Context: type,
lib/std/io/serialization.zig+9-9
...@@ -24,16 +24,16 @@ pub const Packing = enum {...@@ -24,16 +24,16 @@ pub const Packing = enum {
24/// which will be called when the deserializer is used to deserialize24/// which will be called when the deserializer is used to deserialize
25/// that type. It will pass a pointer to the type instance to deserialize25/// that type. It will pass a pointer to the type instance to deserialize
26/// into and a pointer to the deserializer struct.26/// into and a pointer to the deserializer struct.
27pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime InStreamType: type) type {27pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime ReaderType: type) type {
28 return struct {28 return struct {
29 in_stream: if (packing == .Bit) io.BitInStream(endian, InStreamType) else InStreamType,29 in_stream: if (packing == .Bit) io.BitReader(endian, ReaderType) else ReaderType,
3030
31 const Self = @This();31 const Self = @This();
3232
33 pub fn init(in_stream: InStreamType) Self {33 pub fn init(in_stream: ReaderType) Self {
34 return Self{34 return Self{
35 .in_stream = switch (packing) {35 .in_stream = switch (packing) {
36 .Bit => io.bitInStream(endian, in_stream),36 .Bit => io.bitReader(endian, in_stream),
37 .Byte => in_stream,37 .Byte => in_stream,
38 },38 },
39 };39 };
...@@ -45,7 +45,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing,...@@ -45,7 +45,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing,
45 }45 }
4646
47 //@BUG: inferred error issue. See: #138647 //@BUG: inferred error issue. See: #1386
48 fn deserializeInt(self: *Self, comptime T: type) (InStreamType.Error || error{EndOfStream})!T {48 fn deserializeInt(self: *Self, comptime T: type) (ReaderType.Error || error{EndOfStream})!T {
49 comptime assert(trait.is(.Int)(T) or trait.is(.Float)(T));49 comptime assert(trait.is(.Int)(T) or trait.is(.Float)(T));
5050
51 const u8_bit_count = 8;51 const u8_bit_count = 8;
...@@ -368,7 +368,7 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packi...@@ -368,7 +368,7 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packi
368 var _serializer = serializer(endian, packing, out.outStream());368 var _serializer = serializer(endian, packing, out.outStream());
369369
370 var in = io.fixedBufferStream(&data_mem);370 var in = io.fixedBufferStream(&data_mem);
371 var _deserializer = deserializer(endian, packing, in.inStream());371 var _deserializer = deserializer(endian, packing, in.reader());
372372
373 comptime var i = 0;373 comptime var i = 0;
374 inline while (i <= max_test_bitsize) : (i += 1) {374 inline while (i <= max_test_bitsize) : (i += 1) {
...@@ -425,7 +425,7 @@ fn testIntSerializerDeserializerInfNaN(...@@ -425,7 +425,7 @@ fn testIntSerializerDeserializerInfNaN(
425 var _serializer = serializer(endian, packing, out.outStream());425 var _serializer = serializer(endian, packing, out.outStream());
426426
427 var in = io.fixedBufferStream(&data_mem);427 var in = io.fixedBufferStream(&data_mem);
428 var _deserializer = deserializer(endian, packing, in.inStream());428 var _deserializer = deserializer(endian, packing, in.reader());
429429
430 //@TODO: isInf/isNan not currently implemented for f128.430 //@TODO: isInf/isNan not currently implemented for f128.
431 try _serializer.serialize(std.math.nan(f16));431 try _serializer.serialize(std.math.nan(f16));
...@@ -554,7 +554,7 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime packing:...@@ -554,7 +554,7 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime packing:
554 var _serializer = serializer(endian, packing, out.outStream());554 var _serializer = serializer(endian, packing, out.outStream());
555555
556 var in = io.fixedBufferStream(&data_mem);556 var in = io.fixedBufferStream(&data_mem);
557 var _deserializer = deserializer(endian, packing, in.inStream());557 var _deserializer = deserializer(endian, packing, in.reader());
558558
559 try _serializer.serialize(my_inst);559 try _serializer.serialize(my_inst);
560560
...@@ -589,7 +589,7 @@ fn testBadData(comptime endian: builtin.Endian, comptime packing: io.Packing) !v...@@ -589,7 +589,7 @@ fn testBadData(comptime endian: builtin.Endian, comptime packing: io.Packing) !v
589 var _serializer = serializer(endian, packing, out.outStream());589 var _serializer = serializer(endian, packing, out.outStream());
590590
591 var in = io.fixedBufferStream(&data_mem);591 var in = io.fixedBufferStream(&data_mem);
592 var _deserializer = deserializer(endian, packing, in.inStream());592 var _deserializer = deserializer(endian, packing, in.reader());
593593
594 try _serializer.serialize(@as(u14, 3));594 try _serializer.serialize(@as(u14, 3));
595 testing.expectError(error.InvalidEnumTag, _deserializer.deserialize(A));595 testing.expectError(error.InvalidEnumTag, _deserializer.deserialize(A));
lib/std/io/stream_source.zig+17-3
...@@ -2,7 +2,7 @@ const std = @import("../std.zig");...@@ -2,7 +2,7 @@ const std = @import("../std.zig");
2const io = std.io;2const io = std.io;
3const testing = std.testing;3const testing = std.testing;
44
5/// Provides `io.InStream`, `io.OutStream`, and `io.SeekableStream` for in-memory buffers as5/// Provides `io.Reader`, `io.Writer`, and `io.SeekableStream` for in-memory buffers as
6/// well as files.6/// well as files.
7/// For memory sources, if the supplied byte buffer is const, then `io.OutStream` is not available.7/// For memory sources, if the supplied byte buffer is const, then `io.OutStream` is not available.
8/// The error set of the stream functions is the error set of the corresponding file functions.8/// The error set of the stream functions is the error set of the corresponding file functions.
...@@ -16,8 +16,12 @@ pub const StreamSource = union(enum) {...@@ -16,8 +16,12 @@ pub const StreamSource = union(enum) {
16 pub const SeekError = std.fs.File.SeekError;16 pub const SeekError = std.fs.File.SeekError;
17 pub const GetSeekPosError = std.fs.File.GetPosError;17 pub const GetSeekPosError = std.fs.File.GetPosError;
1818
19 pub const InStream = io.InStream(*StreamSource, ReadError, read);19 pub const Reader = io.Reader(*StreamSource, ReadError, read);
20 pub const OutStream = io.OutStream(*StreamSource, WriteError, write);20 /// Deprecated: use `Reader`
21 pub const InStream = Reader;
22 pub const Writer = io.Writer(*StreamSource, WriteError, write);
23 /// Deprecated: use `Writer`
24 pub const OutStream = Writer;
21 pub const SeekableStream = io.SeekableStream(25 pub const SeekableStream = io.SeekableStream(
22 *StreamSource,26 *StreamSource,
23 SeekError,27 SeekError,
...@@ -76,10 +80,20 @@ pub const StreamSource = union(enum) {...@@ -76,10 +80,20 @@ pub const StreamSource = union(enum) {
76 }80 }
77 }81 }
7882
83 pub fn reader(self: *StreamSource) Reader {
84 return .{ .context = self };
85 }
86
87 /// Deprecated: use `reader`
79 pub fn inStream(self: *StreamSource) InStream {88 pub fn inStream(self: *StreamSource) InStream {
80 return .{ .context = self };89 return .{ .context = self };
81 }90 }
8291
92 pub fn writer(self: *StreamSource) Writer {
93 return .{ .context = self };
94 }
95
96 /// Deprecated: use `writer`
83 pub fn outStream(self: *StreamSource) OutStream {97 pub fn outStream(self: *StreamSource) OutStream {
84 return .{ .context = self };98 return .{ .context = self };
85 }99 }
lib/std/io/test.zig+3-3
...@@ -50,8 +50,8 @@ test "write a file, read it, then delete it" {...@@ -50,8 +50,8 @@ test "write a file, read it, then delete it" {
50 const expected_file_size: u64 = "begin".len + data.len + "end".len;50 const expected_file_size: u64 = "begin".len + data.len + "end".len;
51 expectEqual(expected_file_size, file_size);51 expectEqual(expected_file_size, file_size);
5252
53 var buf_stream = io.bufferedInStream(file.inStream());53 var buf_stream = io.bufferedReader(file.reader());
54 const st = buf_stream.inStream();54 const st = buf_stream.reader();
55 const contents = try st.readAllAlloc(std.testing.allocator, 2 * 1024);55 const contents = try st.readAllAlloc(std.testing.allocator, 2 * 1024);
56 defer std.testing.allocator.free(contents);56 defer std.testing.allocator.free(contents);
5757
...@@ -85,7 +85,7 @@ test "BitStreams with File Stream" {...@@ -85,7 +85,7 @@ test "BitStreams with File Stream" {
85 var file = try tmp.dir.openFile(tmp_file_name, .{});85 var file = try tmp.dir.openFile(tmp_file_name, .{});
86 defer file.close();86 defer file.close();
8787
88 var bit_stream = io.bitInStream(builtin.endian, file.inStream());88 var bit_stream = io.bitReader(builtin.endian, file.reader());
8989
90 var out_bits: usize = undefined;90 var out_bits: usize = undefined;
9191
lib/std/pdb.zig+10-6
...@@ -495,7 +495,7 @@ const Msf = struct {...@@ -495,7 +495,7 @@ const Msf = struct {
495 streams: []MsfStream,495 streams: []MsfStream,
496496
497 fn openFile(self: *Msf, allocator: *mem.Allocator, file: File) !void {497 fn openFile(self: *Msf, allocator: *mem.Allocator, file: File) !void {
498 const in = file.inStream();498 const in = file.reader();
499499
500 const superblock = try in.readStruct(SuperBlock);500 const superblock = try in.readStruct(SuperBlock);
501501
...@@ -528,7 +528,7 @@ const Msf = struct {...@@ -528,7 +528,7 @@ const Msf = struct {
528 );528 );
529529
530 const begin = self.directory.pos;530 const begin = self.directory.pos;
531 const stream_count = try self.directory.inStream().readIntLittle(u32);531 const stream_count = try self.directory.reader().readIntLittle(u32);
532 const stream_sizes = try allocator.alloc(u32, stream_count);532 const stream_sizes = try allocator.alloc(u32, stream_count);
533 defer allocator.free(stream_sizes);533 defer allocator.free(stream_sizes);
534534
...@@ -537,7 +537,7 @@ const Msf = struct {...@@ -537,7 +537,7 @@ const Msf = struct {
537 // and must be taken into account when resolving stream indices.537 // and must be taken into account when resolving stream indices.
538 const Nil = 0xFFFFFFFF;538 const Nil = 0xFFFFFFFF;
539 for (stream_sizes) |*s, i| {539 for (stream_sizes) |*s, i| {
540 const size = try self.directory.inStream().readIntLittle(u32);540 const size = try self.directory.reader().readIntLittle(u32);
541 s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.BlockSize);541 s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.BlockSize);
542 }542 }
543543
...@@ -552,7 +552,7 @@ const Msf = struct {...@@ -552,7 +552,7 @@ const Msf = struct {
552 var blocks = try allocator.alloc(u32, size);552 var blocks = try allocator.alloc(u32, size);
553 var j: u32 = 0;553 var j: u32 = 0;
554 while (j < size) : (j += 1) {554 while (j < size) : (j += 1) {
555 const block_id = try self.directory.inStream().readIntLittle(u32);555 const block_id = try self.directory.reader().readIntLittle(u32);
556 const n = (block_id % superblock.BlockSize);556 const n = (block_id % superblock.BlockSize);
557 // 0 is for SuperBlock, 1 and 2 for FPMs.557 // 0 is for SuperBlock, 1 and 2 for FPMs.
558 if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > try file.getEndPos())558 if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > try file.getEndPos())
...@@ -647,7 +647,7 @@ const MsfStream = struct {...@@ -647,7 +647,7 @@ const MsfStream = struct {
647 pub fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {647 pub fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
648 var list = ArrayList(u8).init(allocator);648 var list = ArrayList(u8).init(allocator);
649 while (true) {649 while (true) {
650 const byte = try self.inStream().readByte();650 const byte = try self.reader().readByte();
651 if (byte == 0) {651 if (byte == 0) {
652 return list.span();652 return list.span();
653 }653 }
...@@ -661,7 +661,7 @@ const MsfStream = struct {...@@ -661,7 +661,7 @@ const MsfStream = struct {
661 var offset = self.pos % self.block_size;661 var offset = self.pos % self.block_size;
662662
663 try self.in_file.seekTo(block * self.block_size + offset);663 try self.in_file.seekTo(block * self.block_size + offset);
664 const in = self.in_file.inStream();664 const in = self.in_file.reader();
665665
666 var size: usize = 0;666 var size: usize = 0;
667 var rem_buffer = buffer;667 var rem_buffer = buffer;
...@@ -708,6 +708,10 @@ const MsfStream = struct {...@@ -708,6 +708,10 @@ const MsfStream = struct {
708 return block * self.block_size + offset;708 return block * self.block_size + offset;
709 }709 }
710710
711 pub fn reader(self: *MsfStream) std.io.Reader(*MsfStream, Error, read) {
712 return .{ .context = self };
713 }
714 /// Deprecated: use `reader`
711 pub fn inStream(self: *MsfStream) std.io.InStream(*MsfStream, Error, read) {715 pub fn inStream(self: *MsfStream) std.io.InStream(*MsfStream, Error, read) {
712 return .{ .context = self };716 return .{ .context = self };
713 }717 }
lib/std/process.zig+3-3
...@@ -615,8 +615,8 @@ pub fn getUserInfo(name: []const u8) !UserInfo {...@@ -615,8 +615,8 @@ pub fn getUserInfo(name: []const u8) !UserInfo {
615/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else615/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
616/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.616/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
617pub fn posixGetUserInfo(name: []const u8) !UserInfo {617pub fn posixGetUserInfo(name: []const u8) !UserInfo {
618 var in_stream = try io.InStream.open("/etc/passwd", null);618 var reader = try io.Reader.open("/etc/passwd", null);
619 defer in_stream.close();619 defer reader.close();
620620
621 const State = enum {621 const State = enum {
622 Start,622 Start,
...@@ -633,7 +633,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {...@@ -633,7 +633,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
633 var gid: u32 = 0;633 var gid: u32 = 0;
634634
635 while (true) {635 while (true) {
636 const amt_read = try in_stream.read(buf[0..]);636 const amt_read = try reader.read(buf[0..]);
637 for (buf[0..amt_read]) |byte| {637 for (buf[0..amt_read]) |byte| {
638 switch (state) {638 switch (state) {
639 .Start => switch (byte) {639 .Start => switch (byte) {