Skip to content

Commit a306bfc

Browse files
authored
Merge pull request #17344 from ziglang/type-erased-reader
std: add type-erased reader; base GenericReader on it
2 parents 4d1e8ef + 9a09651 commit a306bfc

File tree

8 files changed

+1022
-764
lines changed

8 files changed

+1022
-764
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ set(ZIG_STAGE2_SOURCES
265265
"${CMAKE_SOURCE_DIR}/lib/std/io/find_byte_writer.zig"
266266
"${CMAKE_SOURCE_DIR}/lib/std/io/fixed_buffer_stream.zig"
267267
"${CMAKE_SOURCE_DIR}/lib/std/io/limited_reader.zig"
268-
"${CMAKE_SOURCE_DIR}/lib/std/io/reader.zig"
268+
"${CMAKE_SOURCE_DIR}/lib/std/io/Reader.zig"
269269
"${CMAKE_SOURCE_DIR}/lib/std/io/seekable_stream.zig"
270270
"${CMAKE_SOURCE_DIR}/lib/std/io/writer.zig"
271271
"${CMAKE_SOURCE_DIR}/lib/std/json.zig"

lib/std/Build/Step/CheckObject.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ const MachODumper = struct {
539539
strings: []const u8,
540540
};
541541

542-
fn parseAndDump(step: *Step, bytes: []align(@alignOf(u64)) const u8) ![]const u8 {
542+
fn parseAndDump(step: *Step, bytes: []const u8) ![]const u8 {
543543
const gpa = step.owner.allocator;
544544
var stream = std.io.fixedBufferStream(bytes);
545545
const reader = stream.reader();
@@ -556,7 +556,7 @@ const MachODumper = struct {
556556
var sections = std.ArrayList(macho.section_64).init(gpa);
557557
var imports = std.ArrayList([]const u8).init(gpa);
558558

559-
var it = LoadCommandIterator{
559+
var it: LoadCommandIterator = .{
560560
.ncmds = hdr.ncmds,
561561
.buffer = bytes[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
562562
};

lib/std/io.zig

Lines changed: 252 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const fs = std.fs;
1010
const mem = std.mem;
1111
const meta = std.meta;
1212
const File = std.fs.File;
13+
const Allocator = std.mem.Allocator;
1314

1415
pub const Mode = enum {
1516
/// I/O operates normally, waiting for the operating system syscalls to complete.
@@ -105,7 +106,255 @@ pub fn getStdIn() File {
105106
};
106107
}
107108

108-
pub const Reader = @import("io/reader.zig").Reader;
109+
pub fn GenericReader(
110+
comptime Context: type,
111+
comptime ReadError: type,
112+
/// Returns the number of bytes read. It may be less than buffer.len.
113+
/// If the number of bytes read is 0, it means end of stream.
114+
/// End of stream is not an error condition.
115+
comptime readFn: fn (context: Context, buffer: []u8) ReadError!usize,
116+
) type {
117+
return struct {
118+
context: Context,
119+
120+
pub const Error = ReadError;
121+
pub const NoEofError = ReadError || error{
122+
EndOfStream,
123+
};
124+
125+
pub inline fn read(self: Self, buffer: []u8) Error!usize {
126+
return readFn(self.context, buffer);
127+
}
128+
129+
pub inline fn readAll(self: Self, buffer: []u8) Error!usize {
130+
return @errorCast(self.any().readAll(buffer));
131+
}
132+
133+
pub inline fn readAtLeast(self: Self, buffer: []u8, len: usize) Error!usize {
134+
return @errorCast(self.any().readAtLeast(buffer, len));
135+
}
136+
137+
pub inline fn readNoEof(self: Self, buf: []u8) NoEofError!void {
138+
return @errorCast(self.any().readNoEof(buf));
139+
}
140+
141+
pub inline fn readAllArrayList(
142+
self: Self,
143+
array_list: *std.ArrayList(u8),
144+
max_append_size: usize,
145+
) (error{StreamTooLong} || Error)!void {
146+
return @errorCast(self.any().readAllArrayList(array_list, max_append_size));
147+
}
148+
149+
pub inline fn readAllArrayListAligned(
150+
self: Self,
151+
comptime alignment: ?u29,
152+
array_list: *std.ArrayListAligned(u8, alignment),
153+
max_append_size: usize,
154+
) (error{StreamTooLong} || Error)!void {
155+
return @errorCast(self.any().readAllArrayListAligned(
156+
alignment,
157+
array_list,
158+
max_append_size,
159+
));
160+
}
161+
162+
pub inline fn readAllAlloc(
163+
self: Self,
164+
allocator: Allocator,
165+
max_size: usize,
166+
) (Error || error{StreamTooLong})![]u8 {
167+
return @errorCast(self.any().readAllAlloc(allocator, max_size));
168+
}
169+
170+
pub inline fn readUntilDelimiterArrayList(
171+
self: Self,
172+
array_list: *std.ArrayList(u8),
173+
delimiter: u8,
174+
max_size: usize,
175+
) (NoEofError || error{StreamTooLong})!void {
176+
return @errorCast(self.any().readUntilDelimiterArrayList(
177+
array_list,
178+
delimiter,
179+
max_size,
180+
));
181+
}
182+
183+
pub inline fn readUntilDelimiterAlloc(
184+
self: Self,
185+
allocator: Allocator,
186+
delimiter: u8,
187+
max_size: usize,
188+
) (NoEofError || error{StreamTooLong})![]u8 {
189+
return @errorCast(self.any().readUntilDelimiterAlloc(
190+
allocator,
191+
delimiter,
192+
max_size,
193+
));
194+
}
195+
196+
pub inline fn readUntilDelimiter(
197+
self: Self,
198+
buf: []u8,
199+
delimiter: u8,
200+
) (NoEofError || error{StreamTooLong})![]u8 {
201+
return @errorCast(self.any().readUntilDelimiter(buf, delimiter));
202+
}
203+
204+
pub inline fn readUntilDelimiterOrEofAlloc(
205+
self: Self,
206+
allocator: Allocator,
207+
delimiter: u8,
208+
max_size: usize,
209+
) (Error || error{StreamTooLong})!?[]u8 {
210+
return @errorCast(self.any().readUntilDelimiterOrEofAlloc(
211+
allocator,
212+
delimiter,
213+
max_size,
214+
));
215+
}
216+
217+
pub inline fn readUntilDelimiterOrEof(
218+
self: Self,
219+
buf: []u8,
220+
delimiter: u8,
221+
) (Error || error{StreamTooLong})!?[]u8 {
222+
return @errorCast(self.any().readUntilDelimiterOrEof(buf, delimiter));
223+
}
224+
225+
pub inline fn streamUntilDelimiter(
226+
self: Self,
227+
writer: anytype,
228+
delimiter: u8,
229+
optional_max_size: ?usize,
230+
) (NoEofError || error{StreamTooLong} || @TypeOf(writer).Error)!void {
231+
return @errorCast(self.any().streamUntilDelimiter(
232+
writer,
233+
delimiter,
234+
optional_max_size,
235+
));
236+
}
237+
238+
pub inline fn skipUntilDelimiterOrEof(self: Self, delimiter: u8) Error!void {
239+
return @errorCast(self.any().skipUntilDelimiterOrEof(delimiter));
240+
}
241+
242+
pub inline fn readByte(self: Self) NoEofError!u8 {
243+
return @errorCast(self.any().readByte());
244+
}
245+
246+
pub inline fn readByteSigned(self: Self) NoEofError!i8 {
247+
return @errorCast(self.any().readByteSigned());
248+
}
249+
250+
pub inline fn readBytesNoEof(
251+
self: Self,
252+
comptime num_bytes: usize,
253+
) NoEofError![num_bytes]u8 {
254+
return @errorCast(self.any().readBytesNoEof(num_bytes));
255+
}
256+
257+
pub inline fn readIntoBoundedBytes(
258+
self: Self,
259+
comptime num_bytes: usize,
260+
bounded: *std.BoundedArray(u8, num_bytes),
261+
) Error!void {
262+
return @errorCast(self.any().readIntoBoundedBytes(num_bytes, bounded));
263+
}
264+
265+
pub inline fn readBoundedBytes(
266+
self: Self,
267+
comptime num_bytes: usize,
268+
) Error!std.BoundedArray(u8, num_bytes) {
269+
return @errorCast(self.any().readBoundedBytes(num_bytes));
270+
}
271+
272+
pub inline fn readIntNative(self: Self, comptime T: type) NoEofError!T {
273+
return @errorCast(self.any().readIntNative(T));
274+
}
275+
276+
pub inline fn readIntForeign(self: Self, comptime T: type) NoEofError!T {
277+
return @errorCast(self.any().readIntForeign(T));
278+
}
279+
280+
pub inline fn readIntLittle(self: Self, comptime T: type) NoEofError!T {
281+
return @errorCast(self.any().readIntLittle(T));
282+
}
283+
284+
pub inline fn readIntBig(self: Self, comptime T: type) NoEofError!T {
285+
return @errorCast(self.any().readIntBig(T));
286+
}
287+
288+
pub inline fn readInt(self: Self, comptime T: type, endian: std.builtin.Endian) NoEofError!T {
289+
return @errorCast(self.any().readInt(T, endian));
290+
}
291+
292+
pub inline fn readVarInt(
293+
self: Self,
294+
comptime ReturnType: type,
295+
endian: std.builtin.Endian,
296+
size: usize,
297+
) NoEofError!ReturnType {
298+
return @errorCast(self.any().readVarInt(ReturnType, endian, size));
299+
}
300+
301+
pub const SkipBytesOptions = AnyReader.SkipBytesOptions;
302+
303+
pub inline fn skipBytes(
304+
self: Self,
305+
num_bytes: u64,
306+
comptime options: SkipBytesOptions,
307+
) NoEofError!void {
308+
return @errorCast(self.any().skipBytes(num_bytes, options));
309+
}
310+
311+
pub inline fn isBytes(self: Self, slice: []const u8) Error!bool {
312+
return @errorCast(self.any().isBytes(slice));
313+
}
314+
315+
pub inline fn readStruct(self: Self, comptime T: type) NoEofError!T {
316+
return @errorCast(self.any().readStruct(T));
317+
}
318+
319+
pub inline fn readStructBig(self: Self, comptime T: type) NoEofError!T {
320+
return @errorCast(self.any().readStructBig(T));
321+
}
322+
323+
pub const ReadEnumError = Error || error{
324+
/// An integer was read, but it did not match any of the tags in the supplied enum.
325+
InvalidValue,
326+
};
327+
328+
pub inline fn readEnum(
329+
self: Self,
330+
comptime Enum: type,
331+
endian: std.builtin.Endian,
332+
) ReadEnumError!Enum {
333+
return @errorCast(self.any().readEnum(Enum, endian));
334+
}
335+
336+
pub inline fn any(self: *const Self) AnyReader {
337+
return .{
338+
.context = @ptrCast(&self.context),
339+
.readFn = typeErasedReadFn,
340+
};
341+
}
342+
343+
const Self = @This();
344+
345+
fn typeErasedReadFn(context: *const anyopaque, buffer: []u8) anyerror!usize {
346+
const ptr: *const Context = @alignCast(@ptrCast(context));
347+
return readFn(ptr.*, buffer);
348+
}
349+
};
350+
}
351+
352+
/// Deprecated; consider switching to `AnyReader` or use `GenericReader`
353+
/// to use previous API.
354+
pub const Reader = GenericReader;
355+
356+
pub const AnyReader = @import("io/Reader.zig");
357+
109358
pub const Writer = @import("io/writer.zig").Writer;
110359
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
111360

@@ -168,7 +417,7 @@ test "null_writer" {
168417
}
169418

170419
pub fn poll(
171-
allocator: std.mem.Allocator,
420+
allocator: Allocator,
172421
comptime StreamEnum: type,
173422
files: PollFiles(StreamEnum),
174423
) Poller(StreamEnum) {
@@ -418,6 +667,7 @@ pub fn PollFiles(comptime StreamEnum: type) type {
418667
}
419668

420669
test {
670+
_ = AnyReader;
421671
_ = @import("io/bit_reader.zig");
422672
_ = @import("io/bit_writer.zig");
423673
_ = @import("io/buffered_atomic_file.zig");
@@ -427,7 +677,6 @@ test {
427677
_ = @import("io/counting_writer.zig");
428678
_ = @import("io/counting_reader.zig");
429679
_ = @import("io/fixed_buffer_stream.zig");
430-
_ = @import("io/reader.zig");
431680
_ = @import("io/writer.zig");
432681
_ = @import("io/peek_stream.zig");
433682
_ = @import("io/seekable_stream.zig");

0 commit comments

Comments
 (0)