From 909efde8a3b92b423f0298ea181ac2c1f614fd05 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 7 Dec 2022 18:01:44 +0100 Subject: [PATCH] Have Reader/Writer be a runtime instead of comptime interface Current version of Reader and Writer takes 3 comptime arguments to specify the type. A Context, Error and read/write function. The drawbacks to this approuch are: - No Reader/Writer types are actually the same. A FixedBufferReader.Reader is no the same as a File.Reader - This means you have to take `anytype` everywhere and every different reader/writer will generate a copy of the function taking them. - Type names are very long, as they include the arguments in the names. This is made even worse by the fact that readers and writers tend to be composed. This affects: - Error messages. They can become very hard to read and understand - C backend. Type names become incredibly long, which is one of the contributing factors to why the output is big This commit changes Reader and Writer to be more like Allocator. They are now a pointer + a function pointer to the function that implementions the read/write. This reduces the arguments taken by Reader and Writer from 3 to 1, which is the error set. We cannot eliminate this. Benifits: - Now, at least some Reader/Writer types can be the same. When they share the same error set, they will be the same type. - We could also add some functionality to promote a Reader/Writer to use a super set of its own error set. For example, we could have: const a: Reader(error{}) = ...; const b: Reader(error{A}) = ...; const readers = &[_]Reader(anyerror){ a.promote(anyerror), b.promote(anyerror), }; - Type names are a lot shorter and nesting Readers and Writers will not produce names that include the child reader/writer. - Error messages are better: const std = @import("std"); fn a(b: usize) void { _ = b; } test { var counting_writer = std.io.countingWriter(std.io.null_writer); // Before: expected type 'usize', found 'io.writer.Writer(*io.counting_writer.CountingWriter(io.writer.Writer(void,error{},(function 'dummyWrite'))),error{},(function 'write'))' // After: expected type 'usize', found 'io.writer.Writer(error{})' a(counting_writer.writer()); } - C backend produces less code: 108.368.735 zig2.after.c 117.846.808 zig2.before.c --- lib/std/array_list.zig | 23 ++-------------- lib/std/fs/file.zig | 30 ++++++++++++++++----- lib/std/io.zig | 9 ++++--- lib/std/io/buffered_writer.zig | 4 +-- lib/std/io/counting_reader.zig | 4 +-- lib/std/io/counting_writer.zig | 4 +-- lib/std/io/fixed_buffer_stream.zig | 8 +++--- lib/std/io/limited_reader.zig | 4 +-- lib/std/io/reader.zig | 43 +++++++++++++++++++++++------- lib/std/io/writer.zig | 37 ++++++++++++++++++++----- lib/std/zig/render.zig | 4 +-- src/AstGen.zig | 33 +++++++++++------------ src/Compilation.zig | 2 +- src/codegen/c.zig | 4 +-- src/link/MachO/Archive.zig | 2 +- src/link/MachO/zld.zig | 2 +- src/link/Wasm.zig | 7 ++++- src/link/Wasm/Object.zig | 37 ++++++++++++------------- 18 files changed, 155 insertions(+), 102 deletions(-) diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index e8675fde61ce..727f5308b1d5 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -270,11 +270,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { @compileError("The Writer interface is only defined for ArrayList(u8) " ++ "but the given type is ArrayList(" ++ @typeName(T) ++ ")") else - std.io.Writer(*Self, error{OutOfMemory}, appendWrite); + std.io.Writer(error{OutOfMemory}); /// Initializes a Writer which will append to the list. pub fn writer(self: *Self) Writer { - return .{ .context = self }; + return Writer.init(self, appendWrite); } /// Same as `append` except it returns the number of bytes written, which is always the same @@ -688,25 +688,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ allocator: Allocator, }; - pub const Writer = if (T != u8) - @compileError("The Writer interface is only defined for ArrayList(u8) " ++ - "but the given type is ArrayList(" ++ @typeName(T) ++ ")") - else - std.io.Writer(WriterContext, error{OutOfMemory}, appendWrite); - - /// Initializes a Writer which will append to the list. - pub fn writer(self: *Self, allocator: Allocator) Writer { - return .{ .context = .{ .self = self, .allocator = allocator } }; - } - - /// Same as `append` except it returns the number of bytes written, which is always the same - /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API. - /// Invalidates pointers if additional memory is needed. - fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize { - try context.self.appendSlice(context.allocator, m); - return m.len; - } - /// Append a value to the list `n` times. /// Allocates more memory as necessary. /// Invalidates pointers if additional memory is needed. diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index a1e81c9b9418..124af7e54e76 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -1372,16 +1372,34 @@ pub const File = struct { } } - pub const Reader = io.Reader(File, ReadError, read); + pub const Reader = io.Reader(ReadError); + + pub fn reader(file: *const File) Reader { + // HACK: The Reader interface expects a mutable pointer to context, but there is no need + // to have that here, as `readFn` never modifies the memory of the `File` struct. + // We want the `Reader` interface to handle these kinds of situations, but sadly + // there is no way to discard const and compile time, so that would mean that + // `FixedBufferStream` could not be used in that context. + return Reader.init(@intToPtr(*File, @ptrToInt(file)), readFn); + } - pub fn reader(file: File) Reader { - return .{ .context = file }; + fn readFn(self: *File, buffer: []u8) ReadError!usize { + return self.read(buffer); } - pub const Writer = io.Writer(File, WriteError, write); + pub const Writer = io.Writer(WriteError); - pub fn writer(file: File) Writer { - return .{ .context = file }; + pub fn writer(file: *const File) Writer { + // HACK: The Writer interface expects a mutable pointer to context, but there is no need + // to have that here, as `writeFn` never modifies the memory of the `File` struct. + // We want the `Writer` interface to handle these kinds of situations, but sadly + // there is no way to discard const and compile time, so that would mean that + // `FixedBufferStream` could not be used in that context. + return Writer.init(@intToPtr(*File, @ptrToInt(file)), writeFn); + } + + fn writeFn(self: *File, bytes: []const u8) WriteError!usize { + return self.write(bytes); } pub const SeekableStream = io.SeekableStream( diff --git a/lib/std/io.zig b/lib/std/io.zig index b12ca80142ab..15147e70b921 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -162,10 +162,13 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt pub const StreamSource = @import("io/stream_source.zig").StreamSource; /// A Writer that doesn't write to anything. -pub const null_writer = @as(NullWriter, .{ .context = {} }); +pub const null_writer = NullWriter{ + .context = undefined, + .writeFn = dummyWrite, +}; -const NullWriter = Writer(void, error{}, dummyWrite); -fn dummyWrite(context: void, data: []const u8) error{}!usize { +const NullWriter = Writer(error{}); +fn dummyWrite(context: *anyopaque, data: []const u8) error{}!usize { _ = context; return data.len; } diff --git a/lib/std/io/buffered_writer.zig b/lib/std/io/buffered_writer.zig index 497a1810a7e1..b84d909a78c9 100644 --- a/lib/std/io/buffered_writer.zig +++ b/lib/std/io/buffered_writer.zig @@ -10,7 +10,7 @@ pub fn BufferedWriter(comptime buffer_size: usize, comptime WriterType: type) ty end: usize = 0, pub const Error = WriterType.Error; - pub const Writer = io.Writer(*Self, Error, write); + pub const Writer = io.Writer(Error); const Self = @This(); @@ -20,7 +20,7 @@ pub fn BufferedWriter(comptime buffer_size: usize, comptime WriterType: type) ty } pub fn writer(self: *Self) Writer { - return .{ .context = self }; + return Writer.init(self, write); } pub fn write(self: *Self, bytes: []const u8) Error!usize { diff --git a/lib/std/io/counting_reader.zig b/lib/std/io/counting_reader.zig index 54e8e6f531a3..c49da91b62bf 100644 --- a/lib/std/io/counting_reader.zig +++ b/lib/std/io/counting_reader.zig @@ -9,7 +9,7 @@ pub fn CountingReader(comptime ReaderType: anytype) type { bytes_read: u64 = 0, pub const Error = ReaderType.Error; - pub const Reader = io.Reader(*@This(), Error, read); + pub const Reader = io.Reader(Error); pub fn read(self: *@This(), buf: []u8) Error!usize { const amt = try self.child_reader.read(buf); @@ -18,7 +18,7 @@ pub fn CountingReader(comptime ReaderType: anytype) type { } pub fn reader(self: *@This()) Reader { - return .{ .context = self }; + return Reader.init(self, read); } }; } diff --git a/lib/std/io/counting_writer.zig b/lib/std/io/counting_writer.zig index ee86c2a9b1e0..6d6bbfe638c9 100644 --- a/lib/std/io/counting_writer.zig +++ b/lib/std/io/counting_writer.zig @@ -9,7 +9,7 @@ pub fn CountingWriter(comptime WriterType: type) type { child_stream: WriterType, pub const Error = WriterType.Error; - pub const Writer = io.Writer(*Self, Error, write); + pub const Writer = io.Writer(Error); const Self = @This(); @@ -20,7 +20,7 @@ pub fn CountingWriter(comptime WriterType: type) type { } pub fn writer(self: *Self) Writer { - return .{ .context = self }; + return Writer.init(self, write); } }; } diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig index b002bb47b83a..6c3597e15684 100644 --- a/lib/std/io/fixed_buffer_stream.zig +++ b/lib/std/io/fixed_buffer_stream.zig @@ -17,8 +17,8 @@ pub fn FixedBufferStream(comptime Buffer: type) type { pub const SeekError = error{}; pub const GetSeekPosError = error{}; - pub const Reader = io.Reader(*Self, ReadError, read); - pub const Writer = io.Writer(*Self, WriteError, write); + pub const Reader = io.Reader(ReadError); + pub const Writer = io.Writer(WriteError); pub const SeekableStream = io.SeekableStream( *Self, @@ -33,11 +33,11 @@ pub fn FixedBufferStream(comptime Buffer: type) type { const Self = @This(); pub fn reader(self: *Self) Reader { - return .{ .context = self }; + return Reader.init(self, read); } pub fn writer(self: *Self) Writer { - return .{ .context = self }; + return Writer.init(self, write); } pub fn seekableStream(self: *Self) SeekableStream { diff --git a/lib/std/io/limited_reader.zig b/lib/std/io/limited_reader.zig index aa00af0d0925..14095552acdc 100644 --- a/lib/std/io/limited_reader.zig +++ b/lib/std/io/limited_reader.zig @@ -9,7 +9,7 @@ pub fn LimitedReader(comptime ReaderType: type) type { bytes_left: u64, pub const Error = ReaderType.Error; - pub const Reader = io.Reader(*Self, Error, read); + pub const Reader = io.Reader(Error); const Self = @This(); @@ -21,7 +21,7 @@ pub fn LimitedReader(comptime ReaderType: type) type { } pub fn reader(self: *Self) Reader { - return .{ .context = self }; + return Reader.init(self, read); } }; } diff --git a/lib/std/io/reader.zig b/lib/std/io/reader.zig index b86aca6cbd40..2e0886c8fb5c 100644 --- a/lib/std/io/reader.zig +++ b/lib/std/io/reader.zig @@ -4,26 +4,33 @@ const assert = std.debug.assert; const mem = std.mem; const testing = std.testing; -pub fn Reader( - comptime Context: type, - comptime ReadError: type, - /// Returns the number of bytes read. It may be less than buffer.len. - /// If the number of bytes read is 0, it means end of stream. - /// End of stream is not an error condition. - comptime readFn: fn (context: Context, buffer: []u8) ReadError!usize, -) type { +pub fn Reader(comptime ReadError: type) type { return struct { pub const Error = ReadError; - context: Context, + context: *anyopaque, + readFn: *const fn (context: *anyopaque, buffer: []u8) Error!usize, const Self = @This(); + pub fn init( + context: anytype, + /// Returns the number of bytes read. It may be less than buffer.len. + /// If the number of bytes read is 0, it means end of stream. + /// End of stream is not an error condition. + comptime readFn: *const fn (ctx: @TypeOf(context), buffer: []u8) Error!usize, + ) Self { + return Self{ + .context = context, + .readFn = makeWrapper(context, Error, readFn), + }; + } + /// Returns the number of bytes read. It may be less than buffer.len. /// If the number of bytes read is 0, it means end of stream. /// End of stream is not an error condition. pub fn read(self: Self, buffer: []u8) Error!usize { - return readFn(self.context, buffer); + return self.readFn(self.context, buffer); } /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it @@ -363,6 +370,22 @@ pub fn Reader( }; } +fn makeWrapper( + context: anytype, + comptime Error: type, + comptime readFn: *const fn (ctx: @TypeOf(context), buffer: []u8) Error!usize, +) *const fn (ctx: *anyopaque, buffer: []u8) Error!usize { + const Context = @TypeOf(context.*); + const ContextPtr = @TypeOf(context); + return struct { + fn wrapper(ctx: *anyopaque, buffer: []u8) Error!usize { + const aligned = @alignCast(@alignOf(Context), ctx); + const casted = @ptrCast(ContextPtr, aligned); + return readFn(casted, buffer); + } + }.wrapper; +} + test "Reader" { var buf = "a\x02".*; var fis = std.io.fixedBufferStream(&buf); diff --git a/lib/std/io/writer.zig b/lib/std/io/writer.zig index 3160c37ff201..0f5060380f5f 100644 --- a/lib/std/io/writer.zig +++ b/lib/std/io/writer.zig @@ -2,19 +2,26 @@ const std = @import("../std.zig"); const assert = std.debug.assert; const mem = std.mem; -pub fn Writer( - comptime Context: type, - comptime WriteError: type, - comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize, -) type { +pub fn Writer(comptime WriteError: type) type { return struct { - context: Context, + context: *anyopaque, + writeFn: *const fn (ctx: *anyopaque, bytes: []const u8) Error!usize, const Self = @This(); pub const Error = WriteError; + pub fn init( + context: anytype, + comptime writeFn: *const fn (ctx: @TypeOf(context), bytes: []const u8) Error!usize, + ) Self { + return Self{ + .context = context, + .writeFn = makeWrapper(context, Error, writeFn), + }; + } + pub fn write(self: Self, bytes: []const u8) Error!usize { - return writeFn(self.context, bytes); + return self.writeFn(self.context, bytes); } pub fn writeAll(self: Self, bytes: []const u8) Error!void { @@ -89,3 +96,19 @@ pub fn Writer( } }; } + +fn makeWrapper( + context: anytype, + comptime Error: type, + comptime writeFn: *const fn (ctx: @TypeOf(context), bytes: []const u8) Error!usize, +) *const fn (ctx: *anyopaque, bytes: []const u8) Error!usize { + const Context = @TypeOf(context.*); + const ContextPtr = @TypeOf(context); + return struct { + fn wrapper(ctx: *anyopaque, bytes: []const u8) Error!usize { + const aligned = @alignCast(@alignOf(Context), ctx); + const casted = @ptrCast(ContextPtr, aligned); + return writeFn(casted, bytes); + } + }.wrapper; +} diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 0c54b3c75136..1fa76908701c 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -2932,7 +2932,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { return struct { const Self = @This(); pub const WriteError = UnderlyingWriter.Error; - pub const Writer = std.io.Writer(*Self, WriteError, write); + pub const Writer = std.io.Writer(WriteError); underlying_writer: UnderlyingWriter, @@ -2955,7 +2955,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { indent_next_line: usize = 0, pub fn writer(self: *Self) Writer { - return .{ .context = self }; + return Writer.init(self, write); } pub fn write(self: *Self, bytes: []const u8) WriteError!usize { diff --git a/src/AstGen.zig b/src/AstGen.zig index 4e571ffda9cf..c7a8eaffb40c 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -10174,9 +10174,7 @@ fn appendErrorNodeNotes( notes: []const u32, ) Allocator.Error!void { @setCold(true); - const string_bytes = &astgen.string_bytes; - const msg = @intCast(u32, string_bytes.items.len); - try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); + const msg = try astgen.printStringBytes(format, args); const notes_index: u32 = if (notes.len != 0) blk: { const notes_start = astgen.extra.items.len; try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); @@ -10241,9 +10239,7 @@ fn appendErrorTokNotes( notes: []const u32, ) !void { @setCold(true); - const string_bytes = &astgen.string_bytes; - const msg = @intCast(u32, string_bytes.items.len); - try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); + const msg = try astgen.printStringBytes(format, args); const notes_index: u32 = if (notes.len != 0) blk: { const notes_start = astgen.extra.items.len; try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); @@ -10280,9 +10276,7 @@ fn appendErrorOff( args: anytype, ) Allocator.Error!void { @setCold(true); - const string_bytes = &astgen.string_bytes; - const msg = @intCast(u32, string_bytes.items.len); - try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); + const msg = try astgen.printStringBytes(format, args); try astgen.compile_errors.append(astgen.gpa, .{ .msg = msg, .node = 0, @@ -10299,11 +10293,8 @@ fn errNoteTok( args: anytype, ) Allocator.Error!u32 { @setCold(true); - const string_bytes = &astgen.string_bytes; - const msg = @intCast(u32, string_bytes.items.len); - try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); return astgen.addExtra(Zir.Inst.CompileErrors.Item{ - .msg = msg, + .msg = try astgen.printStringBytes(format, args), .node = 0, .token = token, .byte_offset = 0, @@ -10318,11 +10309,8 @@ fn errNoteNode( args: anytype, ) Allocator.Error!u32 { @setCold(true); - const string_bytes = &astgen.string_bytes; - const msg = @intCast(u32, string_bytes.items.len); - try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); return astgen.addExtra(Zir.Inst.CompileErrors.Item{ - .msg = msg, + .msg = try astgen.printStringBytes(format, args), .node = node, .token = 0, .byte_offset = 0, @@ -10330,6 +10318,17 @@ fn errNoteNode( }); } +fn printStringBytes(astgen: *AstGen, comptime format: []const u8, args: anytype) !u32 { + const string_bytes = &astgen.string_bytes; + const msg = @intCast(u32, string_bytes.items.len); + + var managed = string_bytes.toManaged(astgen.gpa); + defer string_bytes.* = managed.moveToUnmanaged(); + try managed.writer().print(format ++ "\x00", args); + + return msg; +} + fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 { const gpa = astgen.gpa; const string_bytes = &astgen.string_bytes; diff --git a/src/Compilation.zig b/src/Compilation.zig index 7f6314bbb04c..7d615cd2d7a8 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -439,7 +439,7 @@ pub const AllErrors = struct { try counting_stderr.writeAll(": "); // This is the length of the part before the error message: // e.g. "file.zig:4:5: error: " - const prefix_len = @intCast(usize, counting_stderr.context.bytes_written); + const prefix_len = @intCast(usize, counting_writer.bytes_written); ttyconf.setColor(stderr, .Reset); ttyconf.setColor(stderr, .Bold); if (src.count == 1) { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 1fd953973071..de038edac593 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -6695,7 +6695,7 @@ fn IndentWriter(comptime UnderlyingWriter: type) type { return struct { const Self = @This(); pub const Error = UnderlyingWriter.Error; - pub const Writer = std.io.Writer(*Self, Error, write); + pub const Writer = std.io.Writer(Error); pub const indent_delta = 1; @@ -6704,7 +6704,7 @@ fn IndentWriter(comptime UnderlyingWriter: type) type { current_line_empty: bool = true, pub fn writer(self: *Self) Writer { - return .{ .context = self }; + return Writer.init(self, write); } pub fn write(self: *Self, bytes: []const u8) Error!usize { diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index d222394ad5a1..3dcd8f864b6c 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -189,7 +189,7 @@ pub fn parseObject( offset: u32, ) !Object { const reader = self.file.reader(); - try reader.context.seekTo(self.fat_offset + offset); + try self.file.seekTo(self.fat_offset + offset); const object_header = try reader.readStruct(ar_hdr); diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 9baecd326a3c..726db83b32ae 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -122,7 +122,7 @@ pub const Zld = struct { const cpu_arch = self.options.target.cpu.arch; const reader = file.reader(); const fat_offset = try fat.getLibraryOffset(reader, cpu_arch); - try reader.context.seekTo(fat_offset); + try file.seekTo(fat_offset); var archive = Archive{ .name = name, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 4a9db75c9806..c7ffa39ec6b5 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -2098,7 +2098,12 @@ fn populateErrorNameTable(wasm: *Wasm) !void { const offset = @intCast(u32, atom.code.items.len); // first we create the data for the slice of the name try atom.code.appendNTimes(wasm.base.allocator, 0, 4); // ptr to name, will be relocated - try atom.code.writer(wasm.base.allocator).writeIntLittle(u32, len - 1); + { + var managed = atom.code.toManaged(wasm.base.allocator); + defer atom.code = managed.moveToUnmanaged(); + try managed.writer().writeIntLittle(u32, len - 1); + } + // create relocation to the error name try atom.relocs.append(wasm.base.allocator, .{ .index = names_symbol_index, diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index e5947228a527..2a690c19816a 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -374,13 +374,13 @@ fn Parser(comptime ReaderType: type) type { if (std.mem.eql(u8, name, "linking")) { is_object_file.* = true; parser.object.relocatable_data = relocatable_data.items; // at this point no new relocatable sections will appear so we're free to store them. - try parser.parseMetadata(gpa, @intCast(usize, reader.context.bytes_left)); + try parser.parseMetadata(gpa, @intCast(usize, limited_reader.bytes_left)); } else if (std.mem.startsWith(u8, name, "reloc")) { try parser.parseRelocations(gpa); } else if (std.mem.eql(u8, name, "target_features")) { try parser.parseFeatures(gpa); } else if (std.mem.startsWith(u8, name, ".debug")) { - const debug_size = @intCast(u32, reader.context.bytes_left); + const debug_size = @intCast(u32, limited_reader.bytes_left); const debug_content = try gpa.alloc(u8, debug_size); errdefer gpa.free(debug_content); try reader.readNoEof(debug_content); @@ -394,7 +394,7 @@ fn Parser(comptime ReaderType: type) type { .section_index = section_index, }); } else { - try reader.skipBytes(reader.context.bytes_left, .{}); + try reader.skipBytes(limited_reader.bytes_left, .{}); } }, .type => { @@ -409,7 +409,7 @@ fn Parser(comptime ReaderType: type) type { result.* = try readEnum(std.wasm.Valtype, reader); } } - try assertEnd(reader); + try assertEnd(&limited_reader); }, .import => { for (try readVec(&parser.object.imports, reader, gpa)) |*import| { @@ -443,13 +443,13 @@ fn Parser(comptime ReaderType: type) type { .kind = kind_value, }; } - try assertEnd(reader); + try assertEnd(&limited_reader); }, .function => { for (try readVec(&parser.object.functions, reader, gpa)) |*func| { func.* = .{ .type_index = try readLeb(u32, reader) }; } - try assertEnd(reader); + try assertEnd(&limited_reader); }, .table => { for (try readVec(&parser.object.tables, reader, gpa)) |*table| { @@ -458,13 +458,13 @@ fn Parser(comptime ReaderType: type) type { .limits = try readLimits(reader), }; } - try assertEnd(reader); + try assertEnd(&limited_reader); }, .memory => { for (try readVec(&parser.object.memories, reader, gpa)) |*memory| { memory.* = .{ .limits = try readLimits(reader) }; } - try assertEnd(reader); + try assertEnd(&limited_reader); }, .global => { for (try readVec(&parser.object.globals, reader, gpa)) |*global| { @@ -476,7 +476,7 @@ fn Parser(comptime ReaderType: type) type { .init = try readInit(reader), }; } - try assertEnd(reader); + try assertEnd(&limited_reader); }, .@"export" => { for (try readVec(&parser.object.exports, reader, gpa)) |*exp| { @@ -490,11 +490,11 @@ fn Parser(comptime ReaderType: type) type { .index = try readLeb(u32, reader), }; } - try assertEnd(reader); + try assertEnd(&limited_reader); }, .start => { parser.object.start = try readLeb(u32, reader); - try assertEnd(reader); + try assertEnd(&limited_reader); }, .element => { for (try readVec(&parser.object.elements, reader, gpa)) |*elem| { @@ -505,15 +505,15 @@ fn Parser(comptime ReaderType: type) type { idx.* = try readLeb(u32, reader); } } - try assertEnd(reader); + try assertEnd(&limited_reader); }, .code => { - var start = reader.context.bytes_left; + var start = limited_reader.bytes_left; var index: u32 = 0; const count = try readLeb(u32, reader); while (index < count) : (index += 1) { const code_len = try readLeb(u32, reader); - const offset = @intCast(u32, start - reader.context.bytes_left); + const offset = @intCast(u32, start - limited_reader.bytes_left); const data = try gpa.alloc(u8, code_len); errdefer gpa.free(data); try reader.readNoEof(data); @@ -528,7 +528,7 @@ fn Parser(comptime ReaderType: type) type { } }, .data => { - var start = reader.context.bytes_left; + var start = limited_reader.bytes_left; var index: u32 = 0; const count = try readLeb(u32, reader); while (index < count) : (index += 1) { @@ -537,7 +537,7 @@ fn Parser(comptime ReaderType: type) type { _ = flags; // TODO: Do we need to check flags to detect passive/active memory? _ = data_offset; const data_len = try readLeb(u32, reader); - const offset = @intCast(u32, start - reader.context.bytes_left); + const offset = @intCast(u32, start - limited_reader.bytes_left); const data = try gpa.alloc(u8, data_len); errdefer gpa.free(data); try reader.readNoEof(data); @@ -864,11 +864,12 @@ fn readInit(reader: anytype) !std.wasm.InitExpression { return init_expr; } -fn assertEnd(reader: anytype) !void { +fn assertEnd(limited_reader: anytype) !void { var buf: [1]u8 = undefined; + const reader = limited_reader.reader(); const len = try reader.read(&buf); if (len != 0) return error.MalformedSection; - if (reader.context.bytes_left != 0) return error.MalformedSection; + if (limited_reader.bytes_left != 0) return error.MalformedSection; } /// Parses an object file into atoms, for code and data sections