From 1e2aab2f97843572138076b21e2efb568e060a33 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Jun 2025 21:52:38 -0700 Subject: [PATCH] std: combine BufferedWriter into Writer --- lib/compiler/aro/aro/Diagnostics.zig | 6 +- lib/compiler/build_runner.zig | 17 +- lib/docs/wasm/main.zig | 3 +- lib/docs/wasm/markdown/Document.zig | 3 +- lib/docs/wasm/markdown/Render.zig | 18 +- lib/std/Build/Cache.zig | 5 +- lib/std/Build/Cache/Directory.zig | 10 +- lib/std/Build/Cache/Path.zig | 24 +- lib/std/Build/Step/CheckObject.zig | 83 +- lib/std/Build/Step/ConfigHeader.zig | 15 +- lib/std/Build/Step/Run.zig | 18 +- lib/std/Progress.zig | 7 +- lib/std/SemanticVersion.zig | 2 +- lib/std/Target.zig | 2 +- lib/std/Uri.zig | 14 +- lib/std/array_list.zig | 12 +- lib/std/builtin.zig | 2 +- lib/std/compress/flate.zig | 63 +- lib/std/compress/flate/BlockWriter.zig | 27 +- lib/std/compress/flate/Compress.zig | 31 +- lib/std/compress/flate/Decompress.zig | 25 +- lib/std/compress/lzma.zig | 23 +- lib/std/compress/lzma2.zig | 12 +- lib/std/compress/zstd/Decompress.zig | 11 +- lib/std/crypto/Sha1.zig | 20 +- lib/std/crypto/codecs/asn1.zig | 5 +- lib/std/crypto/codecs/asn1/Oid.zig | 11 +- lib/std/crypto/ecdsa.zig | 4 +- lib/std/crypto/phc_encoding.zig | 12 +- lib/std/crypto/scrypt.zig | 19 +- lib/std/crypto/sha2.zig | 7 +- lib/std/crypto/tls/Client.zig | 10 +- lib/std/debug.zig | 36 +- lib/std/debug/Dwarf/expression.zig | 55 +- lib/std/debug/FixedBufferReader.zig | 3 +- lib/std/fmt.zig | 22 +- lib/std/fs/File.zig | 53 +- lib/std/fs/path.zig | 4 +- lib/std/hash/crc.zig | 18 +- lib/std/http.zig | 199 +-- lib/std/http/Client.zig | 29 +- lib/std/http/Server.zig | 21 +- lib/std/io.zig | 3 - lib/std/io/AllocatingWriter.zig | 215 --- lib/std/io/BufferedWriter.zig | 1859 ---------------------- lib/std/io/Reader.zig | 9 +- lib/std/io/Reader/Limited.zig | 6 +- lib/std/io/Writer.zig | 1988 ++++++++++++++++++++++-- lib/std/io/tty.zig | 4 +- lib/std/json.zig | 4 +- lib/std/json/Stringify.zig | 29 +- lib/std/json/dynamic_test.zig | 7 +- lib/std/leb128.zig | 6 +- lib/std/math/big/int.zig | 2 +- lib/std/net.zig | 2 +- lib/std/tar.zig | 30 +- lib/std/tar/Writer.zig | 16 +- lib/std/testing.zig | 7 +- lib/std/tz.zig | 9 +- lib/std/zig.zig | 23 +- lib/std/zig/Ast.zig | 23 +- lib/std/zig/Ast/Render.zig | 11 +- lib/std/zig/ErrorBundle.zig | 19 +- lib/std/zig/Server.zig | 5 +- lib/std/zig/WindowsSdk.zig | 12 +- lib/std/zig/ZonGen.zig | 5 +- lib/std/zig/llvm/Builder.zig | 73 +- lib/std/zig/string_literal.zig | 7 +- lib/std/zip.zig | 5 +- lib/std/zip/test.zig | 10 +- lib/std/zon/stringify.zig | 14 +- lib/ubsan_rt.zig | 2 +- src/Air.zig | 4 +- src/Air/Liveness.zig | 6 +- src/Air/print.zig | 90 +- src/Compilation.zig | 16 +- src/InternPool.zig | 2 +- src/Package/Fetch.zig | 14 +- src/Package/Fetch/git.zig | 16 +- src/Sema.zig | 8 +- src/Type.zig | 9 +- src/Zcu.zig | 8 +- src/arch/riscv64/CodeGen.zig | 20 +- src/arch/riscv64/Mir.zig | 2 +- src/arch/riscv64/bits.zig | 4 +- src/arch/wasm/CodeGen.zig | 1 + src/arch/wasm/Emit.zig | 13 +- src/arch/x86_64/CodeGen.zig | 21 +- src/arch/x86_64/Disassembler.zig | 6 +- src/arch/x86_64/Encoding.zig | 8 +- src/arch/x86_64/bits.zig | 8 +- src/arch/x86_64/encoder.zig | 13 +- src/codegen.zig | 9 +- src/codegen/c.zig | 135 +- src/codegen/c/Type.zig | 14 +- src/codegen/spirv/spec.zig | 3 +- src/fmt.zig | 37 +- src/link/Coff.zig | 78 +- src/link/Dwarf.zig | 46 +- src/link/Elf.zig | 36 +- src/link/Elf/Archive.zig | 9 +- src/link/Elf/Atom.zig | 48 +- src/link/Elf/AtomList.zig | 11 +- src/link/Elf/LinkerDefined.zig | 9 +- src/link/Elf/Merge.zig | 13 +- src/link/Elf/Object.zig | 23 +- src/link/Elf/SharedObject.zig | 7 +- src/link/Elf/Symbol.zig | 13 +- src/link/Elf/Thunk.zig | 11 +- src/link/Elf/ZigObject.zig | 7 +- src/link/Elf/eh_frame.zig | 19 +- src/link/Elf/file.zig | 6 +- src/link/Elf/gc.zig | 7 +- src/link/Elf/relocatable.zig | 15 +- src/link/Elf/relocation.zig | 7 +- src/link/Elf/synthetic_sections.zig | 42 +- src/link/MachO.zig | 41 +- src/link/MachO/Archive.zig | 13 +- src/link/MachO/Atom.zig | 25 +- src/link/MachO/DebugSymbols.zig | 4 +- src/link/MachO/Dylib.zig | 11 +- src/link/MachO/InternalObject.zig | 7 +- src/link/MachO/Object.zig | 32 +- src/link/MachO/Relocation.zig | 5 +- src/link/MachO/Symbol.zig | 7 +- src/link/MachO/Thunk.zig | 7 +- src/link/MachO/UnwindInfo.zig | 13 +- src/link/MachO/ZigObject.zig | 7 +- src/link/MachO/dead_strip.zig | 3 +- src/link/MachO/dyld_info/Rebase.zig | 23 +- src/link/MachO/dyld_info/Trie.zig | 12 +- src/link/MachO/dyld_info/bind.zig | 37 +- src/link/MachO/eh_frame.zig | 8 +- src/link/MachO/file.zig | 5 +- src/link/MachO/load_commands.zig | 11 +- src/link/MachO/relocatable.zig | 7 +- src/link/MachO/synthetic.zig | 33 +- src/link/Plan9.zig | 54 +- src/link/Wasm.zig | 10 +- src/link/Wasm/Flush.zig | 707 ++++----- src/link/riscv.zig | 13 +- src/link/table_section.zig | 3 +- src/print_env.zig | 9 +- src/print_targets.zig | 3 +- src/print_value.zig | 13 +- src/print_zir.zig | 214 +-- src/print_zoir.zig | 7 +- 147 files changed, 3567 insertions(+), 4017 deletions(-) delete mode 100644 lib/std/io/AllocatingWriter.zig delete mode 100644 lib/std/io/BufferedWriter.zig diff --git a/lib/compiler/aro/aro/Diagnostics.zig b/lib/compiler/aro/aro/Diagnostics.zig index eb3bb31ee8..15673ec526 100644 --- a/lib/compiler/aro/aro/Diagnostics.zig +++ b/lib/compiler/aro/aro/Diagnostics.zig @@ -535,13 +535,13 @@ fn tagKind(d: *Diagnostics, tag: Tag, langopts: LangOpts) Kind { } const MsgWriter = struct { - w: std.io.BufferedWriter(4096, std.fs.File.Writer), + w: *std.fs.File.Writer, config: std.io.tty.Config, - fn init(config: std.io.tty.Config) MsgWriter { + fn init(config: std.io.tty.Config, buffer: []u8) MsgWriter { std.debug.lockStdErr(); return .{ - .w = std.io.bufferedWriter(std.io.getStdErr().writer()), + .w = std.fs.stderr().writer(buffer), .config = config, }; } diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index d335801ae7..6db46ae5dc 100644 --- a/lib/compiler/build_runner.zig +++ b/lib/compiler/build_runner.zig @@ -12,6 +12,7 @@ const Watch = std.Build.Watch; const Fuzz = std.Build.Fuzz; const Allocator = std.mem.Allocator; const fatal = std.process.fatal; +const Writer = std.io.Writer; const runner = @This(); pub const root = @import("@build"); @@ -773,7 +774,7 @@ const PrintNode = struct { last: bool = false, }; -fn printPrefix(node: *PrintNode, stderr: *std.io.BufferedWriter, ttyconf: std.io.tty.Config) !void { +fn printPrefix(node: *PrintNode, stderr: *Writer, ttyconf: std.io.tty.Config) !void { const parent = node.parent orelse return; if (parent.parent == null) return; try printPrefix(parent, stderr, ttyconf); @@ -787,7 +788,7 @@ fn printPrefix(node: *PrintNode, stderr: *std.io.BufferedWriter, ttyconf: std.io } } -fn printChildNodePrefix(stderr: *std.io.BufferedWriter, ttyconf: std.io.tty.Config) !void { +fn printChildNodePrefix(stderr: *Writer, ttyconf: std.io.tty.Config) !void { try stderr.writeAll(switch (ttyconf) { .no_color, .windows_api => "+- ", .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─ @@ -796,7 +797,7 @@ fn printChildNodePrefix(stderr: *std.io.BufferedWriter, ttyconf: std.io.tty.Conf fn printStepStatus( s: *Step, - stderr: *std.io.BufferedWriter, + stderr: *Writer, ttyconf: std.io.tty.Config, run: *const Run, ) !void { @@ -876,7 +877,7 @@ fn printStepStatus( fn printStepFailure( s: *Step, - stderr: *std.io.BufferedWriter, + stderr: *Writer, ttyconf: std.io.tty.Config, ) !void { if (s.result_error_bundle.errorMessageCount() > 0) { @@ -930,7 +931,7 @@ fn printTreeStep( b: *std.Build, s: *Step, run: *const Run, - stderr: *std.io.BufferedWriter, + stderr: *Writer, ttyconf: std.io.tty.Config, parent_node: *PrintNode, step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void), @@ -1188,7 +1189,7 @@ pub fn printErrorMessages( gpa: Allocator, failing_step: *Step, options: std.zig.ErrorBundle.RenderOptions, - stderr: *std.io.BufferedWriter, + stderr: *Writer, prominent_compile_errors: bool, ) !void { // Provide context for where these error messages are coming from by @@ -1241,7 +1242,7 @@ pub fn printErrorMessages( } } -fn steps(builder: *std.Build, bw: *std.io.BufferedWriter) !void { +fn steps(builder: *std.Build, bw: *Writer) !void { const allocator = builder.allocator; for (builder.top_level_steps.values()) |top_level_step| { const name = if (&top_level_step.step == builder.default_step) @@ -1254,7 +1255,7 @@ fn steps(builder: *std.Build, bw: *std.io.BufferedWriter) !void { var stdio_buffer: [256]u8 = undefined; -fn usage(b: *std.Build, bw: *std.io.BufferedWriter) !void { +fn usage(b: *std.Build, bw: *Writer) !void { try bw.print( \\Usage: {s} build [steps] [options] \\ diff --git a/lib/docs/wasm/main.zig b/lib/docs/wasm/main.zig index 614f989c58..a74bacd370 100644 --- a/lib/docs/wasm/main.zig +++ b/lib/docs/wasm/main.zig @@ -5,6 +5,7 @@ const Ast = std.zig.Ast; const Walk = @import("Walk"); const markdown = @import("markdown.zig"); const Decl = Walk.Decl; +const Writer = std.io.Writer; const fileSourceHtml = @import("html_render.zig").fileSourceHtml; const appendEscaped = @import("html_render.zig").appendEscaped; @@ -702,7 +703,7 @@ fn render_docs( r: markdown.Render, doc: markdown.Document, node: markdown.Document.Node.Index, - writer: *std.io.BufferedWriter, + writer: *Writer, ) !void { const decl_index_ptr: *const Decl.Index = @alignCast(@ptrCast(r.context)); const data = doc.nodes.items(.data)[@intFromEnum(node)]; diff --git a/lib/docs/wasm/markdown/Document.zig b/lib/docs/wasm/markdown/Document.zig index 2e678b1a12..d2cdbc5660 100644 --- a/lib/docs/wasm/markdown/Document.zig +++ b/lib/docs/wasm/markdown/Document.zig @@ -5,6 +5,7 @@ const builtin = @import("builtin"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const Render = @import("Render.zig"); +const Writer = std.io.Writer; nodes: Node.List.Slice, extra: []u32, @@ -160,7 +161,7 @@ pub fn deinit(doc: *Document, allocator: Allocator) void { } /// Renders a document directly to a writer using the default renderer. -pub fn render(doc: Document, writer: *std.io.BufferedWriter) @TypeOf(writer).Error!void { +pub fn render(doc: Document, writer: *Writer) Writer.Error!void { const renderer: Render(@TypeOf(writer), void) = .{ .context = {} }; try renderer.render(doc, writer); } diff --git a/lib/docs/wasm/markdown/Render.zig b/lib/docs/wasm/markdown/Render.zig index d5ff93e785..23689e8a6a 100644 --- a/lib/docs/wasm/markdown/Render.zig +++ b/lib/docs/wasm/markdown/Render.zig @@ -5,6 +5,8 @@ //! for node types for which they require no special rendering. const std = @import("std"); +const Writer = std.io.Writer; + const Document = @import("Document.zig"); const Node = Document.Node; const Render = @This(); @@ -14,10 +16,10 @@ renderFn: *const fn ( r: Render, doc: Document, node: Node.Index, - writer: *std.io.BufferedWriter, -) std.io.Writer.Error!void = renderDefault, + writer: *Writer, +) Writer.Error!void = renderDefault, -pub fn render(r: Render, doc: Document, writer: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn render(r: Render, doc: Document, writer: *Writer) Writer.Error!void { try r.renderFn(r, doc, .root, writer); } @@ -25,8 +27,8 @@ pub fn renderDefault( r: Render, doc: Document, node: Node.Index, - writer: *std.io.BufferedWriter, -) std.io.Writer.Error!void { + writer: *Writer, +) Writer.Error!void { const data = doc.nodes.items(.data)[@intFromEnum(node)]; switch (doc.nodes.items(.tag)[@intFromEnum(node)]) { .root => { @@ -183,8 +185,8 @@ pub fn renderDefault( pub fn renderInlineNodeText( doc: Document, node: Node.Index, - writer: *std.io.BufferedWriter, -) std.io.Writer.Error!void { + writer: *Writer, +) Writer.Error!void { const data = doc.nodes.items(.data)[@intFromEnum(node)]; switch (doc.nodes.items(.tag)[@intFromEnum(node)]) { .root, @@ -229,7 +231,7 @@ pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter(formatHtml) { return .{ .data = bytes }; } -fn formatHtml(bytes: []const u8, writer: *std.io.BufferedWriter, comptime fmt: []const u8) !void { +fn formatHtml(bytes: []const u8, writer: *Writer, comptime fmt: []const u8) !void { _ = fmt; for (bytes) |b| { switch (b) { diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 5b92be0eef..61c57344e5 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -286,9 +286,8 @@ pub const HashHelper = struct { pub fn binToHex(bin_digest: BinDigest) HexDigest { var out_digest: HexDigest = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&out_digest); - bw.printHex(&bin_digest, .lower) catch unreachable; + var w: std.io.Writer = .fixed(&out_digest); + w.printHex(&bin_digest, .lower) catch unreachable; return out_digest; } diff --git a/lib/std/Build/Cache/Directory.zig b/lib/std/Build/Cache/Directory.zig index a35b4fe78f..96931ee55b 100644 --- a/lib/std/Build/Cache/Directory.zig +++ b/lib/std/Build/Cache/Directory.zig @@ -55,15 +55,11 @@ pub fn closeAndFree(self: *Directory, gpa: Allocator) void { self.* = undefined; } -pub fn format( - self: Directory, - bw: *std.io.BufferedWriter, - comptime fmt_string: []const u8, -) !void { +pub fn format(self: Directory, w: *std.io.Writer, comptime fmt_string: []const u8) !void { if (fmt_string.len != 0) fmt.invalidFmtError(fmt_string, self); if (self.path) |p| { - try bw.writeAll(p); - try bw.writeAll(fs.path.sep_str); + try w.writeAll(p); + try w.writeAll(fs.path.sep_str); } } diff --git a/lib/std/Build/Cache/Path.zig b/lib/std/Build/Cache/Path.zig index 98d5884e9d..5f9c1409a3 100644 --- a/lib/std/Build/Cache/Path.zig +++ b/lib/std/Build/Cache/Path.zig @@ -140,11 +140,7 @@ pub fn toStringZ(p: Path, allocator: Allocator) Allocator.Error![:0]u8 { return std.fmt.allocPrintZ(allocator, "{f}", .{p}); } -pub fn format( - self: Path, - bw: *std.io.BufferedWriter, - comptime fmt_string: []const u8, -) !void { +pub fn format(self: Path, w: *std.io.Writer, comptime fmt_string: []const u8) !void { if (fmt_string.len == 1) { // Quote-escape the string. const stringEscape = std.zig.stringEscape; @@ -154,33 +150,33 @@ pub fn format( else => @compileError("unsupported format string: " ++ fmt_string), }; if (self.root_dir.path) |p| { - try stringEscape(p, bw, f); - if (self.sub_path.len > 0) try stringEscape(fs.path.sep_str, bw, f); + try stringEscape(p, w, f); + if (self.sub_path.len > 0) try stringEscape(fs.path.sep_str, w, f); } if (self.sub_path.len > 0) { - try stringEscape(self.sub_path, bw, f); + try stringEscape(self.sub_path, w, f); } return; } if (fmt_string.len > 0) std.fmt.invalidFmtError(fmt_string, self); if (std.fs.path.isAbsolute(self.sub_path)) { - try bw.writeAll(self.sub_path); + try w.writeAll(self.sub_path); return; } if (self.root_dir.path) |p| { - try bw.writeAll(p); + try w.writeAll(p); if (self.sub_path.len > 0) { - try bw.writeAll(fs.path.sep_str); - try bw.writeAll(self.sub_path); + try w.writeAll(fs.path.sep_str); + try w.writeAll(self.sub_path); } return; } if (self.sub_path.len > 0) { - try bw.writeAll(self.sub_path); + try w.writeAll(self.sub_path); return; } - try bw.writeByte('.'); + try w.writeByte('.'); } pub fn eql(self: Path, other: Path) bool { diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index 3bc03d0d0e..eae349dd0a 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -6,6 +6,7 @@ const macho = std.macho; const math = std.math; const mem = std.mem; const testing = std.testing; +const Writer = std.io.Writer; const CheckObject = @This(); @@ -231,7 +232,7 @@ const ComputeCompareExpected = struct { pub fn format( value: ComputeCompareExpected, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime fmt: []const u8, ) !void { if (fmt.len != 0) std.fmt.invalidFmtError(fmt, value); @@ -619,7 +620,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { fn formatMessageString( ctx: Ctx, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -813,7 +814,7 @@ const MachODumper = struct { return null; } - fn dumpHeader(hdr: macho.mach_header_64, bw: *std.io.BufferedWriter) !void { + fn dumpHeader(hdr: macho.mach_header_64, bw: *Writer) !void { const cputype = switch (hdr.cputype) { macho.CPU_TYPE_ARM64 => "ARM64", macho.CPU_TYPE_X86_64 => "X86_64", @@ -881,7 +882,7 @@ const MachODumper = struct { try bw.writeByte('\n'); } - fn dumpLoadCommand(lc: macho.LoadCommandIterator.LoadCommand, index: usize, bw: *std.io.BufferedWriter) !void { + fn dumpLoadCommand(lc: macho.LoadCommandIterator.LoadCommand, index: usize, bw: *Writer) !void { // print header first try bw.print( \\LC {d} @@ -1107,7 +1108,7 @@ const MachODumper = struct { } } - fn dumpSymtab(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { + fn dumpSymtab(ctx: ObjectContext, bw: *Writer) !void { try bw.writeAll(symtab_label ++ "\n"); for (ctx.symtab.items) |sym| { @@ -1178,7 +1179,7 @@ const MachODumper = struct { } } - fn dumpIndirectSymtab(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { + fn dumpIndirectSymtab(ctx: ObjectContext, bw: *Writer) !void { try bw.writeAll(indirect_symtab_label ++ "\n"); var sects_buffer: [3]macho.section_64 = undefined; @@ -1227,7 +1228,7 @@ const MachODumper = struct { } } - fn dumpRebaseInfo(ctx: ObjectContext, data: []const u8, bw: *std.io.BufferedWriter) !void { + fn dumpRebaseInfo(ctx: ObjectContext, data: []const u8, bw: *Writer) !void { var rebases: std.ArrayList(u64) = .init(ctx.gpa); defer rebases.deinit(); try ctx.parseRebaseInfo(data, &rebases); @@ -1324,7 +1325,7 @@ const MachODumper = struct { }; }; - fn dumpBindInfo(ctx: ObjectContext, data: []const u8, bw: *std.io.BufferedWriter) !void { + fn dumpBindInfo(ctx: ObjectContext, data: []const u8, bw: *Writer) !void { var bindings: std.ArrayList(Binding) = .init(ctx.gpa); defer { for (bindings.items) |*b| { @@ -1348,8 +1349,7 @@ const MachODumper = struct { } fn parseBindInfo(ctx: ObjectContext, data: []const u8, bindings: *std.ArrayList(Binding)) !void { - var br: std.io.Reader = undefined; - br.initFixed(@constCast(data)); + var br: std.io.Reader = .fixed(data); var seg_id: ?u8 = null; var tag: Binding.Tag = .self; @@ -1439,15 +1439,14 @@ const MachODumper = struct { } else |_| {} } - fn dumpExportsTrie(ctx: ObjectContext, data: []const u8, bw: *std.io.BufferedWriter) !void { + fn dumpExportsTrie(ctx: ObjectContext, data: []const u8, bw: *Writer) !void { const seg = ctx.getSegmentByName("__TEXT") orelse return; var arena = std.heap.ArenaAllocator.init(ctx.gpa); defer arena.deinit(); var exports: std.ArrayList(Export) = .init(arena.allocator()); - var br: std.io.Reader = undefined; - br.initFixed(@constCast(data)); + var br: std.io.Reader = .fixed(data); try parseTrieNode(arena.allocator(), &br, "", &exports); mem.sort(Export, exports.items, {}, Export.lessThan); @@ -1577,7 +1576,7 @@ const MachODumper = struct { } } - fn dumpSection(ctx: ObjectContext, sect: macho.section_64, bw: *std.io.BufferedWriter) !void { + fn dumpSection(ctx: ObjectContext, sect: macho.section_64, bw: *Writer) !void { const data = ctx.data[sect.offset..][0..sect.size]; try bw.print("{s}", .{data}); } @@ -1704,8 +1703,7 @@ const ElfDumper = struct { fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; - var br: std.io.Reader = undefined; - br.initFixed(@constCast(bytes)); + var br: std.io.Reader = .fixed(bytes); if (!mem.eql(u8, try br.takeArray(elf.ARMAG.len), elf.ARMAG)) return error.InvalidArchiveMagicNumber; @@ -1779,8 +1777,7 @@ const ElfDumper = struct { } fn parseSymtab(ctx: *ArchiveContext, data: []const u8, ptr_width: enum { p32, p64 }) !void { - var br: std.io.Reader = undefined; - br.initFixed(@constCast(data)); + var br: std.io.Reader = .fixed(data); const num = switch (ptr_width) { .p32 => try br.takeInt(u32, .big), .p64 => try br.takeInt(u64, .big), @@ -1807,7 +1804,7 @@ const ElfDumper = struct { } } - fn dumpSymtab(ctx: ArchiveContext, bw: *std.io.BufferedWriter) !void { + fn dumpSymtab(ctx: ArchiveContext, bw: *Writer) !void { var symbols: std.AutoArrayHashMap(usize, std.ArrayList([]const u8)) = .init(ctx.gpa); defer { for (symbols.values()) |*value| value.deinit(); @@ -1827,7 +1824,7 @@ const ElfDumper = struct { } } - fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, bw: *std.io.BufferedWriter) !void { + fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, bw: *Writer) !void { for (ctx.objects.values()) |object| { try bw.print("object {s}\n", .{object.name}); const output = try parseAndDumpObject(step, check, object.data); @@ -1850,8 +1847,7 @@ const ElfDumper = struct { fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; - var br: std.io.Reader = undefined; - br.initFixed(@constCast(bytes)); + var br: std.io.Reader = .fixed(bytes); const hdr = try br.takeStruct(elf.Elf64_Ehdr); if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) return error.InvalidMagicNumber; @@ -1944,13 +1940,13 @@ const ElfDumper = struct { symtab: Symtab, dysymtab: Symtab, - fn dumpHeader(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { + fn dumpHeader(ctx: ObjectContext, bw: *Writer) !void { try bw.writeAll("header\n"); try bw.print("type {s}\n", .{@tagName(ctx.hdr.e_type)}); try bw.print("entry {x}\n", .{ctx.hdr.e_entry}); } - fn dumpPhdrs(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { + fn dumpPhdrs(ctx: ObjectContext, bw: *Writer) !void { if (ctx.phdrs.len == 0) return; try bw.writeAll("program headers\n"); @@ -1989,7 +1985,7 @@ const ElfDumper = struct { } } - fn dumpShdrs(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { + fn dumpShdrs(ctx: ObjectContext, bw: *Writer) !void { if (ctx.shdrs.len == 0) return; try bw.writeAll("section headers\n"); @@ -2006,7 +2002,7 @@ const ElfDumper = struct { } } - fn dumpDynamicSection(ctx: ObjectContext, shndx: usize, bw: *std.io.BufferedWriter) !void { + fn dumpDynamicSection(ctx: ObjectContext, shndx: usize, bw: *Writer) !void { const shdr = ctx.shdrs[shndx]; const strtab = ctx.getSectionContents(shdr.sh_link); const data = ctx.getSectionContents(shndx); @@ -2144,7 +2140,7 @@ const ElfDumper = struct { } } - fn dumpSymtab(ctx: ObjectContext, comptime @"type": enum { symtab, dysymtab }, bw: *std.io.BufferedWriter) !void { + fn dumpSymtab(ctx: ObjectContext, comptime @"type": enum { symtab, dysymtab }, bw: *Writer) !void { const symtab = switch (@"type") { .symtab => ctx.symtab, .dysymtab => ctx.dysymtab, @@ -2226,7 +2222,7 @@ const ElfDumper = struct { } } - fn dumpSection(ctx: ObjectContext, shndx: usize, bw: *std.io.BufferedWriter) !void { + fn dumpSection(ctx: ObjectContext, shndx: usize, bw: *Writer) !void { const data = ctx.getSectionContents(shndx); try bw.print("{s}", .{data}); } @@ -2276,7 +2272,7 @@ const ElfDumper = struct { fn formatShType( sh_type: u32, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -2321,7 +2317,7 @@ const ElfDumper = struct { fn formatPhType( ph_type: u32, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -2353,8 +2349,7 @@ const WasmDumper = struct { fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; - var br: std.io.Reader = undefined; - br.initFixed(@constCast(bytes)); + var br: std.io.Reader = .fixed(bytes); const buf = try br.takeArray(8); if (!mem.eql(u8, buf[0..4], &std.wasm.magic)) return error.InvalidMagicByte; @@ -2376,12 +2371,12 @@ const WasmDumper = struct { step: *Step, check: Check, br: *std.io.Reader, - bw: *std.io.BufferedWriter, + bw: *Writer, ) !void { var section_br: std.io.Reader = undefined; switch (check.kind) { .headers => while (br.takeEnum(std.wasm.Section, .little)) |section| { - section_br.initFixed(try br.take(try br.takeLeb128(u32))); + section_br = .fixed(try br.take(try br.takeLeb128(u32))); try parseAndDumpSection(step, section, §ion_br, bw); } else |err| switch (err) { error.InvalidEnumTag => return step.fail("invalid section id", .{}), @@ -2396,7 +2391,7 @@ const WasmDumper = struct { step: *Step, section: std.wasm.Section, br: *std.io.Reader, - bw: *std.io.BufferedWriter, + bw: *Writer, ) !void { try bw.print( \\Section {s} @@ -2444,7 +2439,7 @@ const WasmDumper = struct { } } - fn parseSection(step: *Step, section: std.wasm.Section, br: *std.io.Reader, entries: u32, bw: *std.io.BufferedWriter) !void { + fn parseSection(step: *Step, section: std.wasm.Section, br: *std.io.Reader, entries: u32, bw: *Writer) !void { switch (section) { .type => { var i: u32 = 0; @@ -2575,7 +2570,7 @@ const WasmDumper = struct { } } - fn parseDumpType(step: *Step, comptime E: type, br: *std.io.Reader, bw: *std.io.BufferedWriter) !E { + fn parseDumpType(step: *Step, comptime E: type, br: *std.io.Reader, bw: *Writer) !E { const tag = br.takeEnum(E, .little) catch |err| switch (err) { error.InvalidEnumTag => return step.fail("invalid wasm type value", .{}), else => |e| return e, @@ -2584,7 +2579,7 @@ const WasmDumper = struct { return tag; } - fn parseDumpLimits(br: *std.io.Reader, bw: *std.io.BufferedWriter) !void { + fn parseDumpLimits(br: *std.io.Reader, bw: *Writer) !void { const flags = try br.takeLeb128(u8); const min = try br.takeLeb128(u32); @@ -2592,7 +2587,7 @@ const WasmDumper = struct { if (flags != 0) try bw.print("max {x}\n", .{try br.takeLeb128(u32)}); } - fn parseDumpInit(step: *Step, br: *std.io.Reader, bw: *std.io.BufferedWriter) !void { + fn parseDumpInit(step: *Step, br: *std.io.Reader, bw: *Writer) !void { const opcode = br.takeEnum(std.wasm.Opcode, .little) catch |err| switch (err) { error.InvalidEnumTag => return step.fail("invalid wasm opcode", .{}), else => |e| return e, @@ -2612,14 +2607,14 @@ const WasmDumper = struct { } /// https://webassembly.github.io/spec/core/appendix/custom.html - fn parseDumpNames(step: *Step, br: *std.io.Reader, bw: *std.io.BufferedWriter) !void { + fn parseDumpNames(step: *Step, br: *std.io.Reader, bw: *Writer) !void { var subsection_br: std.io.Reader = undefined; while (br.seek < br.buffer.len) { switch (try parseDumpType(step, std.wasm.NameSubsection, br, bw)) { // The module name subsection ... consists of a single name // that is assigned to the module itself. .module => { - subsection_br.initFixed(try br.take(try br.takeLeb128(u32))); + subsection_br = .fixed(try br.take(try br.takeLeb128(u32))); const name = try subsection_br.take(try subsection_br.takeLeb128(u32)); try bw.print( \\name {s} @@ -2631,7 +2626,7 @@ const WasmDumper = struct { // The function name subsection ... consists of a name map // assigning function names to function indices. .function, .global, .data_segment => { - subsection_br.initFixed(try br.take(try br.takeLeb128(u32))); + subsection_br = .fixed(try br.take(try br.takeLeb128(u32))); const entries = try br.takeLeb128(u32); try bw.print( \\names {d} @@ -2661,7 +2656,7 @@ const WasmDumper = struct { } } - fn parseDumpProducers(br: *std.io.Reader, bw: *std.io.BufferedWriter) !void { + fn parseDumpProducers(br: *std.io.Reader, bw: *Writer) !void { const field_count = try br.takeLeb128(u32); try bw.print( \\fields {d} @@ -2689,7 +2684,7 @@ const WasmDumper = struct { } } - fn parseDumpFeatures(br: *std.io.Reader, bw: *std.io.BufferedWriter) !void { + fn parseDumpFeatures(br: *std.io.Reader, bw: *Writer) !void { const feature_count = try br.takeLeb128(u32); try bw.print( \\features {d} diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index e1ffb6ae1d..6ba6a5694f 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -2,6 +2,7 @@ const std = @import("std"); const ConfigHeader = @This(); const Step = std.Build.Step; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; pub const Style = union(enum) { /// A configure format supported by autotools that uses `#undef foo` to @@ -277,7 +278,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { fn render_autoconf_undef( step: *Step, contents: []const u8, - bw: *std.io.BufferedWriter, + bw: *Writer, values: std.StringArrayHashMap(Value), src_path: []const u8, ) !void { @@ -382,7 +383,7 @@ fn render_autoconf_at( fn render_cmake( step: *Step, contents: []const u8, - bw: *std.io.BufferedWriter, + bw: *Writer, values: std.StringArrayHashMap(Value), src_path: []const u8, ) !void { @@ -508,7 +509,7 @@ fn render_cmake( fn render_blank( gpa: std.mem.Allocator, - bw: *std.io.BufferedWriter, + bw: *Writer, defines: std.StringArrayHashMap(Value), include_path: []const u8, include_guard_override: ?[]const u8, @@ -541,11 +542,11 @@ fn render_blank( , .{include_guard_name}); } -fn render_nasm(bw: *std.io.BufferedWriter, defines: std.StringArrayHashMap(Value)) !void { +fn render_nasm(bw: *Writer, defines: std.StringArrayHashMap(Value)) !void { for (defines.keys(), defines.values()) |name, value| try renderValueNasm(bw, name, value); } -fn renderValueC(bw: *std.io.BufferedWriter, name: []const u8, value: Value) !void { +fn renderValueC(bw: *Writer, name: []const u8, value: Value) !void { switch (value) { .undef => try bw.print("/* #undef {s} */\n", .{name}), .defined => try bw.print("#define {s}\n", .{name}), @@ -557,7 +558,7 @@ fn renderValueC(bw: *std.io.BufferedWriter, name: []const u8, value: Value) !voi } } -fn renderValueNasm(bw: *std.io.BufferedWriter, name: []const u8, value: Value) !void { +fn renderValueNasm(bw: *Writer, name: []const u8, value: Value) !void { switch (value) { .undef => try bw.print("; %undef {s}\n", .{name}), .defined => try bw.print("%define {s}\n", .{name}), @@ -570,7 +571,7 @@ fn renderValueNasm(bw: *std.io.BufferedWriter, name: []const u8, value: Value) ! } fn expand_variables_autoconf_at( - bw: *std.io.BufferedWriter, + bw: *Writer, contents: []const u8, values: std.StringArrayHashMap(Value), used: []bool, diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index ef954f77e8..5648e92458 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -1015,18 +1015,14 @@ fn populateGeneratedPaths( } } -fn formatTerm( - term: ?std.process.Child.Term, - bw: *std.io.BufferedWriter, - comptime fmt: []const u8, -) !void { - _ = fmt; +fn formatTerm(term: ?std.process.Child.Term, w: *std.io.Writer, comptime fmt: []const u8) !void { + comptime assert(fmt.len == 0); if (term) |t| switch (t) { - .Exited => |code| try bw.print("exited with code {}", .{code}), - .Signal => |sig| try bw.print("terminated with signal {}", .{sig}), - .Stopped => |sig| try bw.print("stopped with signal {}", .{sig}), - .Unknown => |code| try bw.print("terminated for unknown reason with code {}", .{code}), - } else try bw.writeAll("exited with any code"); + .Exited => |code| try w.print("exited with code {}", .{code}), + .Signal => |sig| try w.print("terminated with signal {}", .{sig}), + .Stopped => |sig| try w.print("stopped with signal {}", .{sig}), + .Unknown => |code| try w.print("terminated for unknown reason with code {}", .{code}), + } else try w.writeAll("exited with any code"); } fn fmtTerm(term: ?std.process.Child.Term) std.fmt.Formatter(formatTerm) { return .{ .data = term }; diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index 4d50e0aa04..963e1b2869 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -9,6 +9,7 @@ const Progress = @This(); const posix = std.posix; const is_big_endian = builtin.cpu.arch.endian() == .big; const is_windows = builtin.os.tag == .windows; +const Writer = std.io.Writer; /// `null` if the current node (and its children) should /// not print on update() @@ -607,7 +608,7 @@ pub fn unlockStdErr() void { } /// Protected by `stderr_mutex`. -var stderr_buffered_writer: std.io.BufferedWriter = .{ +var stderr_buffered_writer: Writer = .{ .unbuffered_writer = stderr_file_writer.interface(), .buffer = &.{}, }; @@ -617,13 +618,13 @@ var stderr_file_writer: std.fs.File.Writer = .{ .mode = .streaming, }; -/// Allows the caller to freely write to the returned `std.io.BufferedWriter`, +/// Allows the caller to freely write to the returned `Writer`, /// initialized with `buffer`, until `unlockStderrWriter` is called. /// /// During the lock, any `std.Progress` information is cleared from the terminal. /// /// The lock is recursive; the same thread may hold the lock multiple times. -pub fn lockStderrWriter(buffer: []u8) *std.io.BufferedWriter { +pub fn lockStderrWriter(buffer: []u8) *Writer { stderr_mutex.lock(); clearWrittenWithEscapeCodes() catch {}; if (is_windows) stderr_file_writer.file = .stderr(); diff --git a/lib/std/SemanticVersion.zig b/lib/std/SemanticVersion.zig index 82764b0f82..c1df140374 100644 --- a/lib/std/SemanticVersion.zig +++ b/lib/std/SemanticVersion.zig @@ -152,7 +152,7 @@ fn parseNum(text: []const u8) error{ InvalidVersion, Overflow }!usize { pub fn format( self: Version, - bw: *std.io.BufferedWriter, + bw: *std.io.Writer, comptime fmt: []const u8, ) !void { if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self); diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 7112b585c7..5b634ca99a 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -301,7 +301,7 @@ pub const Os = struct { /// This function is defined to serialize a Zig source code representation of this /// type, that, when parsed, will deserialize into the same data. - pub fn format(ver: WindowsVersion, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + pub fn format(ver: WindowsVersion, bw: *std.io.Writer, comptime fmt_str: []const u8) std.io.Writer.Error!void { const maybe_name = std.enums.tagName(WindowsVersion, ver); if (comptime std.mem.eql(u8, fmt_str, "s")) { if (maybe_name) |name| diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig index ae8484a15d..b3b82fbab1 100644 --- a/lib/std/Uri.zig +++ b/lib/std/Uri.zig @@ -5,6 +5,7 @@ const std = @import("std.zig"); const testing = std.testing; const Allocator = std.mem.Allocator; const assert = std.debug.assert; +const Writer = std.io.Writer; const Uri = @This(); @@ -84,7 +85,7 @@ pub const Component = union(enum) { }; } - pub fn format(component: Component, bw: *std.io.BufferedWriter, comptime fmt: []const u8) std.io.Writer.Error!void { + pub fn format(component: Component, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { if (fmt.len == 0) { try bw.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{ @tagName(component), @@ -136,10 +137,10 @@ pub const Component = union(enum) { } pub fn percentEncode( - bw: *std.io.BufferedWriter, + bw: *Writer, raw: []const u8, comptime isValidChar: fn (u8) bool, - ) std.io.Writer.Error!void { + ) Writer.Error!void { var start: usize = 0; for (raw, 0..) |char, index| { if (isValidChar(char)) continue; @@ -280,7 +281,7 @@ pub const WriteToStreamOptions = struct { port: bool = true, }; -pub fn writeToStream(uri: Uri, options: WriteToStreamOptions, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn writeToStream(uri: Uri, options: WriteToStreamOptions, bw: *Writer) Writer.Error!void { if (options.scheme) { try bw.print("{s}:", .{uri.scheme}); if (options.authority and uri.host != null) { @@ -317,7 +318,7 @@ pub fn writeToStream(uri: Uri, options: WriteToStreamOptions, bw: *std.io.Buffer } } -pub fn format(uri: Uri, bw: *std.io.BufferedWriter, comptime fmt: []const u8) std.io.Writer.Error!void { +pub fn format(uri: Uri, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { const scheme = comptime std.mem.indexOfScalar(u8, fmt, ';') != null or fmt.len == 0; const authentication = comptime std.mem.indexOfScalar(u8, fmt, '@') != null or fmt.len == 0; const authority = comptime std.mem.indexOfScalar(u8, fmt, '+') != null or fmt.len == 0; @@ -461,8 +462,7 @@ test remove_dot_segments { /// 5.2.3. Merge Paths fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Component { - var aux: std.io.BufferedWriter = undefined; - aux.initFixed(aux_buf.*); + var aux: Writer = .fixed(aux_buf.*); if (!base.isEmpty()) { aux.print("{fpath}", .{base}) catch return error.NoSpaceLeft; aux.end = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index 37c48c8480..c6731eb659 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -905,20 +905,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { comptime assert(T == u8); try self.ensureUnusedCapacity(gpa, fmt.len); - var aw: std.io.AllocatingWriter = undefined; - const bw = aw.fromArrayList(gpa, self); + var aw: std.io.AllocatingWriter = .fromArrayList(gpa, self); defer self.* = aw.toArrayList(); - return bw.print(fmt, args) catch |err| switch (err) { + return aw.interface.print(fmt, args) catch |err| switch (err) { error.WriteFailed => return error.OutOfMemory, }; } pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void { comptime assert(T == u8); - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(self.unusedCapacitySlice()); - bw.print(fmt, args) catch unreachable; - self.items.len += bw.end; + var w: std.io.Writer = .fixed(self.unusedCapacitySlice()); + w.print(fmt, args) catch unreachable; + self.items.len += w.end; } /// Append a value to the list `n` times. diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 53c3829640..2d8f1d1ed0 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -34,7 +34,7 @@ pub const StackTrace = struct { index: usize, instruction_addresses: []usize, - pub fn format(st: StackTrace, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { + pub fn format(st: StackTrace, bw: *std.io.Writer, comptime fmt: []const u8) !void { comptime if (fmt.len != 0) unreachable; // TODO: re-evaluate whether to use format() methods at all. diff --git a/lib/std/compress/flate.zig b/lib/std/compress/flate.zig index 2c66510f84..4725f67e4f 100644 --- a/lib/std/compress/flate.zig +++ b/lib/std/compress/flate.zig @@ -1,6 +1,7 @@ const builtin = @import("builtin"); const std = @import("../std.zig"); const testing = std.testing; +const Writer = std.io.Writer; /// Container of the deflate bit stream body. Container adds header before /// deflate bit stream and footer after. It can bi gzip, zlib or raw (no header, @@ -106,7 +107,7 @@ pub const Container = enum { } } - pub fn writeFooter(hasher: *Hasher, writer: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn writeFooter(hasher: *Hasher, writer: *Writer) Writer.Error!void { var bits: [4]u8 = undefined; switch (hasher.*) { .gzip => |*gzip| { @@ -230,8 +231,7 @@ test "compress/decompress" { // compress original stream to compressed stream { var original: std.io.Reader = .fixed(data); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&cmp_buf); + var compressed: Writer = .fixed(&cmp_buf); var compress: Compress = .init(&original, .raw); var compress_br = compress.readable(&.{}); const n = try compress_br.readRemaining(&compressed, .{ .level = level }); @@ -246,16 +246,14 @@ test "compress/decompress" { // decompress compressed stream to decompressed stream { var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]); - var decompressed: std.io.BufferedWriter = undefined; - decompressed.initFixed(&dcm_buf); + var decompressed: Writer = .fixed(&dcm_buf); try Decompress.pump(container, &compressed, &decompressed); try testing.expectEqualSlices(u8, data, decompressed.getWritten()); } // compressor writer interface { - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&cmp_buf); + var compressed: Writer = .fixed(&cmp_buf); var cmp = try Compress.init(container, &compressed, .{ .level = level }); var cmp_wrt = cmp.writer(); try cmp_wrt.writeAll(data); @@ -285,8 +283,7 @@ test "compress/decompress" { // compress original stream to compressed stream { var original: std.io.Reader = .fixed(data); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&cmp_buf); + var compressed: Writer = .fixed(&cmp_buf); var cmp = try Compress.Huffman.init(container, &compressed); try cmp.compress(original.reader()); try cmp.finish(); @@ -300,8 +297,7 @@ test "compress/decompress" { // decompress compressed stream to decompressed stream { var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]); - var decompressed: std.io.BufferedWriter = undefined; - decompressed.initFixed(&dcm_buf); + var decompressed: Writer = .fixed(&dcm_buf); try Decompress.pump(container, &compressed, &decompressed); try testing.expectEqualSlices(u8, data, decompressed.getWritten()); } @@ -319,8 +315,7 @@ test "compress/decompress" { // compress original stream to compressed stream { var original: std.io.Reader = .fixed(data); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&cmp_buf); + var compressed: Writer = .fixed(&cmp_buf); var cmp = try Compress.SimpleCompressor(.store, container).init(&compressed); try cmp.compress(original.reader()); try cmp.finish(); @@ -335,8 +330,7 @@ test "compress/decompress" { // decompress compressed stream to decompressed stream { var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]); - var decompressed: std.io.BufferedWriter = undefined; - decompressed.initFixed(&dcm_buf); + var decompressed: Writer = .fixed(&dcm_buf); try Decompress.pump(container, &compressed, &decompressed); try testing.expectEqualSlices(u8, data, decompressed.getWritten()); } @@ -491,8 +485,7 @@ fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const // decompress { - var plain: std.io.BufferedWriter = undefined; - plain.initFixed(&buffer2); + var plain: Writer = .fixed(&buffer2); var in: std.io.Reader = .fixed(gzip_data); try pkg.decompress(&in, &plain); @@ -501,10 +494,8 @@ fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const // compress/decompress { - var plain: std.io.BufferedWriter = undefined; - plain.initFixed(&buffer2); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&buffer1); + var plain: Writer = .fixed(&buffer2); + var compressed: Writer = .fixed(&buffer1); var in: std.io.Reader = .fixed(plain_data); try pkg.compress(&in, &compressed, .{}); @@ -516,10 +507,8 @@ fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const // compressor/decompressor { - var plain: std.io.BufferedWriter = undefined; - plain.initFixed(&buffer2); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&buffer1); + var plain: Writer = .fixed(&buffer2); + var compressed: Writer = .fixed(&buffer1); var in: std.io.Reader = .fixed(plain_data); var cmp = try pkg.compressor(&compressed, .{}); @@ -536,10 +525,8 @@ fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const { // huffman compress/decompress { - var plain: std.io.BufferedWriter = undefined; - plain.initFixed(&buffer2); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&buffer1); + var plain: Writer = .fixed(&buffer2); + var compressed: Writer = .fixed(&buffer1); var in: std.io.Reader = .fixed(plain_data); try pkg.huffman.compress(&in, &compressed); @@ -551,10 +538,8 @@ fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const // huffman compressor/decompressor { - var plain: std.io.BufferedWriter = undefined; - plain.initFixed(&buffer2); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&buffer1); + var plain: Writer = .fixed(&buffer2); + var compressed: Writer = .fixed(&buffer1); var in: std.io.Reader = .fixed(plain_data); var cmp = try pkg.huffman.compressor(&compressed); @@ -571,10 +556,8 @@ fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const { // store compress/decompress { - var plain: std.io.BufferedWriter = undefined; - plain.initFixed(&buffer2); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&buffer1); + var plain: Writer = .fixed(&buffer2); + var compressed: Writer = .fixed(&buffer1); var in: std.io.Reader = .fixed(plain_data); try pkg.store.compress(&in, &compressed); @@ -586,10 +569,8 @@ fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const // store compressor/decompressor { - var plain: std.io.BufferedWriter = undefined; - plain.initFixed(&buffer2); - var compressed: std.io.BufferedWriter = undefined; - compressed.initFixed(&buffer1); + var plain: Writer = .fixed(&buffer2); + var compressed: Writer = .fixed(&buffer1); var in: std.io.Reader = .fixed(plain_data); var cmp = try pkg.store.compressor(&compressed); diff --git a/lib/std/compress/flate/BlockWriter.zig b/lib/std/compress/flate/BlockWriter.zig index 21d56575e7..d1eb3a068e 100644 --- a/lib/std/compress/flate/BlockWriter.zig +++ b/lib/std/compress/flate/BlockWriter.zig @@ -3,6 +3,7 @@ const std = @import("std"); const io = std.io; const assert = std.debug.assert; +const Writer = std.io.Writer; const BlockWriter = @This(); const flate = @import("../flate.zig"); @@ -13,7 +14,7 @@ const Token = @import("Token.zig"); const codegen_order = huffman.codegen_order; const end_code_mark = 255; -output: *std.io.BufferedWriter, +output: *Writer, codegen_freq: [huffman.codegen_code_count]u16 = undefined, literal_freq: [huffman.max_num_lit]u16 = undefined, @@ -26,7 +27,7 @@ fixed_literal_encoding: Compress.LiteralEncoder, fixed_distance_encoding: Compress.DistanceEncoder, huff_distance: Compress.DistanceEncoder, -pub fn init(output: *std.io.BufferedWriter) BlockWriter { +pub fn init(output: *Writer) BlockWriter { return .{ .output = output, .fixed_literal_encoding = Compress.fixedLiteralEncoder(), @@ -41,15 +42,15 @@ pub fn init(output: *std.io.BufferedWriter) BlockWriter { /// That is after final block; when last byte could be incomplete or /// after stored block; which is aligned to the byte boundary (it has x /// padding bits after first 3 bits). -pub fn flush(self: *BlockWriter) std.io.Writer.Error!void { +pub fn flush(self: *BlockWriter) Writer.Error!void { try self.bit_writer.flush(); } -pub fn setWriter(self: *BlockWriter, new_writer: *std.io.BufferedWriter) void { +pub fn setWriter(self: *BlockWriter, new_writer: *Writer) void { self.bit_writer.setWriter(new_writer); } -fn writeCode(self: *BlockWriter, c: Compress.HuffCode) std.io.Writer.Error!void { +fn writeCode(self: *BlockWriter, c: Compress.HuffCode) Writer.Error!void { try self.bit_writer.writeBits(c.code, c.len); } @@ -231,7 +232,7 @@ fn dynamicHeader( num_distances: u32, num_codegens: u32, eof: bool, -) std.io.Writer.Error!void { +) Writer.Error!void { const first_bits: u32 = if (eof) 5 else 4; try self.bit_writer.writeBits(first_bits, 3); try self.bit_writer.writeBits(num_literals - 257, 5); @@ -271,7 +272,7 @@ fn dynamicHeader( } } -fn storedHeader(self: *BlockWriter, length: usize, eof: bool) std.io.Writer.Error!void { +fn storedHeader(self: *BlockWriter, length: usize, eof: bool) Writer.Error!void { assert(length <= 65535); const flag: u32 = if (eof) 1 else 0; try self.bit_writer.writeBits(flag, 3); @@ -281,7 +282,7 @@ fn storedHeader(self: *BlockWriter, length: usize, eof: bool) std.io.Writer.Erro try self.bit_writer.writeBits(~l, 16); } -fn fixedHeader(self: *BlockWriter, eof: bool) std.io.Writer.Error!void { +fn fixedHeader(self: *BlockWriter, eof: bool) Writer.Error!void { // Indicate that we are a fixed Huffman block var value: u32 = 2; if (eof) { @@ -295,7 +296,7 @@ fn fixedHeader(self: *BlockWriter, eof: bool) std.io.Writer.Error!void { // is larger than the original bytes, the data will be written as a // stored block. // If the input is null, the tokens will always be Huffman encoded. -pub fn write(self: *BlockWriter, tokens: []const Token, eof: bool, input: ?[]const u8) std.io.Writer.Error!void { +pub fn write(self: *BlockWriter, tokens: []const Token, eof: bool, input: ?[]const u8) Writer.Error!void { const lit_and_dist = self.indexTokens(tokens); const num_literals = lit_and_dist.num_literals; const num_distances = lit_and_dist.num_distances; @@ -373,7 +374,7 @@ pub fn write(self: *BlockWriter, tokens: []const Token, eof: bool, input: ?[]con try self.writeTokens(tokens, &literal_encoding.codes, &distance_encoding.codes); } -pub fn storedBlock(self: *BlockWriter, input: []const u8, eof: bool) std.io.Writer.Error!void { +pub fn storedBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Error!void { try self.storedHeader(input.len, eof); try self.bit_writer.writeBytes(input); } @@ -388,7 +389,7 @@ fn dynamicBlock( tokens: []const Token, eof: bool, input: ?[]const u8, -) std.io.Writer.Error!void { +) Writer.Error!void { const total_tokens = self.indexTokens(tokens); const num_literals = total_tokens.num_literals; const num_distances = total_tokens.num_distances; @@ -485,7 +486,7 @@ fn writeTokens( tokens: []const Token, le_codes: []Compress.HuffCode, oe_codes: []Compress.HuffCode, -) std.io.Writer.Error!void { +) Writer.Error!void { for (tokens) |t| { if (t.kind == Token.Kind.literal) { try self.writeCode(le_codes[t.literal()]); @@ -512,7 +513,7 @@ fn writeTokens( // Encodes a block of bytes as either Huffman encoded literals or uncompressed bytes // if the results only gains very little from compression. -pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) std.io.Writer.Error!void { +pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Error!void { // Add everything as literals histogram(input, &self.literal_freq); diff --git a/lib/std/compress/flate/Compress.zig b/lib/std/compress/flate/Compress.zig index 4f04e7582a..9a488c0d53 100644 --- a/lib/std/compress/flate/Compress.zig +++ b/lib/std/compress/flate/Compress.zig @@ -47,6 +47,7 @@ const testing = std.testing; const expect = testing.expect; const mem = std.mem; const math = std.math; +const Writer = std.io.Writer; const Compress = @This(); const Token = @import("Token.zig"); @@ -142,7 +143,7 @@ const FlushOption = enum { none, flush, final }; /// flush tokens to the token writer. /// /// Returns number of bytes consumed from `lh`. -fn tokenizeSlice(c: *Compress, bw: *std.io.BufferedWriter, limit: std.io.Limit, lh: []const u8) !usize { +fn tokenizeSlice(c: *Compress, bw: *Writer, limit: std.io.Limit, lh: []const u8) !usize { _ = bw; _ = limit; if (true) @panic("TODO"); @@ -299,7 +300,7 @@ pub fn finish(c: *Compress) !void { /// Use another writer while preserving history. Most probably flush /// should be called on old writer before setting new. -pub fn setWriter(self: *Compress, new_writer: *std.io.BufferedWriter) void { +pub fn setWriter(self: *Compress, new_writer: *Writer) void { self.block_writer.setWriter(new_writer); self.output = new_writer; } @@ -767,7 +768,7 @@ fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool { fn read( context: ?*anyopaque, - bw: *std.io.BufferedWriter, + bw: *Writer, limit: std.io.Limit, ) std.io.Reader.StreamError!usize { const c: *Compress = @ptrCast(@alignCast(context)); @@ -1147,8 +1148,7 @@ test "file tokenization" { const data = case.data; for (levels, 0..) |level, i| { // for each compression level - var original: std.io.Reader = undefined; - original.initFixed(data); + var original: std.io.Reader = .fixed(data); // buffer for decompressed data var al = std.ArrayList(u8).init(testing.allocator); @@ -1181,10 +1181,10 @@ test "file tokenization" { } const TokenDecoder = struct { - output: *std.io.BufferedWriter, + output: *Writer, tokens_count: usize, - pub fn init(output: *std.io.BufferedWriter) TokenDecoder { + pub fn init(output: *Writer) TokenDecoder { return .{ .output = output, .tokens_count = 0, @@ -1222,8 +1222,7 @@ test "store simple compressor" { //0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, }; - var fbs: std.io.Reader = undefined; - fbs.initFixed(data); + var fbs: std.io.Reader = .fixed(data); var al = std.ArrayList(u8).init(testing.allocator); defer al.deinit(); @@ -1232,7 +1231,7 @@ test "store simple compressor" { try cmp.finish(); try testing.expectEqualSlices(u8, &expected, al.items); - fbs.initFixed(data); + fbs = .fixed(data); try al.resize(0); // huffman only compresoor will also emit store block for this small sample @@ -1244,7 +1243,7 @@ test "store simple compressor" { test "sliding window match" { const data = "Blah blah blah blah blah!"; - var win: std.io.BufferedWriter = .{}; + var win: Writer = .{}; try expect(win.write(data) == data.len); try expect(win.wp == data.len); try expect(win.rp == 0); @@ -1263,9 +1262,9 @@ test "sliding window match" { } test "sliding window slide" { - var win: std.io.BufferedWriter = .{}; - win.wp = std.io.BufferedWriter.buffer_len - 11; - win.rp = std.io.BufferedWriter.buffer_len - 111; + var win: Writer = .{}; + win.wp = Writer.buffer_len - 11; + win.rp = Writer.buffer_len - 111; win.buffer[win.rp] = 0xab; try expect(win.lookahead().len == 100); try expect(win.tokensBuffer().?.len == win.rp); @@ -1273,8 +1272,8 @@ test "sliding window slide" { const n = win.slide(); try expect(n == 32757); try expect(win.buffer[win.rp] == 0xab); - try expect(win.rp == std.io.BufferedWriter.hist_len - 111); - try expect(win.wp == std.io.BufferedWriter.hist_len - 11); + try expect(win.rp == Writer.hist_len - 111); + try expect(win.wp == Writer.hist_len - 11); try expect(win.lookahead().len == 100); try expect(win.tokensBuffer() == null); } diff --git a/lib/std/compress/flate/Decompress.zig b/lib/std/compress/flate/Decompress.zig index 9ffc2b588f..496bea66c3 100644 --- a/lib/std/compress/flate/Decompress.zig +++ b/lib/std/compress/flate/Decompress.zig @@ -23,6 +23,7 @@ const Container = flate.Container; const Token = @import("Token.zig"); const testing = std.testing; const Decompress = @This(); +const Writer = std.io.Writer; input: *std.io.Reader, // Hashes, produces checksum, of uncompressed data for gzip/zlib footer. @@ -141,7 +142,7 @@ fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol { pub fn read( context: ?*anyopaque, - bw: *std.io.BufferedWriter, + bw: *Writer, limit: std.io.Limit, ) std.io.Reader.StreamError!usize { const d: *Decompress = @alignCast(@ptrCast(context)); @@ -159,7 +160,7 @@ pub fn read( fn readInner( d: *Decompress, - bw: *std.io.BufferedWriter, + bw: *Writer, limit: std.io.Limit, ) (Error || error{ WriteFailed, EndOfStream })!usize { const in = d.input; @@ -347,7 +348,7 @@ fn readInner( /// Write match (back-reference to the same data slice) starting at `distance` /// back from current write position, and `length` of bytes. -fn writeMatch(bw: *std.io.BufferedWriter, length: u16, distance: u16) !void { +fn writeMatch(bw: *Writer, length: u16, distance: u16) !void { _ = bw; _ = length; _ = distance; @@ -727,8 +728,7 @@ test "decompress" { }, }; for (cases) |c| { - var fb: std.io.Reader = undefined; - fb.initFixed(@constCast(c.in)); + var fb: std.io.Reader = .fixed(c.in); var aw: std.io.AllocatingWriter = undefined; aw.init(testing.allocator); defer aw.deinit(); @@ -788,8 +788,7 @@ test "gzip decompress" { }, }; for (cases) |c| { - var fb: std.io.Reader = undefined; - fb.initFixed(@constCast(c.in)); + var fb: std.io.Reader = .fixed(c.in); var aw: std.io.AllocatingWriter = undefined; aw.init(testing.allocator); defer aw.deinit(); @@ -818,8 +817,7 @@ test "zlib decompress" { }, }; for (cases) |c| { - var fb: std.io.Reader = undefined; - fb.initFixed(@constCast(c.in)); + var fb: std.io.Reader = .fixed(c.in); var aw: std.io.AllocatingWriter = undefined; aw.init(testing.allocator); defer aw.deinit(); @@ -880,8 +878,7 @@ test "fuzzing tests" { }; inline for (cases, 0..) |c, case_no| { - var in: std.io.Reader = undefined; - in.initFixed(@constCast(@embedFile("testdata/fuzz/" ++ c.input ++ ".input"))); + var in: std.io.Reader = .fixed(@embedFile("testdata/fuzz/" ++ c.input ++ ".input")); var aw: std.io.AllocatingWriter = undefined; aw.init(testing.allocator); defer aw.deinit(); @@ -903,8 +900,7 @@ test "bug 18966" { const input = @embedFile("testdata/fuzz/bug_18966.input"); const expect = @embedFile("testdata/fuzz/bug_18966.expect"); - var in: std.io.Reader = undefined; - in.initFixed(@constCast(input)); + var in: std.io.Reader = .fixed(input); var aw: std.io.AllocatingWriter = undefined; aw.init(testing.allocator); defer aw.deinit(); @@ -921,8 +917,7 @@ test "reading into empty buffer" { 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data }; - var in: std.io.Reader = undefined; - in.initFixed(@constCast(input)); + var in: std.io.Reader = .fixed(input); var decomp: Decompress = .init(&in, .raw); var decompress_br = decomp.readable(&.{}); var buf: [0]u8 = undefined; diff --git a/lib/std/compress/lzma.zig b/lib/std/compress/lzma.zig index fbbdc46ae3..6217731c70 100644 --- a/lib/std/compress/lzma.zig +++ b/lib/std/compress/lzma.zig @@ -6,6 +6,7 @@ const Allocator = std.mem.Allocator; const testing = std.testing; const expectEqualSlices = std.testing.expectEqualSlices; const expectError = std.testing.expectError; +const Writer = std.io.Writer; pub const RangeDecoder = struct { range: u32, @@ -320,7 +321,7 @@ pub const Decode = struct { self: *Decode, allocator: Allocator, br: *std.io.Reader, - bw: *std.io.BufferedWriter, + bw: *Writer, buffer: anytype, decoder: *RangeDecoder, bytes_read: *usize, @@ -417,7 +418,7 @@ pub const Decode = struct { self: *Decode, allocator: Allocator, br: *std.io.Reader, - bw: *std.io.BufferedWriter, + bw: *Writer, buffer: anytype, decoder: *RangeDecoder, bytes_read: *usize, @@ -429,7 +430,7 @@ pub const Decode = struct { self: *Decode, allocator: Allocator, br: *std.io.Reader, - bw: *std.io.BufferedWriter, + bw: *Writer, buffer: anytype, decoder: *RangeDecoder, bytes_read: *usize, @@ -667,8 +668,8 @@ const LzCircularBuffer = struct { self: *Self, allocator: Allocator, lit: u8, - bw: *std.io.BufferedWriter, - ) std.io.Writer.Error!void { + bw: *Writer, + ) Writer.Error!void { try self.set(allocator, self.cursor, lit); self.cursor += 1; self.len += 1; @@ -686,8 +687,8 @@ const LzCircularBuffer = struct { allocator: Allocator, len: usize, dist: usize, - bw: *std.io.BufferedWriter, - ) std.io.Writer.Error!void { + bw: *Writer, + ) Writer.Error!void { if (dist > self.dict_size or dist > self.len) { return error.CorruptInput; } @@ -704,7 +705,7 @@ const LzCircularBuffer = struct { } } - pub fn finish(self: *Self, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn finish(self: *Self, bw: *Writer) Writer.Error!void { if (self.cursor > 0) { try bw.writeAll(self.buf.items[0..self.cursor]); self.cursor = 0; @@ -839,8 +840,7 @@ test "Vec2D get addition overflow" { fn testDecompress(compressed: []const u8) ![]u8 { const allocator = std.testing.allocator; - var br: std.io.Reader = undefined; - br.initFixed(compressed); + var br: std.io.Reader = .fixed(compressed); var decompressor = try Decompress.initOptions(allocator, &br, .{}); defer decompressor.deinit(); const reader = decompressor.reader(); @@ -927,8 +927,7 @@ test "too small uncompressed size in header" { test "reading one byte" { const compressed = @embedFile("testdata/good-known_size-with_eopm.lzma"); - var br: std.io.Reader = undefined; - br.initFixed(compressed); + var br: std.io.Reader = .fixed(compressed); var decompressor = try Decompress.initOptions(std.testing.allocator, &br, .{}); defer decompressor.deinit(); var buffer = [1]u8{0}; diff --git a/lib/std/compress/lzma2.zig b/lib/std/compress/lzma2.zig index 4b83f2afb2..4d9a2598a5 100644 --- a/lib/std/compress/lzma2.zig +++ b/lib/std/compress/lzma2.zig @@ -1,8 +1,9 @@ const std = @import("../std.zig"); const Allocator = std.mem.Allocator; const lzma = std.compress.lzma; +const Writer = std.io.Writer; -pub fn decompress(gpa: Allocator, reader: *std.io.Reader, writer: *std.io.BufferedWriter) std.io.Reader.StreamError!void { +pub fn decompress(gpa: Allocator, reader: *std.io.Reader, writer: *Writer) std.io.Reader.StreamError!void { var decoder = try Decode.init(gpa); defer decoder.deinit(gpa); return decoder.decompress(gpa, reader, writer); @@ -34,7 +35,7 @@ pub const Decode = struct { self: *Decode, allocator: Allocator, reader: *std.io.Reader, - writer: *std.io.BufferedWriter, + writer: *Writer, ) !void { var accum = LzAccumBuffer.init(std.math.maxInt(usize)); defer accum.deinit(allocator); @@ -57,7 +58,7 @@ pub const Decode = struct { self: *Decode, allocator: Allocator, br: *std.io.Reader, - writer: *std.io.BufferedWriter, + writer: *Writer, accum: *LzAccumBuffer, status: u8, ) !void { @@ -150,7 +151,7 @@ pub const Decode = struct { fn parseUncompressed( allocator: Allocator, reader: *std.io.Reader, - writer: *std.io.BufferedWriter, + writer: *Writer, accum: *LzAccumBuffer, reset_dict: bool, ) !void { @@ -276,8 +277,7 @@ test decompress { 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, }; - var stream: std.io.Reader = undefined; - stream.initFixed(&compressed); + var stream: std.io.Reader = .fixed(&compressed); var decomp: std.io.AllocatingWriter = undefined; const decomp_bw = decomp.init(std.testing.allocator); defer decomp.deinit(); diff --git a/lib/std/compress/zstd/Decompress.zig b/lib/std/compress/zstd/Decompress.zig index face1a364a..440bfba1a9 100644 --- a/lib/std/compress/zstd/Decompress.zig +++ b/lib/std/compress/zstd/Decompress.zig @@ -3,8 +3,8 @@ const std = @import("std"); const assert = std.debug.assert; const Reader = std.io.Reader; const Limit = std.io.Limit; -const BufferedWriter = std.io.BufferedWriter; const zstd = @import("../zstd.zig"); +const Writer = std.io.Writer; input: *Reader, state: State, @@ -77,7 +77,7 @@ pub fn reader(self: *Decompress) Reader { }; } -fn read(context: ?*anyopaque, bw: *BufferedWriter, limit: Limit) Reader.StreamError!usize { +fn read(context: ?*anyopaque, bw: *Writer, limit: Limit) Reader.StreamError!usize { const d: *Decompress = @ptrCast(@alignCast(context)); const in = d.input; @@ -139,7 +139,7 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void { } } -fn readInFrame(d: *Decompress, bw: *BufferedWriter, limit: Limit, state: *State.InFrame) !usize { +fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame) !usize { const in = d.input; const header_bytes = try in.takeArray(3); @@ -649,8 +649,7 @@ pub const Frame = struct { if (decode.literal_written_count + literal_length > decode.literal_header.regenerated_size) return error.MalformedLiteralsLength; - var sub_bw: BufferedWriter = undefined; - sub_bw.initFixed(dest[write_pos..]); + var sub_bw: Writer = .fixed(dest[write_pos..]); try decodeLiterals(decode, &sub_bw, literal_length); decode.literal_written_count += literal_length; // This is not a @memmove; it intentionally repeats patterns @@ -698,7 +697,7 @@ pub const Frame = struct { } /// Decode `len` bytes of literals into `dest`. - fn decodeLiterals(self: *Decode, dest: *BufferedWriter, len: usize) !void { + fn decodeLiterals(self: *Decode, dest: *Writer, len: usize) !void { switch (self.literal_header.block_type) { .raw => { try dest.writeAll(self.literal_streams.one[self.literal_written_count..][0..len]); diff --git a/lib/std/crypto/Sha1.zig b/lib/std/crypto/Sha1.zig index 228a1a74c2..41ff50d1ba 100644 --- a/lib/std/crypto/Sha1.zig +++ b/lib/std/crypto/Sha1.zig @@ -7,6 +7,7 @@ const std = @import("../std.zig"); const mem = std.mem; const math = std.math; const assert = std.debug.assert; +const Writer = std.io.Writer; pub const block_length = 64; pub const digest_length = 20; @@ -252,21 +253,18 @@ pub fn round(d_s: *[5]u32, b: *const [64]u8) void { d_s[4] +%= v[4]; } -pub fn writable(sha1: *Sha1, buffer: []u8) std.io.BufferedWriter { +pub fn writer(sha1: *Sha1, buffer: []u8) Writer { return .{ - .unbuffered_writer = .{ - .context = sha1, - .vtable = &.{ - .writeSplat = writeSplat, - .writeFile = std.io.Writer.unimplementedWriteFile, - }, - }, + .context = sha1, + .vtable = &.{ .drain = drain }, .buffer = buffer, }; } -fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { - const sha1: *Sha1 = @ptrCast(@alignCast(context)); +fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize { + const sha1: *Sha1 = @ptrCast(@alignCast(w.context)); + sha1.update(w.buffered()); + w.end = 0; const start_total = sha1.total_len; if (sha1.buf_end == 0) { try writeSplatAligned(sha1, data, splat); @@ -299,7 +297,7 @@ fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std. return @intCast(sha1.total_len - start_total); } -fn writeSplatAligned(sha1: *Sha1, data: []const []const u8, splat: usize) std.io.Writer.Error!void { +fn writeSplatAligned(sha1: *Sha1, data: []const []const u8, splat: usize) Writer.Error!void { assert(sha1.buf_end == 0); for (data[0 .. data.len - 1]) |slice| { var off: usize = 0; diff --git a/lib/std/crypto/codecs/asn1.zig b/lib/std/crypto/codecs/asn1.zig index 20d22c0236..514d79669f 100644 --- a/lib/std/crypto/codecs/asn1.zig +++ b/lib/std/crypto/codecs/asn1.zig @@ -1,5 +1,8 @@ //! ASN.1 types for public consumption. + const std = @import("std"); +const Writer = std.io.Writer; + pub const der = @import("./asn1/der.zig"); pub const Oid = @import("./asn1/Oid.zig"); @@ -90,7 +93,7 @@ pub const Tag = struct { }; } - pub fn encode(self: Tag, writer: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn encode(self: Tag, writer: *Writer) Writer.Error!void { var tag1: FirstTag = .{ .number = undefined, .constructed = self.constructed, diff --git a/lib/std/crypto/codecs/asn1/Oid.zig b/lib/std/crypto/codecs/asn1/Oid.zig index 4c20831c8b..559b425263 100644 --- a/lib/std/crypto/codecs/asn1/Oid.zig +++ b/lib/std/crypto/codecs/asn1/Oid.zig @@ -9,7 +9,7 @@ pub const EncodeError = error{ MissingPrefix, }; -pub fn encode(dot_notation: []const u8, out: *std.io.BufferedWriter) EncodeError!void { +pub fn encode(dot_notation: []const u8, out: *Writer) EncodeError!void { var split = std.mem.splitScalar(u8, dot_notation, '.'); const first_str = split.next() orelse return error.MissingPrefix; const second_str = split.next() orelse return error.MissingPrefix; @@ -41,8 +41,7 @@ pub fn encode(dot_notation: []const u8, out: *std.io.BufferedWriter) EncodeError pub const InitError = std.fmt.ParseIntError || error{ MissingPrefix, BufferTooSmall }; pub fn fromDot(dot_notation: []const u8, out: []u8) InitError!Oid { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(out); + var bw: Writer = .fixed(out); encode(dot_notation, &bw) catch |err| switch (err) { error.WriteFailed => return error.BufferTooSmall, else => |e| return e, @@ -58,7 +57,7 @@ test fromDot { } } -pub fn toDot(self: Oid, writer: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn toDot(self: Oid, writer: *Writer) Writer.Error!void { const encoded = self.encoded; const first = @divTrunc(encoded[0], 40); const second = encoded[0] - first * 40; @@ -90,8 +89,7 @@ test toDot { var buf: [256]u8 = undefined; for (test_cases) |t| { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buf); + var bw: Writer = .fixed(&buf); try toDot(Oid{ .encoded = t.encoded }, &bw); try std.testing.expectEqualStrings(t.dot_notation, bw.getWritten()); } @@ -219,3 +217,4 @@ const encoding_base = 128; const Allocator = std.mem.Allocator; const der = @import("der.zig"); const asn1 = @import("../asn1.zig"); +const Writer = std.io.Writer; diff --git a/lib/std/crypto/ecdsa.zig b/lib/std/crypto/ecdsa.zig index e88a7a54c7..b534eb8c20 100644 --- a/lib/std/crypto/ecdsa.zig +++ b/lib/std/crypto/ecdsa.zig @@ -6,6 +6,7 @@ const io = std.io; const mem = std.mem; const sha3 = crypto.hash.sha3; const testing = std.testing; +const Writer = std.io.Writer; const EncodingError = crypto.errors.EncodingError; const IdentityElementError = crypto.errors.IdentityElementError; @@ -135,8 +136,7 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { /// The maximum length of the DER encoding is der_encoded_length_max. /// The function returns a slice, that can be shorter than der_encoded_length_max. pub fn toDer(sig: Signature, buf: *[der_encoded_length_max]u8) []u8 { - var w: std.io.BufferedWriter = undefined; - w.initFixed(buf); + var w: Writer = .fixed(buf); const r_len = @as(u8, @intCast(sig.r.len + (sig.r[0] >> 7))); const s_len = @as(u8, @intCast(sig.s.len + (sig.s[0] >> 7))); const seq_len = @as(u8, @intCast(2 + r_len + 2 + s_len)); diff --git a/lib/std/crypto/phc_encoding.zig b/lib/std/crypto/phc_encoding.zig index 690680991f..ccf7831550 100644 --- a/lib/std/crypto/phc_encoding.zig +++ b/lib/std/crypto/phc_encoding.zig @@ -5,6 +5,7 @@ const fmt = std.fmt; const io = std.io; const mem = std.mem; const meta = std.meta; +const Writer = std.io.Writer; const fields_delimiter = "$"; const fields_delimiter_scalar = '$'; @@ -188,16 +189,15 @@ pub fn deserialize(comptime HashResult: type, str: []const u8) Error!HashResult /// /// `params` can also include any additional parameters. pub fn serialize(params: anytype, str: []u8) Error![]const u8 { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(str); - try serializeTo(params, &bw); - return bw.getWritten(); + var w: Writer = .fixed(str); + try serializeTo(params, &w); + return w.buffered(); } /// Compute the number of bytes required to serialize `params` pub fn calcSize(params: anytype) usize { var trash: [128]u8 = undefined; - var bw: std.io.BufferedWriter = .{ + var bw: Writer = .{ .unbuffered_writer = .discarding, .buffer = &trash, }; @@ -205,7 +205,7 @@ pub fn calcSize(params: anytype) usize { return bw.count; } -fn serializeTo(params: anytype, out: *std.io.BufferedWriter) !void { +fn serializeTo(params: anytype, out: *Writer) !void { const HashResult = @TypeOf(params); if (@hasField(HashResult, version_param_name)) { diff --git a/lib/std/crypto/scrypt.zig b/lib/std/crypto/scrypt.zig index b47a979c24..22f17d7542 100644 --- a/lib/std/crypto/scrypt.zig +++ b/lib/std/crypto/scrypt.zig @@ -10,6 +10,7 @@ const math = std.math; const mem = std.mem; const meta = std.meta; const pwhash = crypto.pwhash; +const Writer = std.io.Writer; const phc_format = @import("phc_encoding.zig"); @@ -304,26 +305,22 @@ const crypt_format = struct { /// Serialize parameters into a string in modular crypt format. pub fn serialize(params: anytype, str: []u8) EncodingError![]const u8 { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(str); - try serializeTo(params, &bw); - return bw.getWritten(); + var w: Writer = .fixed(str); + try serializeTo(params, &w); + return w.getWritten(); } /// Compute the number of bytes required to serialize `params` pub fn calcSize(params: anytype) usize { var trash: [64]u8 = undefined; - var bw: std.io.BufferedWriter = .{ - .unbuffered_writer = .discarding, - .buffer = &trash, - }; - serializeTo(params, &bw) catch |err| switch (err) { + var w: std.io.Writer = .discarding(&trash); + serializeTo(params, &w) catch |err| switch (err) { error.WriteFailed => unreachable, }; - return bw.count; + return w.count; } - fn serializeTo(params: anytype, out: *std.io.BufferedWriter) !void { + fn serializeTo(params: anytype, out: *Writer) !void { var header: [14]u8 = undefined; header[0..3].* = prefix.*; Codec.intEncode(header[3..4], params.ln); diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index 9a0cfc0849..4ea2714973 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -18,6 +18,7 @@ const builtin = @import("builtin"); const mem = std.mem; const math = std.math; const htest = @import("test.zig"); +const Writer = std.io.Writer; pub const Sha224 = Sha2x32(iv224, 224); pub const Sha256 = Sha2x32(iv256, 256); @@ -382,20 +383,20 @@ fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type { for (&d.s, v) |*dv, vv| dv.* +%= vv; } - pub fn writable(this: *@This(), buffer: []u8) std.io.BufferedWriter { + pub fn writable(this: *@This(), buffer: []u8) Writer { return .{ .unbuffered_writer = .{ .context = this, .vtable = &.{ .writeSplat = writeSplat, - .writeFile = std.io.Writer.unimplementedWriteFile, + .writeFile = Writer.unimplementedWriteFile, }, }, .buffer = buffer, }; } - fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { + fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Writer.Error!usize { const this: *@This() = @ptrCast(@alignCast(context)); const start_total = this.total_len; for (data[0 .. data.len - 1]) |slice| this.update(slice); diff --git a/lib/std/crypto/tls/Client.zig b/lib/std/crypto/tls/Client.zig index 971e2a4171..047fec8d02 100644 --- a/lib/std/crypto/tls/Client.zig +++ b/lib/std/crypto/tls/Client.zig @@ -25,7 +25,7 @@ input: *std.io.Reader, /// The encrypted stream from the client to the server. Bytes are pushed here /// via `writer`. -output: *std.io.BufferedWriter, +output: *Writer, /// Populated when `error.TlsAlert` is returned. alert: ?tls.Alert = null, @@ -72,7 +72,7 @@ pub const SslKeyLog = struct { client_key_seq: u64, server_key_seq: u64, client_random: [32]u8, - writer: *std.io.BufferedWriter, + writer: *Writer, fn clientCounter(key_log: *@This()) u64 { defer key_log.client_key_seq += 1; @@ -176,7 +176,7 @@ const InitError = error{ pub fn init( client: *Client, input: *std.io.Reader, - output: *std.io.BufferedWriter, + output: *Writer, options: Options, ) InitError!void { assert(input.buffer.len >= min_buffer_len); @@ -1043,7 +1043,7 @@ pub fn eof(c: Client) bool { return c.received_close_notify; } -fn read(context: ?*anyopaque, bw: *std.io.BufferedWriter, limit: std.io.Limit) Reader.StreamError!usize { +fn read(context: ?*anyopaque, bw: *Writer, limit: std.io.Limit) Reader.StreamError!usize { const c: *Client = @ptrCast(@alignCast(context)); if (c.eof()) return error.EndOfStream; const input = c.input; @@ -1226,7 +1226,7 @@ fn failRead(c: *Client, err: ReadError) error{ReadFailed} { return error.ReadFailed; } -fn logSecrets(bw: *std.io.BufferedWriter, context: anytype, secrets: anytype) void { +fn logSecrets(bw: *Writer, context: anytype, secrets: anytype) void { inline for (@typeInfo(@TypeOf(secrets)).@"struct".fields) |field| bw.print("{s}" ++ (if (@hasField(@TypeOf(context), "counter")) "_{d}" else "") ++ " {x} {x}\n", .{field.name} ++ (if (@hasField(@TypeOf(context), "counter")) .{context.counter} else .{}) ++ .{ diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 58ba4edcc1..0eac0277c7 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -12,6 +12,7 @@ const windows = std.os.windows; const native_arch = builtin.cpu.arch; const native_os = builtin.os.tag; const native_endian = native_arch.endian(); +const Writer = std.io.Writer; pub const MemoryAccessor = @import("debug/MemoryAccessor.zig"); pub const FixedBufferReader = @import("debug/FixedBufferReader.zig"); @@ -208,9 +209,9 @@ pub fn unlockStdErr() void { /// /// During the lock, any `std.Progress` information is cleared from the terminal. /// -/// Returns a `std.io.BufferedWriter` with empty buffer, meaning that it is +/// Returns a `Writer` with empty buffer, meaning that it is /// in fact unbuffered and does not need to be flushed. -pub fn lockStderrWriter(buffer: []u8) *std.io.BufferedWriter { +pub fn lockStderrWriter(buffer: []u8) *Writer { return std.Progress.lockStderrWriter(buffer); } @@ -252,7 +253,7 @@ pub fn dumpHex(bytes: []const u8) void { } /// Prints a hexadecimal view of the bytes, returning any error that occurs. -pub fn dumpHexFallible(bw: *std.io.BufferedWriter, ttyconf: std.io.tty.Config, bytes: []const u8) !void { +pub fn dumpHexFallible(bw: *Writer, ttyconf: std.io.tty.Config, bytes: []const u8) !void { var chunks = mem.window(u8, bytes, 16, 16); while (chunks.next()) |window| { // 1. Print the address. @@ -329,7 +330,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { } /// Prints the current stack trace to the provided writer. -pub fn dumpCurrentStackTraceToWriter(start_addr: ?usize, writer: *std.io.BufferedWriter) !void { +pub fn dumpCurrentStackTraceToWriter(start_addr: ?usize, writer: *Writer) !void { if (builtin.target.cpu.arch.isWasm()) { if (native_os == .wasi) { try writer.writeAll("Unable to dump stack trace: not implemented for Wasm\n"); @@ -413,7 +414,7 @@ pub inline fn getContext(context: *ThreadContext) bool { /// Tries to print the stack trace starting from the supplied base pointer to stderr, /// unbuffered, and ignores any error returned. /// TODO multithreaded awareness -pub fn dumpStackTraceFromBase(context: *ThreadContext, stderr: *std.io.BufferedWriter) void { +pub fn dumpStackTraceFromBase(context: *ThreadContext, stderr: *Writer) void { nosuspend { if (builtin.target.cpu.arch.isWasm()) { if (native_os == .wasi) { @@ -584,8 +585,7 @@ pub fn panicExtra( const size = 0x1000; const trunc_msg = "(msg truncated)"; var buf: [size + trunc_msg.len]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(buf[0..size]); + var bw: Writer = .fixed(buf[0..size]); // a minor annoyance with this is that it will result in the NoSpaceLeft // error being part of the @panic stack trace (but that error should // only happen rarely) @@ -733,7 +733,7 @@ fn waitForOtherThreadToFinishPanicking() void { pub fn writeStackTrace( stack_trace: std.builtin.StackTrace, - writer: *std.io.BufferedWriter, + writer: *Writer, debug_info: *SelfInfo, tty_config: io.tty.Config, ) !void { @@ -964,7 +964,7 @@ pub const StackIterator = struct { }; pub fn writeCurrentStackTrace( - writer: *std.io.BufferedWriter, + writer: *Writer, debug_info: *SelfInfo, tty_config: io.tty.Config, start_addr: ?usize, @@ -1052,7 +1052,7 @@ pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const w } pub fn writeStackTraceWindows( - writer: *std.io.BufferedWriter, + writer: *Writer, debug_info: *SelfInfo, tty_config: io.tty.Config, context: *const windows.CONTEXT, @@ -1072,7 +1072,7 @@ pub fn writeStackTraceWindows( } } -fn printUnknownSource(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, tty_config: io.tty.Config) !void { +fn printUnknownSource(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: io.tty.Config) !void { const module_name = debug_info.getModuleNameForAddress(address); return printLineInfo( writer, @@ -1085,14 +1085,14 @@ fn printUnknownSource(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, add ); } -fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *std.io.BufferedWriter, tty_config: io.tty.Config) void { +fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *Writer, tty_config: io.tty.Config) void { if (!have_ucontext) return; if (it.getLastError()) |unwind_error| { printUnwindError(debug_info, writer, unwind_error.address, unwind_error.err, tty_config) catch {}; } } -fn printUnwindError(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { +fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; try tty_config.setColor(writer, .dim); if (err == error.MissingDebugInfo) { @@ -1103,7 +1103,7 @@ fn printUnwindError(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, addre try tty_config.setColor(writer, .reset); } -pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, tty_config: io.tty.Config) !void { +pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: io.tty.Config) !void { const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, writer, address, tty_config), else => return err, @@ -1127,7 +1127,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *std.io.BufferedWrite } fn printLineInfo( - writer: *std.io.BufferedWriter, + writer: *Writer, source_location: ?SourceLocation, address: usize, symbol_name: []const u8, @@ -1174,7 +1174,7 @@ fn printLineInfo( } } -fn printLineFromFileAnyOs(writer: *std.io.BufferedWriter, source_location: SourceLocation) !void { +fn printLineFromFileAnyOs(writer: *Writer, source_location: SourceLocation) !void { // Need this to always block even in async I/O mode, because this could potentially // be called from e.g. the event loop code crashing. var f = try fs.cwd().openFile(source_location.file_name, .{}); @@ -1567,7 +1567,7 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: posix.abort(); } -fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8, stderr: *std.io.BufferedWriter) void { +fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8, stderr: *Writer) void { _ = switch (msg) { 0 => stderr.print("{s}\n", .{label.?}), 1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), @@ -1699,7 +1699,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize t: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, - writer: *std.io.BufferedWriter, + writer: *Writer, ) !void { if (fmt.len != 0) std.fmt.invalidFmtError(fmt, t); _ = options; diff --git a/lib/std/debug/Dwarf/expression.zig b/lib/std/debug/Dwarf/expression.zig index 88d8e9f7f8..0a45ecf33a 100644 --- a/lib/std/debug/Dwarf/expression.zig +++ b/lib/std/debug/Dwarf/expression.zig @@ -9,6 +9,7 @@ const abi = std.debug.Dwarf.abi; const mem = std.mem; const assert = std.debug.assert; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; /// Expressions can be evaluated in different contexts, each requiring its own set of inputs. /// Callers should specify all the fields relevant to their context. If a field is required @@ -826,7 +827,7 @@ pub fn Builder(comptime options: Options) type { return struct { /// Zero-operand instructions - pub fn writeOpcode(writer: *std.io.BufferedWriter, comptime opcode: u8) !void { + pub fn writeOpcode(writer: *Writer, comptime opcode: u8) !void { if (options.call_frame_context and !comptime isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode; switch (opcode) { OP.dup, @@ -867,14 +868,14 @@ pub fn Builder(comptime options: Options) type { } // 2.5.1.1: Literal Encodings - pub fn writeLiteral(writer: *std.io.BufferedWriter, literal: u8) !void { + pub fn writeLiteral(writer: *Writer, literal: u8) !void { switch (literal) { 0...31 => |n| try writer.writeByte(n + OP.lit0), else => return error.InvalidLiteral, } } - pub fn writeConst(writer: *std.io.BufferedWriter, comptime T: type, value: T) !void { + pub fn writeConst(writer: *Writer, comptime T: type, value: T) !void { if (@typeInfo(T) != .int) @compileError("Constants must be integers"); switch (T) { @@ -906,12 +907,12 @@ pub fn Builder(comptime options: Options) type { } } - pub fn writeConstx(writer: *std.io.BufferedWriter, debug_addr_offset: anytype) !void { + pub fn writeConstx(writer: *Writer, debug_addr_offset: anytype) !void { try writer.writeByte(OP.constx); try leb.writeUleb128(writer, debug_addr_offset); } - pub fn writeConstType(writer: *std.io.BufferedWriter, die_offset: anytype, value_bytes: []const u8) !void { + pub fn writeConstType(writer: *Writer, die_offset: anytype, value_bytes: []const u8) !void { if (options.call_frame_context) return error.InvalidCFAOpcode; if (value_bytes.len > 0xff) return error.InvalidTypeLength; try writer.writeByte(OP.const_type); @@ -920,36 +921,36 @@ pub fn Builder(comptime options: Options) type { try writer.writeAll(value_bytes); } - pub fn writeAddr(writer: *std.io.BufferedWriter, value: Address) !void { + pub fn writeAddr(writer: *Writer, value: Address) !void { try writer.writeByte(OP.addr); try writer.writeInt(Address, value, options.endian); } - pub fn writeAddrx(writer: *std.io.BufferedWriter, debug_addr_offset: anytype) !void { + pub fn writeAddrx(writer: *Writer, debug_addr_offset: anytype) !void { if (options.call_frame_context) return error.InvalidCFAOpcode; try writer.writeByte(OP.addrx); try leb.writeUleb128(writer, debug_addr_offset); } // 2.5.1.2: Register Values - pub fn writeFbreg(writer: *std.io.BufferedWriter, offset: anytype) !void { + pub fn writeFbreg(writer: *Writer, offset: anytype) !void { try writer.writeByte(OP.fbreg); try leb.writeIleb128(writer, offset); } - pub fn writeBreg(writer: *std.io.BufferedWriter, register: u8, offset: anytype) !void { + pub fn writeBreg(writer: *Writer, register: u8, offset: anytype) !void { if (register > 31) return error.InvalidRegister; try writer.writeByte(OP.breg0 + register); try leb.writeIleb128(writer, offset); } - pub fn writeBregx(writer: *std.io.BufferedWriter, register: anytype, offset: anytype) !void { + pub fn writeBregx(writer: *Writer, register: anytype, offset: anytype) !void { try writer.writeByte(OP.bregx); try leb.writeUleb128(writer, register); try leb.writeIleb128(writer, offset); } - pub fn writeRegvalType(writer: *std.io.BufferedWriter, register: anytype, offset: anytype) !void { + pub fn writeRegvalType(writer: *Writer, register: anytype, offset: anytype) !void { if (options.call_frame_context) return error.InvalidCFAOpcode; try writer.writeByte(OP.regval_type); try leb.writeUleb128(writer, register); @@ -957,29 +958,29 @@ pub fn Builder(comptime options: Options) type { } // 2.5.1.3: Stack Operations - pub fn writePick(writer: *std.io.BufferedWriter, index: u8) !void { + pub fn writePick(writer: *Writer, index: u8) !void { try writer.writeByte(OP.pick); try writer.writeByte(index); } - pub fn writeDerefSize(writer: *std.io.BufferedWriter, size: u8) !void { + pub fn writeDerefSize(writer: *Writer, size: u8) !void { try writer.writeByte(OP.deref_size); try writer.writeByte(size); } - pub fn writeXDerefSize(writer: *std.io.BufferedWriter, size: u8) !void { + pub fn writeXDerefSize(writer: *Writer, size: u8) !void { try writer.writeByte(OP.xderef_size); try writer.writeByte(size); } - pub fn writeDerefType(writer: *std.io.BufferedWriter, size: u8, die_offset: anytype) !void { + pub fn writeDerefType(writer: *Writer, size: u8, die_offset: anytype) !void { if (options.call_frame_context) return error.InvalidCFAOpcode; try writer.writeByte(OP.deref_type); try writer.writeByte(size); try leb.writeUleb128(writer, die_offset); } - pub fn writeXDerefType(writer: *std.io.BufferedWriter, size: u8, die_offset: anytype) !void { + pub fn writeXDerefType(writer: *Writer, size: u8, die_offset: anytype) !void { try writer.writeByte(OP.xderef_type); try writer.writeByte(size); try leb.writeUleb128(writer, die_offset); @@ -987,24 +988,24 @@ pub fn Builder(comptime options: Options) type { // 2.5.1.4: Arithmetic and Logical Operations - pub fn writePlusUconst(writer: *std.io.BufferedWriter, uint_value: anytype) !void { + pub fn writePlusUconst(writer: *Writer, uint_value: anytype) !void { try writer.writeByte(OP.plus_uconst); try leb.writeUleb128(writer, uint_value); } // 2.5.1.5: Control Flow Operations - pub fn writeSkip(writer: *std.io.BufferedWriter, offset: i16) !void { + pub fn writeSkip(writer: *Writer, offset: i16) !void { try writer.writeByte(OP.skip); try writer.writeInt(i16, offset, options.endian); } - pub fn writeBra(writer: *std.io.BufferedWriter, offset: i16) !void { + pub fn writeBra(writer: *Writer, offset: i16) !void { try writer.writeByte(OP.bra); try writer.writeInt(i16, offset, options.endian); } - pub fn writeCall(writer: *std.io.BufferedWriter, comptime T: type, offset: T) !void { + pub fn writeCall(writer: *Writer, comptime T: type, offset: T) !void { if (options.call_frame_context) return error.InvalidCFAOpcode; switch (T) { u16 => try writer.writeByte(OP.call2), @@ -1015,19 +1016,19 @@ pub fn Builder(comptime options: Options) type { try writer.writeInt(T, offset, options.endian); } - pub fn writeCallRef(writer: *std.io.BufferedWriter, comptime is_64: bool, value: if (is_64) u64 else u32) !void { + pub fn writeCallRef(writer: *Writer, comptime is_64: bool, value: if (is_64) u64 else u32) !void { if (options.call_frame_context) return error.InvalidCFAOpcode; try writer.writeByte(OP.call_ref); try writer.writeInt(if (is_64) u64 else u32, value, options.endian); } - pub fn writeConvert(writer: *std.io.BufferedWriter, die_offset: anytype) !void { + pub fn writeConvert(writer: *Writer, die_offset: anytype) !void { if (options.call_frame_context) return error.InvalidCFAOpcode; try writer.writeByte(OP.convert); try leb.writeUleb128(writer, die_offset); } - pub fn writeReinterpret(writer: *std.io.BufferedWriter, die_offset: anytype) !void { + pub fn writeReinterpret(writer: *Writer, die_offset: anytype) !void { if (options.call_frame_context) return error.InvalidCFAOpcode; try writer.writeByte(OP.reinterpret); try leb.writeUleb128(writer, die_offset); @@ -1035,23 +1036,23 @@ pub fn Builder(comptime options: Options) type { // 2.5.1.7: Special Operations - pub fn writeEntryValue(writer: *std.io.BufferedWriter, expression: []const u8) !void { + pub fn writeEntryValue(writer: *Writer, expression: []const u8) !void { try writer.writeByte(OP.entry_value); try leb.writeUleb128(writer, expression.len); try writer.writeAll(expression); } // 2.6: Location Descriptions - pub fn writeReg(writer: *std.io.BufferedWriter, register: u8) !void { + pub fn writeReg(writer: *Writer, register: u8) !void { try writer.writeByte(OP.reg0 + register); } - pub fn writeRegx(writer: *std.io.BufferedWriter, register: anytype) !void { + pub fn writeRegx(writer: *Writer, register: anytype) !void { try writer.writeByte(OP.regx); try leb.writeUleb128(writer, register); } - pub fn writeImplicitValue(writer: *std.io.BufferedWriter, value_bytes: []const u8) !void { + pub fn writeImplicitValue(writer: *Writer, value_bytes: []const u8) !void { try writer.writeByte(OP.implicit_value); try leb.writeUleb128(writer, value_bytes.len); try writer.writeAll(value_bytes); diff --git a/lib/std/debug/FixedBufferReader.zig b/lib/std/debug/FixedBufferReader.zig index 939586ede9..36d6985d42 100644 --- a/lib/std/debug/FixedBufferReader.zig +++ b/lib/std/debug/FixedBufferReader.zig @@ -52,8 +52,7 @@ pub fn readIntChecked( } pub fn readLeb128(fbr: *FixedBufferReader, comptime T: type) Error!T { - var br: std.io.Reader = undefined; - br.initFixed(@constCast(fbr.buf)); + var br: std.io.Reader = .fixed(fbr.buf); br.seek = fbr.pos; const result = br.takeLeb128(T); fbr.pos = br.seek; diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index b9f1daa131..6e6e710f1f 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -13,6 +13,7 @@ const lossyCast = math.lossyCast; const expectFmt = std.testing.expectFmt; const testing = std.testing; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; pub const float = @import("fmt/float.zig"); @@ -92,7 +93,7 @@ pub const Options = struct { /// A user type may be a `struct`, `vector`, `union` or `enum` type. /// /// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`. -pub fn format(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytype) std.io.Writer.Error!void { +pub fn format(bw: *Writer, comptime fmt: []const u8, args: anytype) Writer.Error!void { const ArgsType = @TypeOf(args); const args_type_info = @typeInfo(ArgsType); if (args_type_info != .@"struct") { @@ -452,7 +453,7 @@ fn SliceEscape(comptime case: Case) type { return struct { pub fn format( bytes: []const u8, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime fmt: []const u8, ) !void { _ = fmt; @@ -494,8 +495,7 @@ pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscap /// Asserts the rendered integer value fits in `buffer`. /// Returns the end index within `buffer`. pub fn printInt(buffer: []u8, value: anytype, base: u8, case: Case, options: Options) usize { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(buffer); + var bw: Writer = .fixed(buffer); bw.printIntOptions(value, base, case, options) catch unreachable; return bw.end; } @@ -532,7 +532,7 @@ pub fn Formatter(comptime formatFn: anytype) type { const Data = @typeInfo(@TypeOf(formatFn)).@"fn".params[0].type.?; return struct { data: Data, - pub fn format(self: @This(), writer: *std.io.BufferedWriter, comptime fmt: []const u8) std.io.Writer.Error!void { + pub fn format(self: @This(), writer: *Writer, comptime fmt: []const u8) Writer.Error!void { try formatFn(self.data, writer, fmt); } }; @@ -830,8 +830,7 @@ pub const BufPrintError = error{ /// Print a Formatter string into `buf`. Returns a slice of the bytes printed. pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(buf); + var bw: Writer = .fixed(buf); bw.print(fmt, args) catch |err| switch (err) { error.WriteFailed => return error.NoSpaceLeft, }; @@ -846,7 +845,7 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr /// Count the characters needed for format. pub fn count(comptime fmt: []const u8, args: anytype) usize { var trash_buffer: [64]u8 = undefined; - var bw: std.io.BufferedWriter = .{ + var bw: Writer = .{ .unbuffered_writer = .discarding, .buffer = &trash_buffer, }; @@ -1018,16 +1017,15 @@ test "int.padded" { test "buffer" { { var buf1: [32]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buf1); + var bw: Writer = .fixed(&buf1); try bw.printValue("", .{}, 1234, std.options.fmt_max_depth); try std.testing.expectEqualStrings("1234", bw.getWritten()); - bw.initFixed(&buf1); + bw = .fixed(&buf1); try bw.printValue("c", .{}, 'a', std.options.fmt_max_depth); try std.testing.expectEqualStrings("a", bw.getWritten()); - bw.initFixed(&buf1); + bw = .fixed(&buf1); try bw.printValue("b", .{}, 0b1100, std.options.fmt_max_depth); try std.testing.expectEqualStrings("1100", bw.getWritten()); } diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 2837535d57..f941e37120 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -844,7 +844,7 @@ pub fn write(self: File, bytes: []const u8) WriteError!usize { return posix.write(self.handle, bytes); } -/// One-shot alternative to `std.io.BufferedWriter.writeAll` via `writer`. +/// One-shot alternative to `std.io.Writer.writeAll` via `writer`. pub fn writeAll(self: File, bytes: []const u8) WriteError!void { var index: usize = 0; while (index < bytes.len) { @@ -1029,7 +1029,7 @@ pub const Reader = struct { fn stream( io_reader: *std.io.Reader, - bw: *BufferedWriter, + bw: *std.io.Writer, limit: std.io.Limit, ) std.io.Reader.StreamError!usize { const r: *Reader = @fieldParentPtr("interface", io_reader); @@ -1180,6 +1180,12 @@ pub const Reader = struct { .failure => return error.ReadFailed, } } + + pub fn atEnd(r: *Reader) bool { + // Even if stat fails, size is set when end is encountered. + const size = r.getSize() orelse return false; + return size - r.pos == 0; + } }; pub const Writer = struct { @@ -1189,6 +1195,7 @@ pub const Writer = struct { pos: u64 = 0, sendfile_err: ?SendfileError = null, seek_err: ?SeekError = null, + interface: std.io.Writer, pub const Mode = Reader.Mode; @@ -1205,20 +1212,20 @@ pub const Writer = struct { /// vectors through the underlying write calls as possible. const max_buffers_len = 16; - pub fn interface(w: *Writer) std.io.Writer { + pub fn init(file: File, buffer: []u8) std.io.Writer { return .{ - .context = w, - .vtable = &.{ - .writeSplat = writeSplat, - .writeFile = writeFile, + .file = file, + .interface = .{ + .context = undefined, + .vtable = &.{ + .drain = drain, + .sendFile = sendFile, + }, + .buffer = buffer, }, }; } - pub fn writable(w: *Writer, buffer: []u8) std.io.BufferedWriter { - return interface(w).buffered(buffer); - } - pub fn moveToReader(w: *Writer) Reader { defer w.* = undefined; return .{ @@ -1229,9 +1236,10 @@ pub const Writer = struct { }; } - pub fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { - const w: *Writer = @ptrCast(@alignCast(context)); + pub fn drain(io_writer: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { + const w: *Writer = @fieldParentPtr("interface", io_writer); const handle = w.file.handle; + if (true) @panic("update to check for buffered data"); var splat_buffer: [256]u8 = undefined; if (is_windows) { if (data.len == 1 and splat == 0) return 0; @@ -1282,14 +1290,8 @@ pub const Writer = struct { }; } - pub fn writeFile( - context: ?*anyopaque, - file_reader: *Reader, - limit: std.io.Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, - ) std.io.Writer.FileError!usize { - const w: *Writer = @ptrCast(@alignCast(context)); + pub fn sendFile(io_writer: *Writer, file_reader: *Reader, limit: std.io.Limit) std.io.Writer.FileError!usize { + const w: *Writer = @fieldParentPtr("interface", io_writer); const out_fd = w.file.handle; const in_fd = file_reader.file.handle; // TODO try using copy_file_range on Linux @@ -1299,9 +1301,8 @@ pub const Writer = struct { if (native_os == .linux and w.mode == .streaming) sf: { // Try using sendfile on Linux. if (w.sendfile_err != null) break :sf; - // Linux sendfile does not support headers or trailers but it does - // support a streaming read from in_file. - if (headers_len > 0) return writeSplat(context, headers_and_trailers[0..headers_len], 1); + // Linux sendfile does not support headers. + if (io_writer.end != 0) return drain(io_writer, &.{""}, 1); const max_count = 0x7ffff000; // Avoid EINVAL. var off: std.os.linux.off_t = undefined; const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) { @@ -1315,8 +1316,7 @@ pub const Writer = struct { } return 0; }; - off = std.math.cast(std.os.linux.off_t, file_reader.pos) orelse - return writeSplat(context, headers_and_trailers, 1); + off = std.math.cast(std.os.linux.off_t, file_reader.pos) orelse return error.ReadFailed; break :o .{ &off, @min(@intFromEnum(limit), size - file_reader.pos, max_count) }; }, .streaming => .{ null, limit.minInt(max_count) }, @@ -1576,4 +1576,3 @@ const linux = std.os.linux; const windows = std.os.windows; const maxInt = std.math.maxInt; const Alignment = std.mem.Alignment; -const BufferedWriter = std.io.BufferedWriter; diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index cff0fda273..f17c1553a5 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -150,8 +150,8 @@ pub fn fmtJoin(paths: []const []const u8) std.fmt.Formatter(formatJoin) { return .{ .data = paths }; } -fn formatJoin(paths: []const []const u8, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { - _ = fmt; +fn formatJoin(paths: []const []const u8, bw: *std.io.Writer, comptime fmt: []const u8) !void { + comptime assert(fmt.len == 0); const first_path_idx = for (paths, 0..) |p, idx| { if (p.len != 0) break idx; diff --git a/lib/std/hash/crc.zig b/lib/std/hash/crc.zig index e48b9eac97..83aa013eb4 100644 --- a/lib/std/hash/crc.zig +++ b/lib/std/hash/crc.zig @@ -1,4 +1,5 @@ const std = @import("../std.zig"); +const Writer = std.io.Writer; pub fn Generic(comptime W: type, comptime algorithm: Algorithm(W)) type { return struct { @@ -79,21 +80,18 @@ pub fn Generic(comptime W: type, comptime algorithm: Algorithm(W)) type { return c.final(); } - pub fn writable(self: *Self, buffer: []u8) std.io.BufferedWriter { + pub fn writer(self: *Self, buffer: []u8) Writer { return .{ - .unbuffered_writer = .{ - .context = self, - .vtable = &.{ - .writeSplat = writeSplat, - .writeFile = std.io.Writer.unimplementedWriteFile, - }, - }, + .context = self, + .vtable = &.{ .drain = drain }, .buffer = buffer, }; } - fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { - const self: *Self = @ptrCast(@alignCast(context)); + fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize { + const self: *Self = @ptrCast(@alignCast(w.context)); + self.update(w.buffered()); + w.end = 0; var n: usize = 0; for (data[0 .. data.len - 1]) |slice| { self.update(slice); diff --git a/lib/std/http.zig b/lib/std/http.zig index dd9177d97f..56fad6c502 100644 --- a/lib/std/http.zig +++ b/lib/std/http.zig @@ -1,6 +1,8 @@ const builtin = @import("builtin"); const std = @import("std.zig"); const assert = std.debug.assert; +const Writer = std.io.Writer; +const File = std.fs.File; pub const Client = @import("http/Client.zig"); pub const Server = @import("http/Server.zig"); @@ -504,7 +506,7 @@ pub const Reader = struct { fn contentLengthRead( ctx: ?*anyopaque, - bw: *std.io.BufferedWriter, + bw: *Writer, limit: std.io.Limit, ) std.io.Reader.StreamError!usize { const reader: *Reader = @alignCast(@ptrCast(ctx)); @@ -534,7 +536,7 @@ pub const Reader = struct { fn chunkedRead( ctx: ?*anyopaque, - bw: *std.io.BufferedWriter, + bw: *Writer, limit: std.io.Limit, ) std.io.Reader.StreamError!usize { const reader: *Reader = @alignCast(@ptrCast(ctx)); @@ -559,7 +561,7 @@ pub const Reader = struct { fn chunkedReadEndless( reader: *Reader, - bw: *std.io.BufferedWriter, + bw: *Writer, limit: std.io.Limit, chunk_len_ptr: *RemainingChunkLen, ) (BodyError || std.io.Reader.StreamError)!usize { @@ -747,11 +749,12 @@ pub const Decompressor = struct { pub const BodyWriter = struct { /// Until the lifetime of `BodyWriter` ends, it is illegal to modify the /// state of this other than via methods of `BodyWriter`. - http_protocol_output: *std.io.BufferedWriter, + http_protocol_output: *Writer, state: State, elide: bool, + interface: Writer, - pub const WriteError = std.io.Writer.Error; + pub const Error = Writer.Error; /// How many zeroes to reserve for hex-encoded chunk length. const chunk_len_digits = 8; @@ -787,7 +790,7 @@ pub const BodyWriter = struct { }; /// Sends all buffered data across `BodyWriter.http_protocol_output`. - pub fn flush(w: *BodyWriter) WriteError!void { + pub fn flush(w: *BodyWriter) Error!void { const out = w.http_protocol_output; switch (w.state) { .end, .none, .content_length => return out.flush(), @@ -820,7 +823,7 @@ pub const BodyWriter = struct { /// See also: /// * `endUnflushed` /// * `endChunked` - pub fn end(w: *BodyWriter) WriteError!void { + pub fn end(w: *BodyWriter) Error!void { try endUnflushed(w); try w.http_protocol_output.flush(); } @@ -836,7 +839,7 @@ pub const BodyWriter = struct { /// See also: /// * `end` /// * `endChunked` - pub fn endUnflushed(w: *BodyWriter) WriteError!void { + pub fn endUnflushed(w: *BodyWriter) Error!void { switch (w.state) { .end => unreachable, .content_length => |len| { @@ -862,7 +865,7 @@ pub const BodyWriter = struct { /// See also: /// * `endChunkedUnflushed` /// * `end` - pub fn endChunked(w: *BodyWriter, options: EndChunkedOptions) WriteError!void { + pub fn endChunked(w: *BodyWriter, options: EndChunkedOptions) Error!void { try endChunkedUnflushed(w, options); try w.http_protocol_output.flush(); } @@ -879,7 +882,7 @@ pub const BodyWriter = struct { /// * `endChunked` /// * `endUnflushed` /// * `end` - pub fn endChunkedUnflushed(w: *BodyWriter, options: EndChunkedOptions) WriteError!void { + pub fn endChunkedUnflushed(w: *BodyWriter, options: EndChunkedOptions) Error!void { const chunked = &w.state.chunked; if (w.elide) { w.state = .end; @@ -910,138 +913,78 @@ pub const BodyWriter = struct { w.state = .end; } - fn contentLengthWriteSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) WriteError!usize { - const w: *BodyWriter = @alignCast(@ptrCast(context)); - const n = if (w.elide) countSplat(data, splat) else try w.http_protocol_output.writeSplat(data, splat); + fn contentLengthDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + const bw: *BodyWriter = @fieldParentPtr("interface", w); + assert(!bw.elide); + const out = w.http_protocol_output; + const n = try w.drainTo(out, data, splat); w.state.content_length -= n; return n; } - fn noneWriteSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) WriteError!usize { - const w: *BodyWriter = @alignCast(@ptrCast(context)); - if (w.elide) return countSplat(data, splat); - return w.http_protocol_output.writeSplat(data, splat); - } - - fn countSplat(data: []const []const u8, splat: usize) usize { - if (data.len == 0) return 0; - var total: usize = 0; - for (data[0 .. data.len - 1]) |buf| total += buf.len; - total += data[data.len - 1].len * splat; - return total; - } - - fn elideWriteFile( - file_reader: *std.fs.File.Reader, - limit: std.io.Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, - ) error{ReadFailed}!usize { - var source = file_reader.readable(&.{}); - var n = source.discard(limit) catch |err| switch (err) { - error.ReadFailed => return error.ReadFailed, - error.EndOfStream => { - var n: usize = 0; - for (headers_and_trailers) |bytes| n += bytes.len; - return n; - }, - }; - if (file_reader.size) |size| { - if (size - file_reader.pos == 0) { - // End of file reached. - for (headers_and_trailers) |bytes| n += bytes.len; - return n; - } - } - for (headers_and_trailers[0..headers_len]) |bytes| n += bytes.len; - return n; + fn noneDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + const bw: *BodyWriter = @fieldParentPtr("interface", w); + assert(!bw.elide); + const out = w.http_protocol_output; + return try w.drainTo(out, data, splat); } /// Returns `null` if size cannot be computed without making any syscalls. - fn countWriteFile( - file_reader: *std.fs.File.Reader, - limit: std.io.Limit, - headers_and_trailers: []const []const u8, - ) ?usize { - var total: u64 = @min(@intFromEnum(limit), file_reader.getSize() orelse return null); - for (headers_and_trailers) |bytes| total += bytes.len; - return std.math.lossyCast(usize, total); + fn noneSendFile(w: *Writer, file_reader: *File.Reader, limit: std.io.Limit) Writer.FileError!usize { + const bw: *BodyWriter = @fieldParentPtr("interface", w); + assert(!bw.elide); + return w.sendFileTo(bw.http_protocol_output, file_reader, limit); } - fn noneWriteFile( - context: ?*anyopaque, - file_reader: *std.fs.File.Reader, - limit: std.io.Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, - ) std.io.Writer.FileError!usize { - const w: *BodyWriter = @alignCast(@ptrCast(context)); - if (w.elide) return elideWriteFile(file_reader, limit, headers_and_trailers, headers_len); - return w.http_protocol_output.writeFile(file_reader, limit, headers_and_trailers, headers_len); - } - - fn contentLengthWriteFile( - context: ?*anyopaque, - file_reader: *std.fs.File.Reader, - limit: std.io.Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, - ) std.io.Writer.FileError!usize { - const w: *BodyWriter = @alignCast(@ptrCast(context)); - if (w.elide) return elideWriteFile(file_reader, limit, headers_and_trailers, headers_len); - const n = try w.http_protocol_output.writeFile(file_reader, limit, headers_and_trailers, headers_len); - w.state.content_length -= n; + fn contentLengthSendFile(w: *Writer, file_reader: *File.Reader, limit: std.io.Limit) Writer.FileError!usize { + const bw: *BodyWriter = @fieldParentPtr("interface", w); + assert(!bw.elide); + const n = try w.sendFileTo(bw.http_protocol_output, file_reader, limit); + bw.state.content_length -= n; return n; } - fn chunkedWriteFile( - context: ?*anyopaque, - file_reader: *std.fs.File.Reader, - limit: std.io.Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, - ) std.io.Writer.FileError!usize { - const w: *BodyWriter = @alignCast(@ptrCast(context)); - if (w.elide) return elideWriteFile(file_reader, limit, headers_and_trailers, headers_len); - if (limit == .nothing) return chunkedWriteSplat(context, headers_and_trailers, 1); - const data_len = countWriteFile(file_reader, headers_and_trailers) orelse { + fn chunkedSendFile(w: *Writer, file_reader: *File.Reader, limit: std.io.Limit) Writer.FileError!usize { + const bw: *BodyWriter = @fieldParentPtr("interface", w); + assert(!bw.elide); + const data_len = w.countSendFileUpperBound(file_reader, limit) orelse { // If the file size is unknown, we cannot lower to a `writeFile` since we would // have to flush the chunk header before knowing the chunk length. return error.Unimplemented; }; - const bw = w.http_protocol_output; - const chunked = &w.state.chunked; + const out = bw.http_protocol_output; + const chunked = &bw.state.chunked; state: switch (chunked.*) { .offset => |off| { // TODO: is it better perf to read small files into the buffer? - const buffered_len = bw.end - off - chunk_header_template.len; + const buffered_len = out.end - off - chunk_header_template.len; const chunk_len = data_len + buffered_len; - writeHex(bw.buffer[off..][0..chunk_len_digits], chunk_len); - const n = try bw.writeFile(file_reader, limit, headers_and_trailers, headers_len); + writeHex(out.buffer[off..][0..chunk_len_digits], chunk_len); + const n = try w.sendFileTo(out, file_reader, limit); chunked.* = .{ .chunk_len = data_len + 2 - n }; return n; }, .chunk_len => |chunk_len| l: switch (chunk_len) { 0 => { - const off = bw.end; - const header_buf = try bw.writableArray(chunk_header_template.len); + const off = out.end; + const header_buf = try out.writableArray(chunk_header_template.len); @memcpy(header_buf, chunk_header_template); chunked.* = .{ .offset = off }; continue :state .{ .offset = off }; }, 1 => { - try bw.writeByte('\n'); + try out.writeByte('\n'); chunked.chunk_len = 0; continue :l 0; }, 2 => { - try bw.writeByte('\r'); + try out.writeByte('\r'); chunked.chunk_len = 1; continue :l 1; }, else => { const new_limit = limit.min(.limited(chunk_len - 2)); - const n = try bw.writeFile(file_reader, new_limit, headers_and_trailers, headers_len); + const n = try w.sendFileTo(out, file_reader, new_limit); chunked.chunk_len = chunk_len - n; return n; }, @@ -1049,47 +992,45 @@ pub const BodyWriter = struct { } } - fn chunkedWriteSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) WriteError!usize { - const w: *BodyWriter = @alignCast(@ptrCast(context)); - const data_len = countSplat(data, splat); - if (w.elide) return data_len; - - const bw = w.http_protocol_output; - const chunked = &w.state.chunked; - + fn chunkedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + const bw: *BodyWriter = @fieldParentPtr("interface", w); + assert(!bw.elide); + const out = w.http_protocol_output; + const data_len = Writer.countSplat(w.end, data, splat); + const chunked = &bw.state.chunked; state: switch (chunked.*) { .offset => |offset| { - if (bw.unusedCapacitySlice().len >= data_len) { - assert(data_len == (bw.writeSplat(data, splat) catch unreachable)); + if (out.unusedCapacityLen() >= data_len) { + assert(data_len == (w.drainTo(out, data, splat) catch unreachable)); return data_len; } - const buffered_len = bw.end - offset - chunk_header_template.len; + const buffered_len = out.end - offset - chunk_header_template.len; const chunk_len = data_len + buffered_len; - writeHex(bw.buffer[offset..][0..chunk_len_digits], chunk_len); - const n = try bw.writeSplat(data, splat); + writeHex(out.buffer[offset..][0..chunk_len_digits], chunk_len); + const n = try w.drainTo(w, data, splat); chunked.* = .{ .chunk_len = data_len + 2 - n }; return n; }, .chunk_len => |chunk_len| l: switch (chunk_len) { 0 => { - const offset = bw.end; - const header_buf = try bw.writableArray(chunk_header_template.len); + const offset = out.end; + const header_buf = try out.writableArray(chunk_header_template.len); @memcpy(header_buf, chunk_header_template); chunked.* = .{ .offset = offset }; continue :state .{ .offset = offset }; }, 1 => { - try bw.writeByte('\n'); + try out.writeByte('\n'); chunked.chunk_len = 0; continue :l 0; }, 2 => { - try bw.writeByte('\r'); + try out.writeByte('\r'); chunked.chunk_len = 1; continue :l 1; }, else => { - const n = try bw.writeSplatLimit(data, splat, .limited(chunk_len - 2)); + const n = try w.drainToLimit(data, splat, .limited(chunk_len - 2)); chunked.chunk_len = chunk_len - n; return n; }, @@ -1112,21 +1053,21 @@ pub const BodyWriter = struct { } } - pub fn writer(w: *BodyWriter) std.io.Writer { - return .{ + pub fn writer(w: *BodyWriter) Writer { + return if (w.elide) .discarding else .{ .context = w, .vtable = switch (w.state) { .none => &.{ - .writeSplat = noneWriteSplat, - .writeFile = noneWriteFile, + .drain = noneDrain, + .sendFile = noneSendFile, }, .content_length => &.{ - .writeSplat = contentLengthWriteSplat, - .writeFile = contentLengthWriteFile, + .drain = contentLengthDrain, + .sendFile = contentLengthSendFile, }, .chunked => &.{ - .writeSplat = chunkedWriteSplat, - .writeFile = chunkedWriteFile, + .drain = chunkedDrain, + .sendFile = chunkedSendFile, }, .end => unreachable, }, diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig index 2fc7432bd1..35ae366c96 100644 --- a/lib/std/http/Client.zig +++ b/lib/std/http/Client.zig @@ -13,6 +13,7 @@ const net = std.net; const Uri = std.Uri; const Allocator = mem.Allocator; const assert = std.debug.assert; +const Writer = std.io.Writer; const Client = @This(); @@ -229,7 +230,7 @@ pub const Connection = struct { stream_reader: net.Stream.Reader, /// HTTP protocol from client to server. /// This either goes directly to `stream_writer`, or to a TLS client. - writer: std.io.BufferedWriter, + writer: Writer, /// HTTP protocol from server to client. /// This either comes directly from `stream_reader`, or from a TLS client. reader: std.io.Reader, @@ -297,7 +298,7 @@ pub const Connection = struct { const Tls = struct { /// Data from `client` to `Connection.stream`. - writer: std.io.BufferedWriter, + writer: Writer, /// Data from `Connection.stream` to `client`. reader: std.io.Reader, client: std.crypto.tls.Client, @@ -403,7 +404,7 @@ pub const Connection = struct { } } - pub fn flush(c: *Connection) std.io.Writer.Error!void { + pub fn flush(c: *Connection) Writer.Error!void { try c.writer.flush(); if (c.protocol == .tls) { if (disable_tls) unreachable; @@ -415,7 +416,7 @@ pub const Connection = struct { /// If the connection is a TLS connection, sends the close_notify alert. /// /// Flushes all buffers. - pub fn end(c: *Connection) std.io.Writer.Error!void { + pub fn end(c: *Connection) Writer.Error!void { try c.writer.flush(); if (c.protocol == .tls) { if (disable_tls) unreachable; @@ -818,13 +819,13 @@ pub const Request = struct { } /// Sends and flushes a complete request as only HTTP head, no body. - pub fn sendBodiless(r: *Request) std.io.Writer.Error!void { + pub fn sendBodiless(r: *Request) Writer.Error!void { try sendBodilessUnflushed(r); try r.connection.?.flush(); } /// Sends but does not flush a complete request as only HTTP head, no body. - pub fn sendBodilessUnflushed(r: *Request) std.io.Writer.Error!void { + pub fn sendBodilessUnflushed(r: *Request) Writer.Error!void { assert(r.transfer_encoding == .none); assert(!r.method.requestHasBody()); try sendHead(r); @@ -834,7 +835,7 @@ pub const Request = struct { /// /// See also: /// * `sendBodyUnflushed` - pub fn sendBody(r: *Request) std.io.Writer.Error!http.BodyWriter { + pub fn sendBody(r: *Request) Writer.Error!http.BodyWriter { const result = try sendBodyUnflushed(r); try r.connection.?.flush(); return result; @@ -845,7 +846,7 @@ pub const Request = struct { /// /// See also: /// * `sendBody` - pub fn sendBodyUnflushed(r: *Request) std.io.Writer.Error!http.BodyWriter { + pub fn sendBodyUnflushed(r: *Request) Writer.Error!http.BodyWriter { assert(r.method.requestHasBody()); try sendHead(r); return .{ @@ -860,7 +861,7 @@ pub const Request = struct { } /// Sends HTTP headers without flushing. - fn sendHead(r: *Request) std.io.Writer.Error!void { + fn sendHead(r: *Request) Writer.Error!void { const uri = r.uri; const connection = r.connection.?; const w = &connection.writer; @@ -1134,7 +1135,7 @@ pub const Request = struct { /// Returns true if the default behavior is required, otherwise handles /// writing (or not writing) the header. - fn emitOverridableHeader(prefix: []const u8, v: Headers.Value, bw: *std.io.BufferedWriter) std.io.Writer.Error!bool { + fn emitOverridableHeader(prefix: []const u8, v: Headers.Value, bw: *Writer) Writer.Error!bool { switch (v) { .default => return true, .omit => return false, @@ -1242,16 +1243,14 @@ pub const basic_authorization = struct { } pub fn value(uri: Uri, out: []u8) []u8 { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(out); + var bw: Writer = .fixed(out); write(uri, &bw) catch unreachable; return bw.getWritten(); } - pub fn write(uri: Uri, out: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(uri: Uri, out: *Writer) Writer.Error!void { var buf: [max_user_len + ":".len + max_password_len]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buf); + var bw: Writer = .fixed(&buf); bw.print("{fuser}:{fpassword}", .{ uri.user orelse Uri.Component.empty, uri.password orelse Uri.Component.empty, diff --git a/lib/std/http/Server.zig b/lib/std/http/Server.zig index 67d7b9ec12..f4b29d2d8b 100644 --- a/lib/std/http/Server.zig +++ b/lib/std/http/Server.zig @@ -6,11 +6,12 @@ const mem = std.mem; const Uri = std.Uri; const assert = std.debug.assert; const testing = std.testing; +const Writer = std.io.Writer; const Server = @This(); /// Data from the HTTP server to the HTTP client. -out: *std.io.BufferedWriter, +out: *Writer, reader: http.Reader, /// Initialize an HTTP server that can respond to multiple requests on the same @@ -20,7 +21,7 @@ reader: http.Reader, /// header, otherwise `receiveHead` returns `error.HttpHeadersOversize`. /// /// The returned `Server` is ready for `receiveHead` to be called. -pub fn init(in: *std.io.Reader, out: *std.io.BufferedWriter) Server { +pub fn init(in: *std.io.Reader, out: *Writer) Server { return .{ .reader = .{ .in = in, @@ -397,7 +398,7 @@ pub const Request = struct { /// be done to satisfy the request. /// /// Asserts status is not `continue`. - pub fn respondStreaming(request: *Request, options: RespondStreamingOptions) std.io.Writer.Error!http.BodyWriter { + pub fn respondStreaming(request: *Request, options: RespondStreamingOptions) Writer.Error!http.BodyWriter { try writeExpectContinue(request); const o = options.respond_options; assert(o.status != .@"continue"); @@ -485,7 +486,7 @@ pub const Request = struct { /// The header is not guaranteed to be sent until `WebSocket.flush` is /// called on the returned struct. - pub fn respondWebSocket(request: *Request, options: WebSocketOptions) std.io.Writer.Error!WebSocket { + pub fn respondWebSocket(request: *Request, options: WebSocketOptions) Writer.Error!WebSocket { if (request.head.expect != null) return error.HttpExpectationFailed; const out = request.server.out; @@ -611,7 +612,7 @@ pub const Request = struct { pub const WebSocket = struct { key: []const u8, input: *std.io.Reader, - output: *std.io.BufferedWriter, + output: *Writer, pub const Header0 = packed struct(u8) { opcode: Opcode, @@ -701,21 +702,21 @@ pub const WebSocket = struct { } } - pub fn writeMessage(ws: *WebSocket, data: []const u8, op: Opcode) std.io.Writer.Error!void { + pub fn writeMessage(ws: *WebSocket, data: []const u8, op: Opcode) Writer.Error!void { try writeMessageVecUnflushed(ws, &.{data}, op); try ws.output.flush(); } - pub fn writeMessageUnflushed(ws: *WebSocket, data: []const u8, op: Opcode) std.io.Writer.Error!void { + pub fn writeMessageUnflushed(ws: *WebSocket, data: []const u8, op: Opcode) Writer.Error!void { try writeMessageVecUnflushed(ws, &.{data}, op); } - pub fn writeMessageVec(ws: *WebSocket, data: []const []const u8, op: Opcode) std.io.Writer.Error!void { + pub fn writeMessageVec(ws: *WebSocket, data: []const []const u8, op: Opcode) Writer.Error!void { try writeMessageVecUnflushed(ws, data, op); try ws.output.flush(); } - pub fn writeMessageVecUnflushed(ws: *WebSocket, data: []const []const u8, op: Opcode) std.io.Writer.Error!void { + pub fn writeMessageVecUnflushed(ws: *WebSocket, data: []const []const u8, op: Opcode) Writer.Error!void { const total_len = l: { var total_len: u64 = 0; for (data) |iovec| total_len += iovec.len; @@ -749,7 +750,7 @@ pub const WebSocket = struct { try out.writeVecAll(data); } - pub fn flush(ws: *WebSocket) std.io.Writer.Error!void { + pub fn flush(ws: *WebSocket) Writer.Error!void { try ws.output.flush(); } }; diff --git a/lib/std/io.zig b/lib/std/io.zig index e907524c0b..8dcde79069 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -72,8 +72,6 @@ pub const Limit = enum(usize) { pub const Reader = @import("io/Reader.zig"); pub const Writer = @import("io/Writer.zig"); -pub const AllocatingWriter = @import("io/AllocatingWriter.zig"); - pub const ChangeDetectionStream = @import("io/change_detection_stream.zig").ChangeDetectionStream; pub const changeDetectionStream = @import("io/change_detection_stream.zig").changeDetectionStream; @@ -485,7 +483,6 @@ pub fn PollFiles(comptime StreamEnum: type) type { } test { - _ = AllocatingWriter; _ = Reader; _ = Writer; _ = @import("io/test.zig"); diff --git a/lib/std/io/AllocatingWriter.zig b/lib/std/io/AllocatingWriter.zig deleted file mode 100644 index dc10620e78..0000000000 --- a/lib/std/io/AllocatingWriter.zig +++ /dev/null @@ -1,215 +0,0 @@ -//! While it is possible to use `std.ArrayList` as the underlying writer when -//! using `std.io.BufferedWriter` by populating the `std.io.Writer` interface -//! and then using an empty buffer, it means that every use of -//! `std.io.BufferedWriter` will go through the vtable, including for -//! functions such as `writeByte`. This API instead maintains -//! `std.io.BufferedWriter` state such that it writes to the unused capacity of -//! an array list, filling it up completely before making a call through the -//! vtable, causing a resize. Consequently, the same, optimized, non-generic -//! machine code that uses `std.io.Reader`, such as formatted printing, -//! takes the hot paths when using this API. - -const std = @import("../std.zig"); -const AllocatingWriter = @This(); -const assert = std.debug.assert; - -/// This is missing the data stored in `buffered_writer`. See `getWritten` for -/// returning a slice that includes both. -written: []u8, -allocator: std.mem.Allocator, -/// When using this API, it is not necessary to call -/// `std.io.BufferedWriter.flush`. -buffered_writer: std.io.BufferedWriter, - -const vtable: std.io.Writer.VTable = .{ - .writeSplat = writeSplat, - .writeFile = writeFile, -}; - -/// Sets the `AllocatingWriter` to an empty state. -pub fn init(aw: *AllocatingWriter, allocator: std.mem.Allocator) void { - aw.initOwnedSlice(allocator, &.{}); -} - -pub fn initCapacity(aw: *AllocatingWriter, allocator: std.mem.Allocator, capacity: usize) error{OutOfMemory}!void { - const initial_buffer = try allocator.alloc(u8, capacity); - aw.initOwnedSlice(allocator, initial_buffer); -} - -pub fn initOwnedSlice(aw: *AllocatingWriter, allocator: std.mem.Allocator, slice: []u8) void { - aw.* = .{ - .written = slice[0..0], - .allocator = allocator, - .buffered_writer = .{ - .unbuffered_writer = .{ - .context = aw, - .vtable = &vtable, - }, - .buffer = slice, - }, - }; -} - -pub fn deinit(aw: *AllocatingWriter) void { - const written = aw.written; - aw.allocator.free(written.ptr[0 .. written.len + aw.buffered_writer.buffer.len]); - aw.* = undefined; -} - -/// Replaces `array_list` with empty, taking ownership of the memory. -pub fn fromArrayList( - aw: *AllocatingWriter, - allocator: std.mem.Allocator, - array_list: *std.ArrayListUnmanaged(u8), -) *std.io.BufferedWriter { - aw.* = .{ - .written = array_list.items, - .allocator = allocator, - .buffered_writer = .{ - .unbuffered_writer = .{ - .context = aw, - .vtable = &vtable, - }, - .buffer = array_list.unusedCapacitySlice(), - }, - }; - array_list.* = .empty; - return &aw.buffered_writer; -} - -/// Returns an array list that takes ownership of the allocated memory. -/// Resets the `AllocatingWriter` to an empty state. -pub fn toArrayList(aw: *AllocatingWriter) std.ArrayListUnmanaged(u8) { - const bw = &aw.buffered_writer; - const written = aw.written; - const result: std.ArrayListUnmanaged(u8) = .{ - .items = written.ptr[0 .. written.len + bw.end], - .capacity = written.len + bw.buffer.len, - }; - aw.written = &.{}; - bw.buffer = &.{}; - bw.end = 0; - return result; -} - -pub fn toOwnedSlice(aw: *AllocatingWriter) error{OutOfMemory}![]u8 { - var list = aw.toArrayList(); - return list.toOwnedSlice(aw.allocator); -} - -pub fn toOwnedSliceSentinel(aw: *AllocatingWriter, comptime sentinel: u8) error{OutOfMemory}![:sentinel]u8 { - const gpa = aw.allocator; - var list = toArrayList(aw); - return list.toOwnedSliceSentinel(gpa, sentinel); -} - -fn setArrayList(aw: *AllocatingWriter, list: std.ArrayListUnmanaged(u8)) void { - aw.written = list.items; - aw.buffered_writer.buffer = list.unusedCapacitySlice(); -} - -pub fn getWritten(aw: *AllocatingWriter) []u8 { - const bw = &aw.buffered_writer; - const end = aw.buffered_writer.end; - const written = aw.written.ptr[0 .. aw.written.len + end]; - aw.written = written; - bw.buffer = bw.buffer[end..]; - bw.end = 0; - return written; -} - -pub fn shrinkRetainingCapacity(aw: *AllocatingWriter, new_len: usize) void { - const bw = &aw.buffered_writer; - bw.buffer = aw.written.ptr[new_len .. aw.written.len + bw.buffer.len]; - bw.end = 0; - aw.written.len = new_len; -} - -pub fn clearRetainingCapacity(aw: *AllocatingWriter) void { - aw.shrinkRetainingCapacity(0); -} - -fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { - assert(data.len != 0); - const aw: *AllocatingWriter = @alignCast(@ptrCast(context)); - const start_len = aw.written.len; - const bw = &aw.buffered_writer; - const skip_first = data[0].ptr == aw.written.ptr + start_len; - const items_len = if (skip_first) start_len + data[0].len else start_len; - var list: std.ArrayListUnmanaged(u8) = .{ - .items = aw.written.ptr[0..items_len], - .capacity = start_len + bw.buffer.len, - }; - defer setArrayList(aw, list); - const rest = if (splat == 0) data[1 .. data.len - 1] else data[1..]; - const pattern = data[data.len - 1]; - const remaining_splat = splat - 1; - var new_capacity: usize = list.capacity + pattern.len * remaining_splat; - for (rest) |bytes| new_capacity += bytes.len; - list.ensureTotalCapacity(aw.allocator, new_capacity + 1) catch return error.WriteFailed; - for (rest) |bytes| list.appendSliceAssumeCapacity(bytes); - if (pattern.len == 1) { - list.appendNTimesAssumeCapacity(pattern[0], remaining_splat); - } else { - for (0..remaining_splat) |_| list.appendSliceAssumeCapacity(pattern); - } - aw.written = list.items; - bw.buffer = list.unusedCapacitySlice(); - return list.items.len - start_len; -} - -fn writeFile( - context: ?*anyopaque, - file_reader: *std.fs.File.Reader, - limit: std.io.Limit, - headers_and_trailers_full: []const []const u8, - headers_len_full: usize, -) std.io.Writer.FileError!usize { - if (std.fs.File.Handle == void) return error.Unimplemented; - const aw: *AllocatingWriter = @alignCast(@ptrCast(context)); - const gpa = aw.allocator; - var list = aw.toArrayList(); - defer setArrayList(aw, list); - const start_len = list.items.len; - const headers_and_trailers, const headers_len = if (headers_len_full >= 1) b: { - assert(headers_and_trailers_full[0].ptr == list.items.ptr + start_len); - list.items.len += headers_and_trailers_full[0].len; - break :b .{ headers_and_trailers_full[1..], headers_len_full - 1 }; - } else .{ headers_and_trailers_full, headers_len_full }; - const trailers = headers_and_trailers[headers_len..]; - const pos = file_reader.pos; - - const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line; - var new_capacity: usize = list.capacity + limit.minInt(additional); - for (headers_and_trailers) |bytes| new_capacity += bytes.len; - list.ensureTotalCapacity(gpa, new_capacity) catch return error.WriteFailed; - for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); - const dest = limit.slice(list.items.ptr[list.items.len..list.capacity]); - const n = file_reader.read(dest) catch |err| switch (err) { - error.ReadFailed => return error.ReadFailed, - error.EndOfStream => 0, - }; - const is_end = if (file_reader.getSize()) |size| n >= size - pos else |_| n == 0; - if (is_end) { - new_capacity = list.capacity; - for (trailers) |bytes| new_capacity += bytes.len; - list.ensureTotalCapacity(gpa, new_capacity) catch return error.WriteFailed; - for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes); - } else { - list.items.len += n; - } - return list.items.len - start_len; -} - -test AllocatingWriter { - var aw: AllocatingWriter = undefined; - aw.init(std.testing.allocator); - defer aw.deinit(); - const bw = &aw.buffered_writer; - - const x: i32 = 42; - const y: i32 = 1234; - try bw.print("x: {}\ny: {}\n", .{ x, y }); - - try std.testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", aw.getWritten()); -} diff --git a/lib/std/io/BufferedWriter.zig b/lib/std/io/BufferedWriter.zig deleted file mode 100644 index 38abbfa40f..0000000000 --- a/lib/std/io/BufferedWriter.zig +++ /dev/null @@ -1,1859 +0,0 @@ -const std = @import("../std.zig"); -const BufferedWriter = @This(); -const assert = std.debug.assert; -const native_endian = @import("builtin").target.cpu.arch.endian(); -const Writer = std.io.Writer; -const Allocator = std.mem.Allocator; -const testing = std.testing; -const Limit = std.io.Limit; -const File = std.fs.File; - -/// Underlying stream to send bytes to. -/// -/// A write will only be sent here if it could not fit into `buffer`, or if it -/// is a `writeFile`. -/// -/// `unbuffered_writer` may modify `buffer` if the number of bytes returned -/// equals number of bytes provided. This property is exploited by -/// `std.io.AllocatingWriter` for example. -unbuffered_writer: Writer, -/// If this has length zero, the writer is unbuffered, and `flush` is a no-op. -buffer: []u8, -/// In `buffer` before this are buffered bytes, after this is `undefined`. -end: usize = 0, -/// Tracks total number of bytes written to this `BufferedWriter`. This value -/// only increases. In the case of fixed mode, this value always equals `end`. -count: usize = 0, - -/// Number of slices to store on the stack, when trying to send as many byte -/// vectors through the underlying write calls as possible. -pub const max_buffers_len = 8; - -/// Although `BufferedWriter` can easily satisfy the `Writer` interface, it's -/// generally more practical to pass a `BufferedWriter` instance itself around, -/// since it will result in fewer calls across vtable boundaries. -pub fn writer(bw: *BufferedWriter) Writer { - return .{ - .context = bw, - .vtable = &.{ - .writeSplat = passthruWriteSplat, - .writeFile = passthruWriteFile, - }, - }; -} - -const fixed_vtable: Writer.VTable = .{ - .writeSplat = fixedWriteSplat, - .writeFile = Writer.unimplementedWriteFile, -}; - -/// Replaces the `BufferedWriter` with one that writes to `buffer` and returns -/// `error.WriteFailed` when it is full. `end` and `count` will always be -/// equal. -pub fn initFixed(bw: *BufferedWriter, buffer: []u8) void { - bw.* = .{ - .unbuffered_writer = .{ - .context = bw, - .vtable = &fixed_vtable, - }, - .buffer = buffer, - }; -} - -pub fn hashed(bw: *BufferedWriter, hasher: anytype) Writer.Hashed(@TypeOf(hasher)) { - return .{ .out = bw, .hasher = hasher }; -} - -/// This function is available when using `initFixed`. -pub fn getWritten(bw: *const BufferedWriter) []u8 { - assert(bw.unbuffered_writer.vtable == &fixed_vtable); - return bw.buffer[0..bw.end]; -} - -/// This function is available when using `initFixed`. -pub fn reset(bw: *BufferedWriter) void { - assert(bw.unbuffered_writer.vtable == &fixed_vtable); - bw.end = 0; - bw.count = 0; -} - -pub fn flush(bw: *BufferedWriter) Writer.Error!void { - const send_buffer = bw.buffer[0..bw.end]; - var index: usize = 0; - while (index < send_buffer.len) index += try bw.unbuffered_writer.writeVec(&.{send_buffer[index..]}); - bw.end = 0; -} - -pub fn flushLimit(bw: *BufferedWriter, limit: Limit) Writer.Error!void { - const buffer = limit.slice(bw.buffer[0..bw.end]); - var index: usize = 0; - while (index < buffer.len) index += try bw.unbuffered_writer.writeVec(&.{buffer[index..]}); - const remainder = bw.buffer[index..]; - std.mem.copyForwards(u8, bw.buffer[0..remainder.len], remainder); - bw.end = remainder.len; -} - -pub fn unusedCapacitySlice(bw: *const BufferedWriter) []u8 { - return bw.buffer[bw.end..]; -} - -/// Asserts the provided buffer has total capacity enough for `len`. -/// -/// Advances the buffer end position by `len`. -pub fn writableArray(bw: *BufferedWriter, comptime len: usize) Writer.Error!*[len]u8 { - const big_slice = try bw.writableSliceGreedy(len); - advance(bw, len); - return big_slice[0..len]; -} - -/// Asserts the provided buffer has total capacity enough for `len`. -/// -/// Advances the buffer end position by `len`. -pub fn writableSlice(bw: *BufferedWriter, len: usize) Writer.Error![]u8 { - const big_slice = try bw.writableSliceGreedy(len); - advance(bw, len); - return big_slice[0..len]; -} - -/// Asserts the provided buffer has total capacity enough for `minimum_length`. -/// -/// Does not `advance` the buffer end position. -/// -/// If `minimum_length` is zero, this is equivalent to `unusedCapacitySlice`. -pub fn writableSliceGreedy(bw: *BufferedWriter, minimum_length: usize) Writer.Error![]u8 { - assert(bw.buffer.len >= minimum_length); - const cap_slice = bw.buffer[bw.end..]; - if (cap_slice.len >= minimum_length) { - @branchHint(.likely); - return cap_slice; - } - const buffer = bw.buffer[0..bw.end]; - const n = try bw.unbuffered_writer.writeVec(&.{buffer}); - if (n == buffer.len) { - @branchHint(.likely); - bw.end = 0; - return bw.buffer; - } - if (n > 0) { - const remainder = buffer[n..]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - } - return bw.buffer[bw.end..]; -} - -pub fn ensureUnusedCapacity(bw: *BufferedWriter, n: usize) Writer.Error!void { - _ = try writableSliceGreedy(bw, n); -} - -pub fn undo(bw: *BufferedWriter, n: usize) void { - bw.end -= n; - bw.count -= n; -} - -/// After calling `writableSliceGreedy`, this function tracks how many bytes -/// were written to it. -/// -/// This is not needed when using `writableSlice` or `writableArray`. -pub fn advance(bw: *BufferedWriter, n: usize) void { - const new_end = bw.end + n; - assert(new_end <= bw.buffer.len); - bw.end = new_end; - bw.count += n; -} - -/// The `data` parameter is mutable because this function needs to mutate the -/// fields in order to handle partial writes from `Writer.VTable.writeSplat`. -pub fn writeVecAll(bw: *BufferedWriter, data: [][]const u8) Writer.Error!void { - var index: usize = 0; - var truncate: usize = 0; - while (index < data.len) { - { - const untruncated = data[index]; - data[index] = untruncated[truncate..]; - defer data[index] = untruncated; - truncate += try bw.writeVec(data[index..]); - } - while (index < data.len and truncate >= data[index].len) { - truncate -= data[index].len; - index += 1; - } - } -} - -/// The `data` parameter is mutable because this function needs to mutate the -/// fields in order to handle partial writes from `Writer.VTable.writeSplat`. -pub fn writeSplatAll(bw: *BufferedWriter, data: [][]const u8, splat: usize) Writer.Error!void { - var index: usize = 0; - var truncate: usize = 0; - var remaining_splat = splat; - while (index + 1 < data.len) { - { - const untruncated = data[index]; - data[index] = untruncated[truncate..]; - defer data[index] = untruncated; - truncate += try bw.writeSplat(data[index..], remaining_splat); - } - while (truncate >= data[index].len) { - if (index + 1 < data.len) { - truncate -= data[index].len; - index += 1; - } else { - const last = data[data.len - 1]; - remaining_splat -= @divExact(truncate, last.len); - while (remaining_splat > 0) { - const n = try bw.writeSplat(data[data.len - 1 ..][0..1], remaining_splat); - remaining_splat -= @divExact(n, last.len); - } - return; - } - } - } -} - -/// If the number of bytes to write based on `data` and `splat` fits inside -/// `unusedCapacitySlice`, this function is guaranteed to not fail, not call -/// into the underlying writer, and return the full number of bytes. -pub fn writeSplat(bw: *BufferedWriter, data: []const []const u8, splat: usize) Writer.Error!usize { - return passthruWriteSplat(bw, data, splat); -} - -/// If the total number of bytes of `data` fits inside `unusedCapacitySlice`, -/// this function is guaranteed to not fail, not call into the underlying -/// writer, and return the total bytes inside `data`. -pub fn writeVec(bw: *BufferedWriter, data: []const []const u8) Writer.Error!usize { - return passthruWriteSplat(bw, data, 1); -} - -/// Equivalent to `writeSplat` but writes at most `limit` bytes. -pub fn writeSplatLimit( - bw: *BufferedWriter, - data: []const []const u8, - splat: usize, - limit: Limit, -) Writer.Error!usize { - _ = bw; - _ = data; - _ = splat; - _ = limit; - @panic("TODO"); -} - -fn passthruWriteSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Writer.Error!usize { - const bw: *BufferedWriter = @alignCast(@ptrCast(context)); - const buffer = bw.buffer; - const start_end = bw.end; - - var buffers: [max_buffers_len][]const u8 = undefined; - var end = start_end; - for (data, 0..) |bytes, i| { - const new_end = end + bytes.len; - if (new_end <= buffer.len) { - @branchHint(.likely); - @memcpy(buffer[end..new_end], bytes); - end = new_end; - continue; - } - if (end == 0) return track(&bw.count, try bw.unbuffered_writer.writeSplat(data, splat)); - buffers[0] = buffer[0..end]; - const remaining_data = data[i..]; - const remaining_buffers = buffers[1..]; - const len: usize = @min(remaining_data.len, remaining_buffers.len); - @memcpy(remaining_buffers[0..len], remaining_data[0..len]); - const send_buffers = buffers[0 .. len + 1]; - if (len >= remaining_data.len) { - @branchHint(.likely); - // Made it past the headers, so we can enable splatting. - const n = try bw.unbuffered_writer.writeSplat(send_buffers, splat); - if (n < end) { - @branchHint(.unlikely); - const remainder = buffer[n..end]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - return track(&bw.count, end - start_end); - } - bw.end = 0; - return track(&bw.count, n - start_end); - } - const n = try bw.unbuffered_writer.writeSplat(send_buffers, 1); - if (n < end) { - @branchHint(.unlikely); - const remainder = buffer[n..end]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - return track(&bw.count, end - start_end); - } - bw.end = 0; - return track(&bw.count, n - start_end); - } - - const pattern = data[data.len - 1]; - - if (splat == 0) { - @branchHint(.unlikely); - // It was added in the loop above; undo it here. - end -= pattern.len; - bw.end = end; - return track(&bw.count, end - start_end); - } - - const remaining_splat = splat - 1; - - switch (pattern.len) { - 0 => { - bw.end = end; - return track(&bw.count, end - start_end); - }, - 1 => { - const new_end = end + remaining_splat; - if (new_end <= buffer.len) { - @branchHint(.likely); - @memset(buffer[end..new_end], pattern[0]); - bw.end = new_end; - return track(&bw.count, new_end - start_end); - } - buffers[0] = buffer[0..end]; - buffers[1] = pattern; - const n = try bw.unbuffered_writer.writeSplat(buffers[0..2], remaining_splat); - if (n < end) { - @branchHint(.unlikely); - const remainder = buffer[n..end]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - return track(&bw.count, end - start_end); - } - bw.end = 0; - return track(&bw.count, n - start_end); - }, - else => { - const new_end = end + pattern.len * remaining_splat; - if (new_end <= buffer.len) { - @branchHint(.likely); - while (end < new_end) : (end += pattern.len) { - @memcpy(buffer[end..][0..pattern.len], pattern); - } - bw.end = new_end; - return track(&bw.count, new_end - start_end); - } - buffers[0] = buffer[0..end]; - buffers[1] = pattern; - const n = try bw.unbuffered_writer.writeSplat(buffers[0..2], remaining_splat); - if (n < end) { - @branchHint(.unlikely); - const remainder = buffer[n..end]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - return track(&bw.count, end - start_end); - } - bw.end = 0; - return track(&bw.count, n - start_end); - }, - } -} - -fn track(count: *usize, n: usize) usize { - count.* += n; - return n; -} - -/// When this function is called it means the buffer got full, so it's time -/// to return an error. However, we still need to make sure all of the -/// available buffer has been filled. -fn fixedWriteSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Writer.Error!usize { - const bw: *BufferedWriter = @alignCast(@ptrCast(context)); - for (data) |bytes| { - const dest = bw.buffer[bw.end..]; - if (dest.len == 0) return error.WriteFailed; - const len = @min(bytes.len, dest.len); - @memcpy(dest[0..len], bytes[0..len]); - bw.end += len; - bw.count = bw.end; - } - const pattern = data[data.len - 1]; - const dest = bw.buffer[bw.end..]; - switch (pattern.len) { - 0 => unreachable, - 1 => @memset(dest, pattern[0]), - else => for (0..splat - 1) |i| @memcpy(dest[i * pattern.len ..][0..pattern.len], pattern), - } - bw.end = bw.buffer.len; - bw.count = bw.end; - return error.WriteFailed; -} - -pub fn write(bw: *BufferedWriter, bytes: []const u8) Writer.Error!usize { - const buffer = bw.buffer; - const end = bw.end; - const new_end = end + bytes.len; - if (new_end > buffer.len) { - var data: [2][]const u8 = .{ buffer[0..end], bytes }; - const n = try bw.unbuffered_writer.writeVec(&data); - if (n < end) { - @branchHint(.unlikely); - const remainder = buffer[n..end]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - return 0; - } - bw.end = 0; - return track(&bw.count, n - end); - } - @memcpy(buffer[end..new_end], bytes); - bw.end = new_end; - return track(&bw.count, bytes.len); -} - -/// Calls `write` as many times as necessary such that all of `bytes` are -/// transferred. -pub fn writeAll(bw: *BufferedWriter, bytes: []const u8) Writer.Error!void { - var index: usize = 0; - while (index < bytes.len) index += try bw.write(bytes[index..]); -} - -pub fn print(bw: *BufferedWriter, comptime format: []const u8, args: anytype) Writer.Error!void { - try std.fmt.format(bw, format, args); -} - -pub fn writeByte(bw: *BufferedWriter, byte: u8) Writer.Error!void { - const buffer = bw.buffer[0..bw.end]; - if (buffer.len < bw.buffer.len) { - @branchHint(.likely); - buffer.ptr[buffer.len] = byte; - bw.end = buffer.len + 1; - bw.count += 1; - return; - } - var buffers: [2][]const u8 = .{ buffer, &.{byte} }; - while (true) { - const n = try bw.unbuffered_writer.writeVec(&buffers); - if (n == 0) { - @branchHint(.unlikely); - continue; - } - bw.count += 1; - if (n >= buffer.len) { - @branchHint(.likely); - if (n > buffer.len) { - @branchHint(.likely); - bw.end = 0; - return; - } else { - buffer[0] = byte; - bw.end = 1; - return; - } - } - const remainder = buffer[n..]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - buffer[remainder.len] = byte; - bw.end = remainder.len + 1; - return; - } -} - -/// Writes the same byte many times, performing the underlying write call as -/// many times as necessary. -pub fn splatByteAll(bw: *BufferedWriter, byte: u8, n: usize) Writer.Error!void { - var remaining: usize = n; - while (remaining > 0) remaining -= try bw.splatByte(byte, remaining); -} - -/// Writes the same byte many times, allowing short writes. -/// -/// Does maximum of one underlying `Writer.VTable.writeSplat`. -pub fn splatByte(bw: *BufferedWriter, byte: u8, n: usize) Writer.Error!usize { - return passthruWriteSplat(bw, &.{&.{byte}}, n); -} - -/// Writes the same slice many times, performing the underlying write call as -/// many times as necessary. -pub fn splatBytesAll(bw: *BufferedWriter, bytes: []const u8, splat: usize) Writer.Error!void { - var remaining_bytes: usize = bytes.len * splat; - remaining_bytes -= try bw.splatBytes(bytes, splat); - while (remaining_bytes > 0) { - const leftover = remaining_bytes % bytes.len; - const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes }; - remaining_bytes -= try bw.splatBytes(&buffers, splat); - } -} - -/// Writes the same slice many times, allowing short writes. -/// -/// Does maximum of one underlying `Writer.VTable.writeSplat`. -pub fn splatBytes(bw: *BufferedWriter, bytes: []const u8, n: usize) Writer.Error!usize { - return passthruWriteSplat(bw, &.{bytes}, n); -} - -/// Asserts the `buffer` was initialized with a capacity of at least `@sizeOf(T)` bytes. -pub inline fn writeInt(bw: *BufferedWriter, comptime T: type, value: T, endian: std.builtin.Endian) Writer.Error!void { - var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined; - std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); - return bw.writeAll(&bytes); -} - -pub fn writeStruct(bw: *BufferedWriter, value: anytype) Writer.Error!void { - // Only extern and packed structs have defined in-memory layout. - comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto); - return bw.writeAll(std.mem.asBytes(&value)); -} - -/// The function is inline to avoid the dead code in case `endian` is -/// comptime-known and matches host endianness. -/// TODO: make sure this value is not a reference type -pub inline fn writeStructEndian(bw: *BufferedWriter, value: anytype, endian: std.builtin.Endian) Writer.Error!void { - if (native_endian == endian) { - return bw.writeStruct(value); - } else { - var copy = value; - std.mem.byteSwapAllFields(@TypeOf(value), ©); - return bw.writeStruct(copy); - } -} - -pub inline fn writeSliceEndian( - bw: *BufferedWriter, - Elem: type, - slice: []const Elem, - endian: std.builtin.Endian, -) Writer.Error!void { - if (native_endian == endian) { - return writeAll(bw, @ptrCast(slice)); - } else { - return bw.writeArraySwap(bw, Elem, slice); - } -} - -/// Asserts that the buffer storage capacity is at least enough to store `@sizeOf(Elem)` -pub fn writeSliceSwap(bw: *BufferedWriter, Elem: type, slice: []const Elem) Writer.Error!void { - // copy to storage first, then swap in place - _ = bw; - _ = slice; - @panic("TODO"); -} - -/// Unlike `writeSplat` and `writeVec`, this function will call into the -/// underlying writer even if there is enough buffer capacity for the file -/// contents. -/// -/// Although it would be possible to eliminate `error.Unimplemented` from -/// the error set by reading directly into the buffer in such case, -/// this is not done because it is more efficient to do it in `writeFileAll` -/// so that the error does not occur with each write. -/// -/// See `writeFileReading` for an alternative that does not have -/// `error.Unimplemented` in the error set. -pub fn writeFile( - bw: *BufferedWriter, - file_reader: *File.Reader, - limit: Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, -) Writer.FileError!usize { - return passthruWriteFile(bw, file_reader, limit, headers_and_trailers, headers_len); -} - -/// Returning zero bytes means end of stream. -/// -/// Asserts nonzero buffer capacity. -pub fn writeFileReading( - bw: *BufferedWriter, - file_reader: *File.Reader, - limit: Limit, -) Writer.ReadingFileError!usize { - const dest = limit.slice(try bw.writableSliceGreedy(1)); - const n = file_reader.read(dest) catch |err| switch (err) { - error.EndOfStream => 0, - error.ReadFailed => return error.ReadFailed, - }; - bw.advance(n); - return n; -} - -fn passthruWriteFile( - context: ?*anyopaque, - file_reader: *File.Reader, - limit: Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, -) Writer.FileError!usize { - const bw: *BufferedWriter = @alignCast(@ptrCast(context)); - const buffer = bw.buffer; - if (buffer.len == 0) return track( - &bw.count, - try bw.unbuffered_writer.writeFile(file_reader, limit, headers_and_trailers, headers_len), - ); - const start_end = bw.end; - const headers = headers_and_trailers[0..headers_len]; - const trailers = headers_and_trailers[headers_len..]; - var buffers: [max_buffers_len][]const u8 = undefined; - var end = start_end; - for (headers, 0..) |header, i| { - const new_end = end + header.len; - if (new_end <= buffer.len) { - @branchHint(.likely); - @memcpy(buffer[end..new_end], header); - end = new_end; - continue; - } - buffers[0] = buffer[0..end]; - const remaining_headers = headers[i..]; - const remaining_buffers = buffers[1..]; - const buffers_len: usize = @min(remaining_headers.len, remaining_buffers.len); - @memcpy(remaining_buffers[0..buffers_len], remaining_headers[0..buffers_len]); - if (buffers_len >= remaining_headers.len) { - // Made it past the headers, so we can call `writeFile`. - const remaining_buffers_for_trailers = remaining_buffers[buffers_len..]; - const send_trailers_len: usize = @min(trailers.len, remaining_buffers_for_trailers.len); - @memcpy(remaining_buffers_for_trailers[0..send_trailers_len], trailers[0..send_trailers_len]); - const send_headers_len = 1 + buffers_len; - const send_buffers = buffers[0 .. send_headers_len + send_trailers_len]; - const n = try bw.unbuffered_writer.writeFile(file_reader, limit, send_buffers, send_headers_len); - if (n < end) { - @branchHint(.unlikely); - const remainder = buffer[n..end]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - return track(&bw.count, end - start_end); - } - bw.end = 0; - return track(&bw.count, n - start_end); - } - // Have not made it past the headers yet; must call `writeVec`. - const n = try bw.unbuffered_writer.writeVec(buffers[0 .. buffers_len + 1]); - if (n < end) { - @branchHint(.unlikely); - const remainder = buffer[n..end]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - return track(&bw.count, end - start_end); - } - bw.end = 0; - return track(&bw.count, n - start_end); - } - // All headers written to buffer. - buffers[0] = buffer[0..end]; - const remaining_buffers = buffers[1..]; - const send_trailers_len: usize = @min(trailers.len, remaining_buffers.len); - @memcpy(remaining_buffers[0..send_trailers_len], trailers[0..send_trailers_len]); - const send_headers_len = @intFromBool(end != 0); - const send_buffers = buffers[1 - send_headers_len .. 1 + send_trailers_len]; - const n = try bw.unbuffered_writer.writeFile(file_reader, limit, send_buffers, send_headers_len); - if (n < end) { - @branchHint(.unlikely); - const remainder = buffer[n..end]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - bw.end = remainder.len; - return track(&bw.count, end - start_end); - } - bw.end = 0; - return track(&bw.count, n - start_end); -} - -pub const WriteFileOptions = struct { - limit: Limit = .unlimited, - /// Headers and trailers must be passed together so that in case `len` is - /// zero, they can be forwarded directly to `Writer.VTable.writeSplat`. - /// - /// The parameter is mutable because this function needs to mutate the - /// fields in order to handle partial writes from `Writer.VTable.writeFile`. - headers_and_trailers: [][]const u8 = &.{}, - /// The number of trailers is inferred from - /// `headers_and_trailers.len - headers_len`. - headers_len: usize = 0, -}; - -pub fn writeFileAll( - bw: *BufferedWriter, - file_reader: *std.fs.File.Reader, - options: WriteFileOptions, -) Writer.ReadingFileError!void { - const headers_and_trailers = options.headers_and_trailers; - const headers = headers_and_trailers[0..options.headers_len]; - var remaining = options.limit; - var i: usize = 0; - while (true) { - const before_pos = file_reader.pos; - var n = bw.writeFile(file_reader, remaining, headers_and_trailers[i..], headers.len - i) catch |err| switch (err) { - error.ReadFailed => return error.ReadFailed, - error.WriteFailed => return error.WriteFailed, - error.Unimplemented => { - file_reader.mode = file_reader.mode.toReading(); - try bw.writeVecAll(headers[i..]); - try bw.writeFileReadingAll(file_reader, remaining); - try bw.writeVecAll(headers_and_trailers[headers.len..]); - return; - }, - }; - while (i < headers.len and n >= headers[i].len) { - n -= headers[i].len; - i += 1; - } - if (i < headers.len) { - headers[i] = headers[i][n..]; - continue; - } - const file_bytes_consumed = file_reader.pos - before_pos; - remaining = remaining.subtract(file_bytes_consumed).?; - const size = file_reader.size orelse continue; // End of file not yet reached. - if (file_reader.pos < size) continue; // End of file not yet reached. - n -= file_bytes_consumed; // Trailers reached. - while (i < headers_and_trailers.len and n >= headers_and_trailers[i].len) { - n -= headers_and_trailers[i].len; - i += 1; - } - if (i < headers_and_trailers.len) { - headers_and_trailers[i] = headers_and_trailers[i][n..]; - try bw.writeVecAll(headers_and_trailers[i..]); - return; - } - return; - } -} - -/// Equivalent to `writeFileAll` but uses direct `pread` and `read` calls on -/// `file` rather than `Writer.writeFile`. This is generally used as a fallback -/// when the underlying implementation returns `error.Unimplemented`, which is -/// why that error code does not appear in this function's error set. -/// -/// Asserts nonzero buffer capacity. -pub fn writeFileReadingAll( - bw: *BufferedWriter, - file_reader: *File.Reader, - limit: Limit, -) Writer.ReadingFileError!void { - var remaining = limit; - while (remaining.nonzero()) { - const n = try writeFileReading(bw, file_reader, remaining); - if (n == 0) return; - remaining = remaining.subtract(n).?; - } -} - -pub fn alignBuffer( - bw: *BufferedWriter, - buffer: []const u8, - width: usize, - alignment: std.fmt.Alignment, - fill: u8, -) Writer.Error!void { - const padding = if (buffer.len < width) width - buffer.len else 0; - if (padding == 0) { - @branchHint(.likely); - return bw.writeAll(buffer); - } - switch (alignment) { - .left => { - try bw.writeAll(buffer); - try bw.splatByteAll(fill, padding); - }, - .center => { - const left_padding = padding / 2; - const right_padding = (padding + 1) / 2; - try bw.splatByteAll(fill, left_padding); - try bw.writeAll(buffer); - try bw.splatByteAll(fill, right_padding); - }, - .right => { - try bw.splatByteAll(fill, padding); - try bw.writeAll(buffer); - }, - } -} - -pub fn alignBufferOptions(bw: *BufferedWriter, buffer: []const u8, options: std.fmt.Options) Writer.Error!void { - return bw.alignBuffer(buffer, options.width orelse buffer.len, options.alignment, options.fill); -} - -pub fn printAddress(bw: *BufferedWriter, value: anytype) Writer.Error!void { - const T = @TypeOf(value); - switch (@typeInfo(T)) { - .pointer => |info| { - try bw.writeAll(@typeName(info.child) ++ "@"); - if (info.size == .slice) - try bw.printIntOptions(@intFromPtr(value.ptr), 16, .lower, .{}) - else - try bw.printIntOptions(@intFromPtr(value), 16, .lower, .{}); - return; - }, - .optional => |info| { - if (@typeInfo(info.child) == .pointer) { - try bw.writeAll(@typeName(info.child) ++ "@"); - try bw.printIntOptions(@intFromPtr(value), 16, .lower, .{}); - return; - } - }, - else => {}, - } - - @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier"); -} - -pub fn printValue( - bw: *BufferedWriter, - comptime fmt: []const u8, - options: std.fmt.Options, - value: anytype, - max_depth: usize, -) Writer.Error!void { - const T = @TypeOf(value); - - if (comptime std.mem.eql(u8, fmt, "*")) { - return bw.printAddress(value); - } - - const is_any = comptime std.mem.eql(u8, fmt, ANY); - if (!is_any and std.meta.hasMethod(T, "format")) { - if (fmt.len > 0 and fmt[0] == 'f') { - return value.format(bw, fmt[1..]); - } else if (fmt.len == 0) { - // after 0.15.0 is tagged, delete the hasMethod condition and this compile error - @compileError("ambiguous format string; specify {f} to call format method, or {any} to skip it"); - } - } - - switch (@typeInfo(T)) { - .float, .comptime_float => return bw.printFloat(if (is_any) "d" else fmt, options, value), - .int, .comptime_int => return bw.printInt(if (is_any) "d" else fmt, options, value), - .bool => { - if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - return bw.alignBufferOptions(if (value) "true" else "false", options); - }, - .void => { - if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - return bw.alignBufferOptions("void", options); - }, - .optional => { - const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '?') - stripOptionalOrErrorUnionSpec(fmt) - else if (is_any) - ANY - else - @compileError("cannot print optional without a specifier (i.e. {?} or {any})"); - if (value) |payload| { - return bw.printValue(remaining_fmt, options, payload, max_depth); - } else { - return bw.alignBufferOptions("null", options); - } - }, - .error_union => { - const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '!') - stripOptionalOrErrorUnionSpec(fmt) - else if (is_any) - ANY - else - @compileError("cannot print error union without a specifier (i.e. {!} or {any})"); - if (value) |payload| { - return bw.printValue(remaining_fmt, options, payload, max_depth); - } else |err| { - return bw.printValue("", options, err, max_depth); - } - }, - .error_set => { - if (fmt.len == 1 and fmt[0] == 's') return bw.writeAll(@errorName(value)); - if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - try printErrorSet(bw, value); - }, - .@"enum" => { - if (fmt.len == 1 and fmt[0] == 's') { - try bw.writeAll(@tagName(value)); - return; - } - if (!is_any) { - if (fmt.len != 0) return printValue(bw, fmt, options, @intFromEnum(value), max_depth); - return printValue(bw, ANY, options, value, max_depth); - } - const enum_info = @typeInfo(T).@"enum"; - if (enum_info.is_exhaustive) { - var vecs: [3][]const u8 = .{ @typeName(T), ".", @tagName(value) }; - try bw.writeVecAll(&vecs); - return; - } - try bw.writeAll(@typeName(T)); - @setEvalBranchQuota(3 * enum_info.fields.len); - inline for (enum_info.fields) |field| { - if (@intFromEnum(value) == field.value) { - try bw.writeAll("."); - try bw.writeAll(@tagName(value)); - return; - } - } - try bw.writeByte('('); - try bw.printValue(ANY, options, @intFromEnum(value), max_depth); - try bw.writeByte(')'); - }, - .@"union" => |info| { - if (!is_any) { - if (fmt.len != 0) invalidFmtError(fmt, value); - return printValue(bw, ANY, options, value, max_depth); - } - try bw.writeAll(@typeName(T)); - if (max_depth == 0) { - try bw.writeAll("{ ... }"); - return; - } - if (info.tag_type) |UnionTagType| { - try bw.writeAll("{ ."); - try bw.writeAll(@tagName(@as(UnionTagType, value))); - try bw.writeAll(" = "); - inline for (info.fields) |u_field| { - if (value == @field(UnionTagType, u_field.name)) { - try bw.printValue(ANY, options, @field(value, u_field.name), max_depth - 1); - } - } - try bw.writeAll(" }"); - } else { - try bw.writeByte('@'); - try bw.printIntOptions(@intFromPtr(&value), 16, .lower, options); - } - }, - .@"struct" => |info| { - if (!is_any) { - if (fmt.len != 0) invalidFmtError(fmt, value); - return printValue(bw, ANY, options, value, max_depth); - } - if (info.is_tuple) { - // Skip the type and field names when formatting tuples. - if (max_depth == 0) { - try bw.writeAll("{ ... }"); - return; - } - try bw.writeAll("{"); - inline for (info.fields, 0..) |f, i| { - if (i == 0) { - try bw.writeAll(" "); - } else { - try bw.writeAll(", "); - } - try bw.printValue(ANY, options, @field(value, f.name), max_depth - 1); - } - try bw.writeAll(" }"); - return; - } - try bw.writeAll(@typeName(T)); - if (max_depth == 0) { - try bw.writeAll("{ ... }"); - return; - } - try bw.writeAll("{"); - inline for (info.fields, 0..) |f, i| { - if (i == 0) { - try bw.writeAll(" ."); - } else { - try bw.writeAll(", ."); - } - try bw.writeAll(f.name); - try bw.writeAll(" = "); - try bw.printValue(ANY, options, @field(value, f.name), max_depth - 1); - } - try bw.writeAll(" }"); - }, - .pointer => |ptr_info| switch (ptr_info.size) { - .one => switch (@typeInfo(ptr_info.child)) { - .array, .@"enum", .@"union", .@"struct" => { - return bw.printValue(fmt, options, value.*, max_depth); - }, - else => { - var buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" }; - try bw.writeVecAll(&buffers); - try bw.printIntOptions(@intFromPtr(value), 16, .lower, options); - return; - }, - }, - .many, .c => { - if (ptr_info.sentinel() != null) - return bw.printValue(fmt, options, std.mem.span(value), max_depth); - if (fmt.len == 1 and fmt[0] == 's' and ptr_info.child == u8) - return bw.alignBufferOptions(std.mem.span(value), options); - if (!is_any and fmt.len == 0) - @compileError("cannot format pointer without a specifier (i.e. {s} or {*})"); - if (!is_any and fmt.len != 0) - invalidFmtError(fmt, value); - try bw.printAddress(value); - }, - .slice => { - if (!is_any and fmt.len == 0) - @compileError("cannot format slice without a specifier (i.e. {s}, {x}, {b64}, or {any})"); - if (max_depth == 0) - return bw.writeAll("{ ... }"); - if (ptr_info.child == u8) switch (fmt.len) { - 1 => switch (fmt[0]) { - 's' => return bw.alignBufferOptions(value, options), - 'x' => return bw.printHex(value, .lower), - 'X' => return bw.printHex(value, .upper), - else => {}, - }, - 3 => if (fmt[0] == 'b' and fmt[1] == '6' and fmt[2] == '4') { - return bw.printBase64(value); - }, - else => {}, - }; - try bw.writeAll("{ "); - for (value, 0..) |elem, i| { - try bw.printValue(fmt, options, elem, max_depth - 1); - if (i != value.len - 1) { - try bw.writeAll(", "); - } - } - try bw.writeAll(" }"); - }, - }, - .array => |info| { - if (fmt.len == 0) - @compileError("cannot format array without a specifier (i.e. {s} or {any})"); - if (max_depth == 0) { - return bw.writeAll("{ ... }"); - } - if (info.child == u8) { - if (fmt[0] == 's') { - return bw.alignBufferOptions(&value, options); - } else if (fmt[0] == 'x') { - return bw.printHex(&value, .lower); - } else if (fmt[0] == 'X') { - return bw.printHex(&value, .upper); - } - } - try bw.writeAll("{ "); - for (value, 0..) |elem, i| { - try bw.printValue(fmt, options, elem, max_depth - 1); - if (i < value.len - 1) { - try bw.writeAll(", "); - } - } - try bw.writeAll(" }"); - }, - .vector => |info| { - if (max_depth == 0) { - return bw.writeAll("{ ... }"); - } - try bw.writeAll("{ "); - var i: usize = 0; - while (i < info.len) : (i += 1) { - try bw.printValue(fmt, options, value[i], max_depth - 1); - if (i < info.len - 1) { - try bw.writeAll(", "); - } - } - try bw.writeAll(" }"); - }, - .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"), - .type => { - if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - return bw.alignBufferOptions(@typeName(value), options); - }, - .enum_literal => { - if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - const buffer = [_]u8{'.'} ++ @tagName(value); - return bw.alignBufferOptions(buffer, options); - }, - .null => { - if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - return bw.alignBufferOptions("null", options); - }, - else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"), - } -} - -fn printErrorSet(bw: *BufferedWriter, error_set: anyerror) Writer.Error!void { - var vecs: [2][]const u8 = .{ "error.", @errorName(error_set) }; - try bw.writeVecAll(&vecs); -} - -pub fn printInt( - bw: *BufferedWriter, - comptime fmt: []const u8, - options: std.fmt.Options, - value: anytype, -) Writer.Error!void { - const int_value = if (@TypeOf(value) == comptime_int) blk: { - const Int = std.math.IntFittingRange(value, value); - break :blk @as(Int, value); - } else value; - - switch (fmt.len) { - 0 => return bw.printIntOptions(int_value, 10, .lower, options), - 1 => switch (fmt[0]) { - 'd' => return bw.printIntOptions(int_value, 10, .lower, options), - 'c' => { - if (@typeInfo(@TypeOf(int_value)).int.bits <= 8) { - return bw.printAsciiChar(@as(u8, int_value), options); - } else { - @compileError("cannot print integer that is larger than 8 bits as an ASCII character"); - } - }, - 'u' => { - if (@typeInfo(@TypeOf(int_value)).int.bits <= 21) { - return bw.printUnicodeCodepoint(@as(u21, int_value), options); - } else { - @compileError("cannot print integer that is larger than 21 bits as an UTF-8 sequence"); - } - }, - 'b' => return bw.printIntOptions(int_value, 2, .lower, options), - 'x' => return bw.printIntOptions(int_value, 16, .lower, options), - 'X' => return bw.printIntOptions(int_value, 16, .upper, options), - 'o' => return bw.printIntOptions(int_value, 8, .lower, options), - 'B' => return bw.printByteSize(int_value, .decimal, options), - 'D' => return bw.printDuration(int_value, options), - else => invalidFmtError(fmt, value), - }, - 2 => { - if (fmt[0] == 'B' and fmt[1] == 'i') { - return bw.printByteSize(int_value, .binary, options); - } else { - invalidFmtError(fmt, value); - } - }, - else => invalidFmtError(fmt, value), - } - comptime unreachable; -} - -pub fn printAsciiChar(bw: *BufferedWriter, c: u8, options: std.fmt.Options) Writer.Error!void { - return bw.alignBufferOptions(@as(*const [1]u8, &c), options); -} - -pub fn printAscii(bw: *BufferedWriter, bytes: []const u8, options: std.fmt.Options) Writer.Error!void { - return bw.alignBufferOptions(bytes, options); -} - -pub fn printUnicodeCodepoint(bw: *BufferedWriter, c: u21, options: std.fmt.Options) Writer.Error!void { - var buf: [4]u8 = undefined; - const len = try std.unicode.utf8Encode(c, &buf); - return bw.alignBufferOptions(buf[0..len], options); -} - -pub fn printIntOptions( - bw: *BufferedWriter, - value: anytype, - base: u8, - case: std.fmt.Case, - options: std.fmt.Options, -) Writer.Error!void { - assert(base >= 2); - - const int_value = if (@TypeOf(value) == comptime_int) blk: { - const Int = std.math.IntFittingRange(value, value); - break :blk @as(Int, value); - } else value; - - const value_info = @typeInfo(@TypeOf(int_value)).int; - - // The type must have the same size as `base` or be wider in order for the - // division to work - const min_int_bits = comptime @max(value_info.bits, 8); - const MinInt = std.meta.Int(.unsigned, min_int_bits); - - const abs_value = @abs(int_value); - // The worst case in terms of space needed is base 2, plus 1 for the sign - var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined; - - var a: MinInt = abs_value; - var index: usize = buf.len; - - if (base == 10) { - while (a >= 100) : (a = @divTrunc(a, 100)) { - index -= 2; - buf[index..][0..2].* = std.fmt.digits2(@intCast(a % 100)); - } - - if (a < 10) { - index -= 1; - buf[index] = '0' + @as(u8, @intCast(a)); - } else { - index -= 2; - buf[index..][0..2].* = std.fmt.digits2(@intCast(a)); - } - } else { - while (true) { - const digit = a % base; - index -= 1; - buf[index] = std.fmt.digitToChar(@intCast(digit), case); - a /= base; - if (a == 0) break; - } - } - - if (value_info.signedness == .signed) { - if (value < 0) { - // Negative integer - index -= 1; - buf[index] = '-'; - } else if (options.width == null or options.width.? == 0) { - // Positive integer, omit the plus sign - } else { - // Positive integer - index -= 1; - buf[index] = '+'; - } - } - - return bw.alignBufferOptions(buf[index..], options); -} - -pub fn printFloat( - bw: *BufferedWriter, - comptime fmt: []const u8, - options: std.fmt.Options, - value: anytype, -) Writer.Error!void { - var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined; - - if (fmt.len > 1) invalidFmtError(fmt, value); - switch (if (fmt.len == 0) 'e' else fmt[0]) { - 'e' => { - const s = std.fmt.float.render(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) { - error.BufferTooSmall => "(float)", - }; - return bw.alignBufferOptions(s, options); - }, - 'd' => { - const s = std.fmt.float.render(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { - error.BufferTooSmall => "(float)", - }; - return bw.alignBufferOptions(s, options); - }, - 'x' => { - var sub_bw: BufferedWriter = undefined; - sub_bw.initFixed(&buf); - sub_bw.printFloatHexadecimal(value, options.precision) catch unreachable; - return bw.alignBufferOptions(sub_bw.getWritten(), options); - }, - else => invalidFmtError(fmt, value), - } -} - -pub fn printFloatHexadecimal(bw: *BufferedWriter, value: anytype, opt_precision: ?usize) Writer.Error!void { - if (std.math.signbit(value)) try bw.writeByte('-'); - if (std.math.isNan(value)) return bw.writeAll("nan"); - if (std.math.isInf(value)) return bw.writeAll("inf"); - - const T = @TypeOf(value); - const TU = std.meta.Int(.unsigned, @bitSizeOf(T)); - - const mantissa_bits = std.math.floatMantissaBits(T); - const fractional_bits = std.math.floatFractionalBits(T); - const exponent_bits = std.math.floatExponentBits(T); - const mantissa_mask = (1 << mantissa_bits) - 1; - const exponent_mask = (1 << exponent_bits) - 1; - const exponent_bias = (1 << (exponent_bits - 1)) - 1; - - const as_bits: TU = @bitCast(value); - var mantissa = as_bits & mantissa_mask; - var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask)); - - const is_denormal = exponent == 0 and mantissa != 0; - const is_zero = exponent == 0 and mantissa == 0; - - if (is_zero) { - // Handle this case here to simplify the logic below. - try bw.writeAll("0x0"); - if (opt_precision) |precision| { - if (precision > 0) { - try bw.writeAll("."); - try bw.splatByteAll('0', precision); - } - } else { - try bw.writeAll(".0"); - } - try bw.writeAll("p0"); - return; - } - - if (is_denormal) { - // Adjust the exponent for printing. - exponent += 1; - } else { - if (fractional_bits == mantissa_bits) - mantissa |= 1 << fractional_bits; // Add the implicit integer bit. - } - - const mantissa_digits = (fractional_bits + 3) / 4; - // Fill in zeroes to round the fraction width to a multiple of 4. - mantissa <<= mantissa_digits * 4 - fractional_bits; - - if (opt_precision) |precision| { - // Round if needed. - if (precision < mantissa_digits) { - // We always have at least 4 extra bits. - var extra_bits = (mantissa_digits - precision) * 4; - // The result LSB is the Guard bit, we need two more (Round and - // Sticky) to round the value. - while (extra_bits > 2) { - mantissa = (mantissa >> 1) | (mantissa & 1); - extra_bits -= 1; - } - // Round to nearest, tie to even. - mantissa |= @intFromBool(mantissa & 0b100 != 0); - mantissa += 1; - // Drop the excess bits. - mantissa >>= 2; - // Restore the alignment. - mantissa <<= @as(std.math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4)); - - const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0; - // Prefer a normalized result in case of overflow. - if (overflow) { - mantissa >>= 1; - exponent += 1; - } - } - } - - // +1 for the decimal part. - var buf: [1 + mantissa_digits]u8 = undefined; - assert(std.fmt.printInt(&buf, mantissa, 16, .lower, .{ .fill = '0', .width = 1 + mantissa_digits }) == buf.len); - - try bw.writeAll("0x"); - try bw.writeByte(buf[0]); - const trimmed = std.mem.trimRight(u8, buf[1..], "0"); - if (opt_precision) |precision| { - if (precision > 0) try bw.writeAll("."); - } else if (trimmed.len > 0) { - try bw.writeAll("."); - } - try bw.writeAll(trimmed); - // Add trailing zeros if explicitly requested. - if (opt_precision) |precision| if (precision > 0) { - if (precision > trimmed.len) - try bw.splatByteAll('0', precision - trimmed.len); - }; - try bw.writeAll("p"); - try bw.printIntOptions(exponent - exponent_bias, 10, .lower, .{}); -} - -pub const ByteSizeUnits = enum { - /// This formatter represents the number as multiple of 1000 and uses the SI - /// measurement units (kB, MB, GB, ...). - decimal, - /// This formatter represents the number as multiple of 1024 and uses the IEC - /// measurement units (KiB, MiB, GiB, ...). - binary, -}; - -/// Format option `precision` is ignored when `value` is less than 1kB -pub fn printByteSize( - bw: *std.io.BufferedWriter, - value: u64, - comptime units: ByteSizeUnits, - options: std.fmt.Options, -) Writer.Error!void { - if (value == 0) return bw.alignBufferOptions("0B", options); - // The worst case in terms of space needed is 32 bytes + 3 for the suffix. - var buf: [std.fmt.float.min_buffer_size + 3]u8 = undefined; - - const mags_si = " kMGTPEZY"; - const mags_iec = " KMGTPEZY"; - - const log2 = std.math.log2(value); - const base = switch (units) { - .decimal => 1000, - .binary => 1024, - }; - const magnitude = switch (units) { - .decimal => @min(log2 / comptime std.math.log2(1000), mags_si.len - 1), - .binary => @min(log2 / 10, mags_iec.len - 1), - }; - const new_value = std.math.lossyCast(f64, value) / std.math.pow(f64, std.math.lossyCast(f64, base), std.math.lossyCast(f64, magnitude)); - const suffix = switch (units) { - .decimal => mags_si[magnitude], - .binary => mags_iec[magnitude], - }; - - const s = switch (magnitude) { - 0 => buf[0..std.fmt.printInt(&buf, value, 10, .lower, .{})], - else => std.fmt.float.render(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { - error.BufferTooSmall => unreachable, - }, - }; - - var i: usize = s.len; - if (suffix == ' ') { - buf[i] = 'B'; - i += 1; - } else switch (units) { - .decimal => { - buf[i..][0..2].* = [_]u8{ suffix, 'B' }; - i += 2; - }, - .binary => { - buf[i..][0..3].* = [_]u8{ suffix, 'i', 'B' }; - i += 3; - }, - } - - return bw.alignBufferOptions(buf[0..i], options); -} - -// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948 -const ANY = "any"; - -fn stripOptionalOrErrorUnionSpec(comptime fmt: []const u8) []const u8 { - return if (std.mem.eql(u8, fmt[1..], ANY)) - ANY - else - fmt[1..]; -} - -pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) noreturn { - @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'"); -} - -pub fn printDurationSigned(bw: *BufferedWriter, ns: i64) Writer.Error!void { - if (ns < 0) try bw.writeByte('-'); - return bw.printDurationUnsigned(@abs(ns)); -} - -pub fn printDurationUnsigned(bw: *BufferedWriter, ns: u64) Writer.Error!void { - var ns_remaining = ns; - inline for (.{ - .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' }, - .{ .ns = std.time.ns_per_week, .sep = 'w' }, - .{ .ns = std.time.ns_per_day, .sep = 'd' }, - .{ .ns = std.time.ns_per_hour, .sep = 'h' }, - .{ .ns = std.time.ns_per_min, .sep = 'm' }, - }) |unit| { - if (ns_remaining >= unit.ns) { - const units = ns_remaining / unit.ns; - try bw.printIntOptions(units, 10, .lower, .{}); - try bw.writeByte(unit.sep); - ns_remaining -= units * unit.ns; - if (ns_remaining == 0) return; - } - } - - inline for (.{ - .{ .ns = std.time.ns_per_s, .sep = "s" }, - .{ .ns = std.time.ns_per_ms, .sep = "ms" }, - .{ .ns = std.time.ns_per_us, .sep = "us" }, - }) |unit| { - const kunits = ns_remaining * 1000 / unit.ns; - if (kunits >= 1000) { - try bw.printIntOptions(kunits / 1000, 10, .lower, .{}); - const frac = kunits % 1000; - if (frac > 0) { - // Write up to 3 decimal places - var decimal_buf = [_]u8{ '.', 0, 0, 0 }; - var inner: BufferedWriter = undefined; - inner.initFixed(decimal_buf[1..]); - inner.printIntOptions(frac, 10, .lower, .{ .fill = '0', .width = 3 }) catch unreachable; - var end: usize = 4; - while (end > 1) : (end -= 1) { - if (decimal_buf[end - 1] != '0') break; - } - try bw.writeAll(decimal_buf[0..end]); - } - return bw.writeAll(unit.sep); - } - } - - try bw.printIntOptions(ns_remaining, 10, .lower, .{}); - try bw.writeAll("ns"); -} - -/// Writes number of nanoseconds according to its signed magnitude: -/// `[#y][#w][#d][#h][#m]#[.###][n|u|m]s` -/// `nanoseconds` must be an integer that coerces into `u64` or `i64`. -pub fn printDuration(bw: *BufferedWriter, nanoseconds: anytype, options: std.fmt.Options) Writer.Error!void { - // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24 - var buf: [24]u8 = undefined; - var sub_bw: BufferedWriter = undefined; - sub_bw.initFixed(&buf); - switch (@typeInfo(@TypeOf(nanoseconds)).int.signedness) { - .signed => sub_bw.printDurationSigned(nanoseconds) catch unreachable, - .unsigned => sub_bw.printDurationUnsigned(nanoseconds) catch unreachable, - } - return bw.alignBufferOptions(sub_bw.getWritten(), options); -} - -pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) Writer.Error!void { - const charset = switch (case) { - .upper => "0123456789ABCDEF", - .lower => "0123456789abcdef", - }; - for (bytes) |c| { - try bw.writeByte(charset[c >> 4]); - try bw.writeByte(charset[c & 15]); - } -} - -pub fn printBase64(bw: *BufferedWriter, bytes: []const u8) Writer.Error!void { - var chunker = std.mem.window(u8, bytes, 3, 3); - var temp: [5]u8 = undefined; - while (chunker.next()) |chunk| { - try bw.writeAll(std.base64.standard.Encoder.encode(&temp, chunk)); - } -} - -/// Write a single unsigned integer as LEB128 to the given writer. -pub fn writeUleb128(bw: *BufferedWriter, value: anytype) Writer.Error!void { - try bw.writeLeb128(switch (@typeInfo(@TypeOf(value))) { - .comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value), - .int => |value_info| switch (value_info.signedness) { - .signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)), - .unsigned => value, - }, - else => comptime unreachable, - }); -} - -/// Write a single signed integer as LEB128 to the given writer. -pub fn writeSleb128(bw: *BufferedWriter, value: anytype) Writer.Error!void { - try bw.writeLeb128(switch (@typeInfo(@TypeOf(value))) { - .comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value), - .int => |value_info| switch (value_info.signedness) { - .signed => value, - .unsigned => @as(@Type(.{ .int = .{ .signedness = .signed, .bits = value_info.bits + 1 } }), value), - }, - else => comptime unreachable, - }); -} - -/// Write a single integer as LEB128 to the given writer. -pub fn writeLeb128(bw: *BufferedWriter, value: anytype) Writer.Error!void { - const value_info = @typeInfo(@TypeOf(value)).int; - try bw.writeMultipleOf7Leb128(@as(@Type(.{ .int = .{ - .signedness = value_info.signedness, - .bits = std.mem.alignForwardAnyAlign(u16, value_info.bits, 7), - } }), value)); -} - -fn writeMultipleOf7Leb128(bw: *BufferedWriter, value: anytype) Writer.Error!void { - const value_info = @typeInfo(@TypeOf(value)).int; - comptime assert(value_info.bits % 7 == 0); - var remaining = value; - while (true) { - const buffer: []packed struct(u8) { bits: u7, more: bool } = @ptrCast(try bw.writableSliceGreedy(1)); - for (buffer, 1..) |*byte, len| { - const more = switch (value_info.signedness) { - .signed => remaining >> 6 != remaining >> (value_info.bits - 1), - .unsigned => remaining > std.math.maxInt(u7), - }; - byte.* = if (@inComptime()) @typeInfo(@TypeOf(buffer)).pointer.child{ - .bits = @bitCast(@as(@Type(.{ .int = .{ - .signedness = value_info.signedness, - .bits = 7, - } }), @truncate(remaining))), - .more = more, - } else .{ - .bits = @bitCast(@as(@Type(.{ .int = .{ - .signedness = value_info.signedness, - .bits = 7, - } }), @truncate(remaining))), - .more = more, - }; - if (value_info.bits > 7) remaining >>= 7; - if (!more) return bw.advance(len); - } - bw.advance(buffer.len); - } -} - -test "formatValue max_depth" { - const Vec2 = struct { - const SelfType = @This(); - x: f32, - y: f32, - - pub fn format( - self: SelfType, - comptime fmt: []const u8, - options: std.fmt.Options, - bw: *BufferedWriter, - ) Writer.Error!void { - _ = options; - if (fmt.len == 0) { - return bw.print("({d:.3},{d:.3})", .{ self.x, self.y }); - } else { - @compileError("unknown format string: '" ++ fmt ++ "'"); - } - } - }; - const E = enum { - One, - Two, - Three, - }; - const TU = union(enum) { - const SelfType = @This(); - float: f32, - int: u32, - ptr: ?*SelfType, - }; - const S = struct { - const SelfType = @This(); - a: ?*SelfType, - tu: TU, - e: E, - vec: Vec2, - }; - - var inst = S{ - .a = null, - .tu = TU{ .ptr = null }, - .e = E.Two, - .vec = Vec2{ .x = 10.2, .y = 2.22 }, - }; - inst.a = &inst; - inst.tu.ptr = &inst.tu; - - var buf: [1000]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buf); - try bw.printValue("", .{}, inst, 0); - try testing.expectEqualStrings("io.BufferedWriter.test.printValue max_depth.S{ ... }", bw.getWritten()); - - bw.reset(); - try bw.printValue("", .{}, inst, 1); - try testing.expectEqualStrings("io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ ... }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ ... }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", bw.getWritten()); - - bw.reset(); - try bw.printValue("", .{}, inst, 2); - try testing.expectEqualStrings("io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ ... }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ ... }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ .ptr = io.BufferedWriter.test.printValue max_depth.TU{ ... } }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", bw.getWritten()); - - bw.reset(); - try bw.printValue("", .{}, inst, 3); - try testing.expectEqualStrings("io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ ... }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ ... }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ .ptr = io.BufferedWriter.test.printValue max_depth.TU{ ... } }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ .ptr = io.BufferedWriter.test.printValue max_depth.TU{ .ptr = io.BufferedWriter.test.printValue max_depth.TU{ ... } } }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", bw.getWritten()); - - const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 }; - bw.reset(); - try bw.printValue("", .{}, vec, 0); - try testing.expectEqualStrings("{ ... }", bw.getWritten()); - - bw.reset(); - try bw.printValue("", .{}, vec, 1); - try testing.expectEqualStrings("{ 1, 2, 3, 4 }", bw.getWritten()); -} - -test printDuration { - testDurationCase("0ns", 0); - testDurationCase("1ns", 1); - testDurationCase("999ns", std.time.ns_per_us - 1); - testDurationCase("1us", std.time.ns_per_us); - testDurationCase("1.45us", 1450); - testDurationCase("1.5us", 3 * std.time.ns_per_us / 2); - testDurationCase("14.5us", 14500); - testDurationCase("145us", 145000); - testDurationCase("999.999us", std.time.ns_per_ms - 1); - testDurationCase("1ms", std.time.ns_per_ms + 1); - testDurationCase("1.5ms", 3 * std.time.ns_per_ms / 2); - testDurationCase("1.11ms", 1110000); - testDurationCase("1.111ms", 1111000); - testDurationCase("1.111ms", 1111100); - testDurationCase("999.999ms", std.time.ns_per_s - 1); - testDurationCase("1s", std.time.ns_per_s); - testDurationCase("59.999s", std.time.ns_per_min - 1); - testDurationCase("1m", std.time.ns_per_min); - testDurationCase("1h", std.time.ns_per_hour); - testDurationCase("1d", std.time.ns_per_day); - testDurationCase("1w", std.time.ns_per_week); - testDurationCase("1y", 365 * std.time.ns_per_day); - testDurationCase("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1 - testDurationCase("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms); - testDurationCase("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us); - testDurationCase("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1); - testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms); - testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1); - testDurationCase("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999); - testDurationCase("584y49w23h34m33.709s", std.math.maxInt(u64)); - - testing.expectFmt("=======0ns", "{D:=>10}", .{0}); - testing.expectFmt("1ns=======", "{D:=<10}", .{1}); - testing.expectFmt(" 999ns ", "{D:^10}", .{std.time.ns_per_us - 1}); -} - -test printDurationSigned { - testDurationCaseSigned("0ns", 0); - testDurationCaseSigned("1ns", 1); - testDurationCaseSigned("-1ns", -(1)); - testDurationCaseSigned("999ns", std.time.ns_per_us - 1); - testDurationCaseSigned("-999ns", -(std.time.ns_per_us - 1)); - testDurationCaseSigned("1us", std.time.ns_per_us); - testDurationCaseSigned("-1us", -(std.time.ns_per_us)); - testDurationCaseSigned("1.45us", 1450); - testDurationCaseSigned("-1.45us", -(1450)); - testDurationCaseSigned("1.5us", 3 * std.time.ns_per_us / 2); - testDurationCaseSigned("-1.5us", -(3 * std.time.ns_per_us / 2)); - testDurationCaseSigned("14.5us", 14500); - testDurationCaseSigned("-14.5us", -(14500)); - testDurationCaseSigned("145us", 145000); - testDurationCaseSigned("-145us", -(145000)); - testDurationCaseSigned("999.999us", std.time.ns_per_ms - 1); - testDurationCaseSigned("-999.999us", -(std.time.ns_per_ms - 1)); - testDurationCaseSigned("1ms", std.time.ns_per_ms + 1); - testDurationCaseSigned("-1ms", -(std.time.ns_per_ms + 1)); - testDurationCaseSigned("1.5ms", 3 * std.time.ns_per_ms / 2); - testDurationCaseSigned("-1.5ms", -(3 * std.time.ns_per_ms / 2)); - testDurationCaseSigned("1.11ms", 1110000); - testDurationCaseSigned("-1.11ms", -(1110000)); - testDurationCaseSigned("1.111ms", 1111000); - testDurationCaseSigned("-1.111ms", -(1111000)); - testDurationCaseSigned("1.111ms", 1111100); - testDurationCaseSigned("-1.111ms", -(1111100)); - testDurationCaseSigned("999.999ms", std.time.ns_per_s - 1); - testDurationCaseSigned("-999.999ms", -(std.time.ns_per_s - 1)); - testDurationCaseSigned("1s", std.time.ns_per_s); - testDurationCaseSigned("-1s", -(std.time.ns_per_s)); - testDurationCaseSigned("59.999s", std.time.ns_per_min - 1); - testDurationCaseSigned("-59.999s", -(std.time.ns_per_min - 1)); - testDurationCaseSigned("1m", std.time.ns_per_min); - testDurationCaseSigned("-1m", -(std.time.ns_per_min)); - testDurationCaseSigned("1h", std.time.ns_per_hour); - testDurationCaseSigned("-1h", -(std.time.ns_per_hour)); - testDurationCaseSigned("1d", std.time.ns_per_day); - testDurationCaseSigned("-1d", -(std.time.ns_per_day)); - testDurationCaseSigned("1w", std.time.ns_per_week); - testDurationCaseSigned("-1w", -(std.time.ns_per_week)); - testDurationCaseSigned("1y", 365 * std.time.ns_per_day); - testDurationCaseSigned("-1y", -(365 * std.time.ns_per_day)); - testDurationCaseSigned("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1d - testDurationCaseSigned("-1y52w23h59m59.999s", -(730 * std.time.ns_per_day - 1)); // 365d = 52w1d - testDurationCaseSigned("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms); - testDurationCaseSigned("-1y1h1.001s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms)); - testDurationCaseSigned("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us); - testDurationCaseSigned("-1y1h1s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us)); - testDurationCaseSigned("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1); - testDurationCaseSigned("-1y1h999.999us", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1)); - testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms); - testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms)); - testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1); - testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1)); - testDurationCaseSigned("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999); - testDurationCaseSigned("-1y1m999ns", -(365 * std.time.ns_per_day + std.time.ns_per_min + 999)); - testDurationCaseSigned("292y24w3d23h47m16.854s", std.math.maxInt(i64)); - testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64) + 1); - testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64)); - - testing.expectFmt("=======0ns", "{s:=>10}", .{0}); - testing.expectFmt("1ns=======", "{s:=<10}", .{1}); - testing.expectFmt("-1ns======", "{s:=<10}", .{-(1)}); - testing.expectFmt(" -999ns ", "{s:^10}", .{-(std.time.ns_per_us - 1)}); -} - -fn testDurationCase(expected: []const u8, input: u64) !void { - var buf: [24]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buf); - try bw.printDurationUnsigned(input); - try testing.expectEqualStrings(expected, bw.getWritten()); -} - -fn testDurationCaseSigned(expected: []const u8, input: i64) !void { - var buf: [24]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buf); - try bw.printDurationSigned(input); - try testing.expectEqualStrings(expected, bw.getWritten()); -} - -test printIntOptions { - try testPrintIntCase("-1", @as(i1, -1), 10, .lower, .{}); - - try testPrintIntCase("-101111000110000101001110", @as(i32, -12345678), 2, .lower, .{}); - try testPrintIntCase("-12345678", @as(i32, -12345678), 10, .lower, .{}); - try testPrintIntCase("-bc614e", @as(i32, -12345678), 16, .lower, .{}); - try testPrintIntCase("-BC614E", @as(i32, -12345678), 16, .upper, .{}); - - try testPrintIntCase("12345678", @as(u32, 12345678), 10, .upper, .{}); - - try testPrintIntCase(" 666", @as(u32, 666), 10, .lower, .{ .width = 6 }); - try testPrintIntCase(" 1234", @as(u32, 0x1234), 16, .lower, .{ .width = 6 }); - try testPrintIntCase("1234", @as(u32, 0x1234), 16, .lower, .{ .width = 1 }); - - try testPrintIntCase("+42", @as(i32, 42), 10, .lower, .{ .width = 3 }); - try testPrintIntCase("-42", @as(i32, -42), 10, .lower, .{ .width = 3 }); -} - -test "printInt with comptime_int" { - var buf: [20]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buf); - try bw.printInt(@as(comptime_int, 123456789123456789), "", .{}); - try std.testing.expectEqualStrings("123456789123456789", bw.getWritten()); -} - -test "printFloat with comptime_float" { - var buf: [20]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buf); - try bw.printFloat("", .{}, @as(comptime_float, 1.0)); - try std.testing.expectEqualStrings(bw.getWritten(), "1e0"); - try std.testing.expectFmt("1e0", "{}", .{1.0}); -} - -fn testPrintIntCase(expected: []const u8, value: anytype, base: u8, case: std.fmt.Case, options: std.fmt.Options) !void { - var buffer: [100]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buffer); - bw.printIntOptions(value, base, case, options); - try testing.expectEqualStrings(expected, bw.getWritten()); -} - -test printByteSize { - try testing.expectFmt("file size: 42B\n", "file size: {B}\n", .{42}); - try testing.expectFmt("file size: 42B\n", "file size: {Bi}\n", .{42}); - try testing.expectFmt("file size: 63MB\n", "file size: {B}\n", .{63 * 1000 * 1000}); - try testing.expectFmt("file size: 63MiB\n", "file size: {Bi}\n", .{63 * 1024 * 1024}); - try testing.expectFmt("file size: 42B\n", "file size: {B:.2}\n", .{42}); - try testing.expectFmt("file size: 42B\n", "file size: {B:>9.2}\n", .{42}); - try testing.expectFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{63 * 1024 * 1024}); - try testing.expectFmt("file size: 60.08MiB\n", "file size: {Bi:.2}\n", .{63 * 1000 * 1000}); - try testing.expectFmt("file size: =66.06MB=\n", "file size: {B:=^9.2}\n", .{63 * 1024 * 1024}); - try testing.expectFmt("file size: 66.06MB\n", "file size: {B: >9.2}\n", .{63 * 1024 * 1024}); - try testing.expectFmt("file size: 66.06MB \n", "file size: {B: <9.2}\n", .{63 * 1024 * 1024}); - try testing.expectFmt("file size: 0.01844674407370955ZB\n", "file size: {B}\n", .{std.math.maxInt(u64)}); -} - -test "bytes.hex" { - const some_bytes = "\xCA\xFE\xBA\xBE"; - try std.testing.expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes}); - try std.testing.expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes}); - try std.testing.expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]}); - try std.testing.expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]}); - const bytes_with_zeros = "\x00\x0E\xBA\xBE"; - try std.testing.expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros}); -} - -test initFixed { - { - var buf: [255]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buf); - try bw.print("{s}{s}!", .{ "Hello", "World" }); - try testing.expectEqualStrings("HelloWorld!", bw.getWritten()); - } - - comptime { - var buf: [255]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buf); - try bw.print("{s}{s}!", .{ "Hello", "World" }); - try testing.expectEqualStrings("HelloWorld!", bw.getWritten()); - } -} - -test "fixed output" { - var buffer: [10]u8 = undefined; - var bw: BufferedWriter = undefined; - bw.initFixed(&buffer); - - try bw.writeAll("Hello"); - try testing.expect(std.mem.eql(u8, bw.getWritten(), "Hello")); - - try bw.writeAll("world"); - try testing.expect(std.mem.eql(u8, bw.getWritten(), "Helloworld")); - - try testing.expectError(error.WriteStreamEnd, bw.writeAll("!")); - try testing.expect(std.mem.eql(u8, bw.getWritten(), "Helloworld")); - - bw.reset(); - try testing.expect(bw.getWritten().len == 0); - - try testing.expectError(error.WriteStreamEnd, bw.writeAll("Hello world!")); - try testing.expect(std.mem.eql(u8, bw.getWritten(), "Hello worl")); - - try bw.seekTo((try bw.getEndPos()) + 1); - try testing.expectError(error.WriteStreamEnd, bw.writeAll("H")); -} - -test flushLimit { - return error.Unimplemented; -} diff --git a/lib/std/io/Reader.zig b/lib/std/io/Reader.zig index 27d9170e3b..2f13b467bb 100644 --- a/lib/std/io/Reader.zig +++ b/lib/std/io/Reader.zig @@ -1149,8 +1149,7 @@ pub fn restitute(r: *Reader, n: usize) void { } test fixed { - var r: Reader = undefined; - r.initFixed("a\x02"); + var r: Reader = .fixed("a\x02"); try testing.expect((try r.takeByte()) == 'a'); try testing.expect((try r.takeEnum(enum(u8) { a = 0, @@ -1186,8 +1185,7 @@ test peekArray { } test discardAll { - var r: Reader = undefined; - r.initFixed("foobar"); + var r: Reader = .fixed("foobar"); try r.discard(3); try testing.expectEqualStrings("bar", try r.take(3)); try r.discard(0); @@ -1300,8 +1298,7 @@ test readVec { test "expected error.EndOfStream" { // Unit test inspired by https://github.com/ziglang/zig/issues/17733 - var r: std.io.Reader = undefined; - r.initFixed(""); + var r: std.io.Reader = .fixed(""); try std.testing.expectError(error.EndOfStream, r.readEnum(enum(u8) { a, b }, .little)); try std.testing.expectError(error.EndOfStream, r.isBytes("foo")); } diff --git a/lib/std/io/Reader/Limited.zig b/lib/std/io/Reader/Limited.zig index 0c6d3d32ea..9476b97804 100644 --- a/lib/std/io/Reader/Limited.zig +++ b/lib/std/io/Reader/Limited.zig @@ -2,7 +2,7 @@ const Limited = @This(); const std = @import("../../std.zig"); const Reader = std.io.Reader; -const BufferedWriter = std.io.BufferedWriter; +const Writer = std.io.Writer; const Limit = std.io.Limit; unlimited: *Reader, @@ -25,10 +25,10 @@ pub fn init(reader: *Reader, limit: Limit, buffer: []u8) Limited { }; } -fn stream(context: ?*anyopaque, bw: *BufferedWriter, limit: Limit) Reader.StreamError!usize { +fn stream(context: ?*anyopaque, w: *Writer, limit: Limit) Reader.StreamError!usize { const l: *Limited = @alignCast(@ptrCast(context)); const combined_limit = limit.min(l.remaining); - const n = try l.unlimited_reader.read(bw, combined_limit); + const n = try l.unlimited_reader.read(w, combined_limit); l.remaining = l.remaining.subtract(n).?; return n; } diff --git a/lib/std/io/Writer.zig b/lib/std/io/Writer.zig index b7f55e7a2c..19346f58c0 100644 --- a/lib/std/io/Writer.zig +++ b/lib/std/io/Writer.zig @@ -1,51 +1,71 @@ +const builtin = @import("builtin"); +const native_endian = builtin.target.cpu.arch.endian(); + +const Writer = @This(); const std = @import("../std.zig"); const assert = std.debug.assert; -const Writer = @This(); const Limit = std.io.Limit; const File = std.fs.File; +const testing = std.testing; +const Allocator = std.mem.Allocator; context: ?*anyopaque, vtable: *const VTable, +/// If this has length zero, the writer is unbuffered, and `flush` is a no-op. +buffer: []u8, +/// In `buffer` before this are buffered bytes, after this is `undefined`. +end: usize = 0, +/// Tracks total number of bytes written to this `Writer`. This value +/// only increases. In the case of fixed mode, this value always equals `end`. +/// +/// This value is maintained by the interface; `VTable` function +/// implementations need not modify it. +count: usize = 0, pub const VTable = struct { - /// Each slice in `data` is written in order. + /// Sends bytes to the logical sink. A write will only be sent here if it + /// could not fit into `buffer`. + /// + /// `buffer[0..end]` is consumed first, followed by each slice of `data` in + /// order. Elements of `data` may alias each other but may not alias + /// `buffer`. + /// + /// This function modifies `Writer` state. /// /// `data.len` must be greater than zero, and the last element of `data` is /// special. It is repeated as necessary so that it is written `splat` - /// number of times. + /// number of times, which may be zero. /// - /// Number of bytes actually written is returned. + /// Number of bytes actually written is returned, excluding bytes from + /// `buffer`. Bytes from `buffer` are tracked by modifying `end`. /// /// Number of bytes returned may be zero, which does not mean - /// end-of-stream. A subsequent call may return nonzero, or may signal end - /// of stream via `error.WriteFailed`. - writeSplat: *const fn (ctx: ?*anyopaque, data: []const []const u8, splat: usize) Error!usize, + /// end-of-stream. A subsequent call may return nonzero, or signal end of + /// stream via `error.WriteFailed`. + drain: *const fn (w: *Writer, data: []const []const u8, splat: usize) Error!usize, - /// Writes contents from an open file. `headers` are written first, then - /// `limit` bytes of `file` starting from `offset`, then `trailers`. + /// Copies contents from an open file to the logical sink. `buffer[0..end]` + /// is consumed first, followed by `limit` bytes from `file_reader`. /// - /// Number of bytes actually written is returned, which may lie within - /// headers, the file, trailers, or anywhere in between. + /// Number of bytes actually written is returned, excluding bytes from + /// `buffer`. Bytes from `buffer` are tracked by modifying `end`. /// - /// Number of bytes returned may be zero, which does not mean - /// end-of-stream. A subsequent call may return nonzero, or may signal end - /// of stream via `error.WriteFailed`. + /// Number of bytes returned may be zero, which does not necessarily mean + /// end-of-stream. A subsequent call may return nonzero, or signal end of + /// stream via `error.WriteFailed`. Caller must check `file_reader` state + /// (`File.Reader.atEnd`) to disambiguate between a zero-length read or + /// write, and whether the file reached the end. /// /// `error.Unimplemented` indicates the callee cannot offer a more /// efficient implementation than the caller performing its own reads. - writeFile: *const fn ( - ctx: ?*anyopaque, + sendFile: *const fn ( + w: *Writer, file_reader: *File.Reader, /// Maximum amount of bytes to read from the file. Implementations may - /// assume that the file size does not exceed this amount. - /// - /// `headers_and_trailers` do not count towards this limit. + /// assume that the file size does not exceed this amount. Data from + /// `buffer` does not count towards this limit. limit: Limit, - /// Headers and trailers must be passed together so that in case `len` is - /// zero, they can be forwarded directly as one contiguous slice of memory. - headers_and_trailers: []const []const u8, - headers_len: usize, - ) FileError!usize, + ) FileError!usize = unimplementedSendFile, }; pub const Error = error{ @@ -70,97 +90,1602 @@ pub const FileError = error{ Unimplemented, }; -pub fn writeVec(w: Writer, data: []const []const u8) Error!usize { - assert(data.len > 0); - return w.vtable.writeSplat(w.context, data, 1); -} - -pub fn writeSplat(w: Writer, data: []const []const u8, splat: usize) Error!usize { - assert(data.len > 0); - return w.vtable.writeSplat(w.context, data, splat); -} - -pub fn writeFile( - w: Writer, - file_reader: *File.Reader, - limit: Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, -) FileError!usize { - return w.vtable.writeFile(w.context, file_reader, limit, headers_and_trailers, headers_len); -} - -pub fn buffered(w: Writer, buffer: []u8) std.io.BufferedWriter { +/// Writes to `buffer` and returns `error.WriteFailed` when it is full. Unless +/// modified externally, `count` will always equal `end`. +pub fn fixed(buffer: []u8) Writer { return .{ + .context = undefined, + .vtable = &.{ .drain = fixedDrain }, .buffer = buffer, - .unbuffered_writer = w, }; } -pub fn unbuffered(w: Writer) std.io.BufferedWriter { - return w.buffered(&.{}); -} - -pub fn failingWriteSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Error!usize { - _ = context; - _ = data; - _ = splat; - return error.WriteFailed; -} - -pub fn failingWriteFile( - context: ?*anyopaque, - file_reader: *File.Reader, - limit: Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, -) FileError!usize { - _ = context; - _ = file_reader; - _ = limit; - _ = headers_and_trailers; - _ = headers_len; - return error.WriteFailed; +pub fn hashed(w: *Writer, hasher: anytype) Hashed(@TypeOf(hasher)) { + return .{ .out = w, .hasher = hasher }; } pub const failing: Writer = .{ .context = undefined, .vtable = &.{ - .writeSplat = failingWriteSplat, - .writeFile = failingWriteFile, + .drain = failingDrain, + .sendFile = failingSendFile, }, }; -pub fn discardingWriteSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Error!usize { - _ = context; - const headers = data[0 .. data.len - 1]; - const pattern = data[headers.len..]; +pub fn discarding(buffer: []u8) Writer { + return .{ + .context = undefined, + .vtable = &.{ + .drain = discardingDrain, + .sendFile = discardingSendFile, + }, + .buffer = buffer, + }; +} + +/// Returns the contents not yet drained. +pub fn buffered(w: *const Writer) []u8 { + return w.buffer[0..w.end]; +} + +pub fn countSplat(n: usize, data: []const []const u8, splat: usize) usize { + assert(data.len > 0); + var total: usize = n; + for (data[0 .. data.len - 1]) |buf| total += buf.len; + total += data[data.len - 1].len * splat; + return total; +} + +pub fn countSendFileUpperBound(n: usize, file_reader: *File.Reader, limit: Limit) ?usize { + const total: u64 = @min(@intFromEnum(limit), file_reader.getSize() orelse return null); + return std.math.lossyCast(usize, total + n); +} + +/// If the total number of bytes of `data` fits inside `unusedCapacitySlice`, +/// this function is guaranteed to not fail, not call into `VTable`, and return +/// the total bytes inside `data`. +pub fn writeVec(w: *Writer, data: []const []const u8) Error!usize { + return writeSplat(w, data, 1); +} + +/// If the number of bytes to write based on `data` and `splat` fits inside +/// `unusedCapacitySlice`, this function is guaranteed to not fail, not call +/// into `VTable`, and return the full number of bytes. +pub fn writeSplat(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + assert(data.len > 0); + const buffer = w.buffer; + const count = countSplat(0, data, splat); + if (w.end + count > buffer.len) { + const end = w.end; + const n = try w.vtable.drain(w, data, splat); + return n -| end; + } + w.count += count; + for (data) |bytes| { + @memcpy(buffer[w.end..][0..bytes.len], bytes); + w.end += bytes.len; + } + const pattern = data[data.len - 1]; + if (splat == 0) { + @branchHint(.unlikely); + // It was added in the loop above; undo it here. + w.end -= pattern.len; + return count; + } + const remaining_splat = splat - 1; + switch (pattern.len) { + 0 => {}, + 1 => { + @memset(buffer[w.end..][0..remaining_splat], pattern[0]); + w.end += remaining_splat; + }, + else => { + const new_end = w.end + pattern.len * remaining_splat; + while (w.end < new_end) : (w.end += pattern.len) { + @memcpy(buffer[w.end..][0..pattern.len], pattern); + } + }, + } + return count; +} + +/// Equivalent to `writeSplat` but writes at most `limit` bytes. +pub fn writeSplatLimit( + w: *Writer, + data: []const []const u8, + splat: usize, + limit: Limit, +) Error!usize { + _ = w; + _ = data; + _ = splat; + _ = limit; + @panic("TODO"); +} + +/// Drains all remaining buffered data. +pub fn flush(w: *Writer) Error!void { + const drainFn = w.vtable.drain; + // This implementation allows for drain functions that do not modify `end`, + // such as `fixedDrain`. + var remaining = w.end; + while (remaining != 0) remaining -= try drainFn(w, &.{""}, 1); +} + +pub fn unusedCapacitySlice(w: *const Writer) []u8 { + return w.buffer[w.end..]; +} + +pub fn unusedCapacityLen(w: *const Writer) usize { + return w.buffer.len - w.end; +} + +/// Asserts the provided buffer has total capacity enough for `len`. +/// +/// Advances the buffer end position by `len`. +pub fn writableArray(w: *Writer, comptime len: usize) Error!*[len]u8 { + const big_slice = try w.writableSliceGreedy(len); + advance(w, len); + return big_slice[0..len]; +} + +/// Asserts the provided buffer has total capacity enough for `len`. +/// +/// Advances the buffer end position by `len`. +pub fn writableSlice(w: *Writer, len: usize) Error![]u8 { + const big_slice = try w.writableSliceGreedy(len); + advance(w, len); + return big_slice[0..len]; +} + +/// Asserts the provided buffer has total capacity enough for `minimum_length`. +/// +/// Does not `advance` the buffer end position. +/// +/// If `minimum_length` is zero, this is equivalent to `unusedCapacitySlice`. +pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 { + assert(w.buffer.len >= minimum_length); + const cap_slice = w.buffer[w.end..]; + if (cap_slice.len >= minimum_length) { + @branchHint(.likely); + return cap_slice; + } + const buffer = w.buffer[0..w.end]; + const n = try w.unbuffered_writer.writeVec(&.{buffer}); + if (n == buffer.len) { + @branchHint(.likely); + w.end = 0; + return w.buffer; + } + if (n > 0) { + const remainder = buffer[n..]; + std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); + w.end = remainder.len; + } + return w.buffer[w.end..]; +} + +pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void { + _ = try writableSliceGreedy(w, n); +} + +pub fn undo(w: *Writer, n: usize) void { + w.end -= n; + w.count -= n; +} + +/// After calling `writableSliceGreedy`, this function tracks how many bytes +/// were written to it. +/// +/// This is not needed when using `writableSlice` or `writableArray`. +pub fn advance(w: *Writer, n: usize) void { + const new_end = w.end + n; + assert(new_end <= w.buffer.len); + w.end = new_end; + w.count += n; +} + +/// The `data` parameter is mutable because this function needs to mutate the +/// fields in order to handle partial writes from `VTable.writeSplat`. +pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void { + var index: usize = 0; + var truncate: usize = 0; + while (index < data.len) { + { + const untruncated = data[index]; + data[index] = untruncated[truncate..]; + defer data[index] = untruncated; + truncate += try w.writeVec(data[index..]); + } + while (index < data.len and truncate >= data[index].len) { + truncate -= data[index].len; + index += 1; + } + } +} + +/// The `data` parameter is mutable because this function needs to mutate the +/// fields in order to handle partial writes from `VTable.writeSplat`. +pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void { + var index: usize = 0; + var truncate: usize = 0; + var remaining_splat = splat; + while (index + 1 < data.len) { + { + const untruncated = data[index]; + data[index] = untruncated[truncate..]; + defer data[index] = untruncated; + truncate += try w.writeSplat(data[index..], remaining_splat); + } + while (truncate >= data[index].len) { + if (index + 1 < data.len) { + truncate -= data[index].len; + index += 1; + } else { + const last = data[data.len - 1]; + remaining_splat -= @divExact(truncate, last.len); + while (remaining_splat > 0) { + const n = try w.writeSplat(data[data.len - 1 ..][0..1], remaining_splat); + remaining_splat -= @divExact(n, last.len); + } + return; + } + } + } +} + +pub fn write(w: *Writer, bytes: []const u8) Error!usize { + if (w.end + bytes.len <= w.buffer.len) { + @memcpy(w.buffer[w.end..][0..bytes.len], bytes); + w.end += bytes.len; + w.count += bytes.len; + return bytes.len; + } + const end = w.end; + const n = try w.vtable.drain(w, &.{bytes}, 1); + return n -| end; +} + +/// Calls `write` as many times as necessary such that all of `bytes` are +/// transferred. +pub fn writeAll(w: *Writer, bytes: []const u8) Error!void { + var index: usize = 0; + while (index < bytes.len) index += try w.write(bytes[index..]); +} + +pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void { + try std.fmt.format(w, format, args); +} + +pub fn writeByte(w: *Writer, byte: u8) Error!void { + const buffer = w.buffer[0..w.end]; + if (buffer.len < w.buffer.len) { + @branchHint(.likely); + buffer.ptr[buffer.len] = byte; + w.end = buffer.len + 1; + w.count += 1; + return; + } + var buffers: [2][]const u8 = .{ buffer, &.{byte} }; + while (true) { + const n = try w.unbuffered_writer.writeVec(&buffers); + if (n == 0) { + @branchHint(.unlikely); + continue; + } + w.count += 1; + if (n >= buffer.len) { + @branchHint(.likely); + if (n > buffer.len) { + @branchHint(.likely); + w.end = 0; + return; + } else { + buffer[0] = byte; + w.end = 1; + return; + } + } + const remainder = buffer[n..]; + std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); + buffer[remainder.len] = byte; + w.end = remainder.len + 1; + return; + } +} + +/// Writes the same byte many times, performing the underlying write call as +/// many times as necessary. +pub fn splatByteAll(w: *Writer, byte: u8, n: usize) Error!void { + var remaining: usize = n; + while (remaining > 0) remaining -= try w.splatByte(byte, remaining); +} + +/// Writes the same byte many times, allowing short writes. +/// +/// Does maximum of one underlying `VTable.drain`. +pub fn splatByte(w: *Writer, byte: u8, n: usize) Error!usize { + return writeSplat(w, &.{&.{byte}}, n); +} + +/// Writes the same slice many times, performing the underlying write call as +/// many times as necessary. +pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void { + var remaining_bytes: usize = bytes.len * splat; + remaining_bytes -= try w.splatBytes(bytes, splat); + while (remaining_bytes > 0) { + const leftover = remaining_bytes % bytes.len; + const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes }; + remaining_bytes -= try w.splatBytes(&buffers, splat); + } +} + +/// Writes the same slice many times, allowing short writes. +/// +/// Does maximum of one underlying `VTable.writeSplat`. +pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize { + return writeSplat(w, &.{bytes}, n); +} + +/// Asserts the `buffer` was initialized with a capacity of at least `@sizeOf(T)` bytes. +pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.builtin.Endian) Error!void { + var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined; + std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); + return w.writeAll(&bytes); +} + +pub fn writeStruct(w: *Writer, value: anytype) Error!void { + // Only extern and packed structs have defined in-memory layout. + comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto); + return w.writeAll(std.mem.asBytes(&value)); +} + +/// The function is inline to avoid the dead code in case `endian` is +/// comptime-known and matches host endianness. +/// TODO: make sure this value is not a reference type +pub inline fn writeStructEndian(w: *Writer, value: anytype, endian: std.builtin.Endian) Error!void { + if (native_endian == endian) { + return w.writeStruct(value); + } else { + var copy = value; + std.mem.byteSwapAllFields(@TypeOf(value), ©); + return w.writeStruct(copy); + } +} + +pub inline fn writeSliceEndian( + w: *Writer, + Elem: type, + slice: []const Elem, + endian: std.builtin.Endian, +) Error!void { + if (native_endian == endian) { + return writeAll(w, @ptrCast(slice)); + } else { + return w.writeArraySwap(w, Elem, slice); + } +} + +/// Asserts that the buffer storage capacity is at least enough to store `@sizeOf(Elem)` +pub fn writeSliceSwap(w: *Writer, Elem: type, slice: []const Elem) Error!void { + // copy to storage first, then swap in place + _ = w; + _ = slice; + @panic("TODO"); +} + +/// Unlike `writeSplat` and `writeVec`, this function will call into `VTable` +/// even if there is enough buffer capacity for the file contents. +/// +/// Although it would be possible to eliminate `error.Unimplemented` from the +/// error set by reading directly into the buffer in such case, this is not +/// done because it is more efficient to do it higher up the call stack so that +/// the error does not occur with each write. +/// +/// See `sendFileReading` for an alternative that does not have +/// `error.Unimplemented` in the error set. +pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { + const end = w.end; + const n = try w.vtable.sendFile(w, file_reader, limit); + return n -| end; +} + +/// Asserts nonzero buffer capacity. +pub fn sendFileReading(w: *Writer, file_reader: *File.Reader, limit: Limit) ReadingFileError!usize { + const dest = limit.slice(try w.writableSliceGreedy(1)); + const n = file_reader.read(dest) catch |err| switch (err) { + error.EndOfStream => 0, + error.ReadFailed => return error.ReadFailed, + }; + w.advance(n); + return n; +} + +pub fn sendFileAll(w: *Writer, file_reader: *File.Reader, limit: Limit) ReadingFileError!usize { + var remaining = @intFromEnum(limit); + while (remaining > 0) { + const n = sendFile(w, file_reader, .limited(remaining)) catch |err| switch (err) { + error.EndOfStream => return 0, + error.ReadFailed => return error.ReadFailed, + error.WriteFailed => return error.WriteFailed, + error.Unimplemented => { + file_reader.mode = file_reader.mode.toReading(); + try w.sendFileReadingAll(file_reader, remaining); + return; + }, + }; + remaining -= n; + } + return @intFromEnum(limit) - remaining; +} + +/// Equivalent to `sendFileAll` but uses direct `pread` and `read` calls on +/// `file` rather than `sendFile`. This is generally used as a fallback when +/// the underlying implementation returns `error.Unimplemented`, which is why +/// that error code does not appear in this function's error set. +/// +/// Asserts nonzero buffer capacity. +pub fn sendFileReadingAll(w: *Writer, file_reader: *File.Reader, limit: Limit) ReadingFileError!void { + var remaining = limit; + while (remaining.nonzero()) { + const n = try sendFileReading(w, file_reader, remaining); + if (n == 0) return; + remaining = remaining.subtract(n).?; + } +} + +pub fn alignBuffer( + w: *Writer, + buffer: []const u8, + width: usize, + alignment: std.fmt.Alignment, + fill: u8, +) Error!void { + const padding = if (buffer.len < width) width - buffer.len else 0; + if (padding == 0) { + @branchHint(.likely); + return w.writeAll(buffer); + } + switch (alignment) { + .left => { + try w.writeAll(buffer); + try w.splatByteAll(fill, padding); + }, + .center => { + const left_padding = padding / 2; + const right_padding = (padding + 1) / 2; + try w.splatByteAll(fill, left_padding); + try w.writeAll(buffer); + try w.splatByteAll(fill, right_padding); + }, + .right => { + try w.splatByteAll(fill, padding); + try w.writeAll(buffer); + }, + } +} + +pub fn alignBufferOptions(w: *Writer, buffer: []const u8, options: std.fmt.Options) Error!void { + return w.alignBuffer(buffer, options.width orelse buffer.len, options.alignment, options.fill); +} + +pub fn printAddress(w: *Writer, value: anytype) Error!void { + const T = @TypeOf(value); + switch (@typeInfo(T)) { + .pointer => |info| { + try w.writeAll(@typeName(info.child) ++ "@"); + if (info.size == .slice) + try w.printIntOptions(@intFromPtr(value.ptr), 16, .lower, .{}) + else + try w.printIntOptions(@intFromPtr(value), 16, .lower, .{}); + return; + }, + .optional => |info| { + if (@typeInfo(info.child) == .pointer) { + try w.writeAll(@typeName(info.child) ++ "@"); + try w.printIntOptions(@intFromPtr(value), 16, .lower, .{}); + return; + } + }, + else => {}, + } + + @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier"); +} + +pub fn printValue( + w: *Writer, + comptime fmt: []const u8, + options: std.fmt.Options, + value: anytype, + max_depth: usize, +) Error!void { + const T = @TypeOf(value); + + if (comptime std.mem.eql(u8, fmt, "*")) { + return w.printAddress(value); + } + + const is_any = comptime std.mem.eql(u8, fmt, ANY); + if (!is_any and std.meta.hasMethod(T, "format")) { + if (fmt.len > 0 and fmt[0] == 'f') { + return value.format(w, fmt[1..]); + } else if (fmt.len == 0) { + // after 0.15.0 is tagged, delete the hasMethod condition and this compile error + @compileError("ambiguous format string; specify {f} to call format method, or {any} to skip it"); + } + } + + switch (@typeInfo(T)) { + .float, .comptime_float => return w.printFloat(if (is_any) "d" else fmt, options, value), + .int, .comptime_int => return w.printInt(if (is_any) "d" else fmt, options, value), + .bool => { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + return w.alignBufferOptions(if (value) "true" else "false", options); + }, + .void => { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + return w.alignBufferOptions("void", options); + }, + .optional => { + const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '?') + stripOptionalOrErrorUnionSpec(fmt) + else if (is_any) + ANY + else + @compileError("cannot print optional without a specifier (i.e. {?} or {any})"); + if (value) |payload| { + return w.printValue(remaining_fmt, options, payload, max_depth); + } else { + return w.alignBufferOptions("null", options); + } + }, + .error_union => { + const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '!') + stripOptionalOrErrorUnionSpec(fmt) + else if (is_any) + ANY + else + @compileError("cannot print error union without a specifier (i.e. {!} or {any})"); + if (value) |payload| { + return w.printValue(remaining_fmt, options, payload, max_depth); + } else |err| { + return w.printValue("", options, err, max_depth); + } + }, + .error_set => { + if (fmt.len == 1 and fmt[0] == 's') return w.writeAll(@errorName(value)); + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + try printErrorSet(w, value); + }, + .@"enum" => { + if (fmt.len == 1 and fmt[0] == 's') { + try w.writeAll(@tagName(value)); + return; + } + if (!is_any) { + if (fmt.len != 0) return printValue(w, fmt, options, @intFromEnum(value), max_depth); + return printValue(w, ANY, options, value, max_depth); + } + const enum_info = @typeInfo(T).@"enum"; + if (enum_info.is_exhaustive) { + var vecs: [3][]const u8 = .{ @typeName(T), ".", @tagName(value) }; + try w.writeVecAll(&vecs); + return; + } + try w.writeAll(@typeName(T)); + @setEvalBranchQuota(3 * enum_info.fields.len); + inline for (enum_info.fields) |field| { + if (@intFromEnum(value) == field.value) { + try w.writeAll("."); + try w.writeAll(@tagName(value)); + return; + } + } + try w.writeByte('('); + try w.printValue(ANY, options, @intFromEnum(value), max_depth); + try w.writeByte(')'); + }, + .@"union" => |info| { + if (!is_any) { + if (fmt.len != 0) invalidFmtError(fmt, value); + return printValue(w, ANY, options, value, max_depth); + } + try w.writeAll(@typeName(T)); + if (max_depth == 0) { + try w.writeAll("{ ... }"); + return; + } + if (info.tag_type) |UnionTagType| { + try w.writeAll("{ ."); + try w.writeAll(@tagName(@as(UnionTagType, value))); + try w.writeAll(" = "); + inline for (info.fields) |u_field| { + if (value == @field(UnionTagType, u_field.name)) { + try w.printValue(ANY, options, @field(value, u_field.name), max_depth - 1); + } + } + try w.writeAll(" }"); + } else { + try w.writeByte('@'); + try w.printIntOptions(@intFromPtr(&value), 16, .lower, options); + } + }, + .@"struct" => |info| { + if (!is_any) { + if (fmt.len != 0) invalidFmtError(fmt, value); + return printValue(w, ANY, options, value, max_depth); + } + if (info.is_tuple) { + // Skip the type and field names when formatting tuples. + if (max_depth == 0) { + try w.writeAll("{ ... }"); + return; + } + try w.writeAll("{"); + inline for (info.fields, 0..) |f, i| { + if (i == 0) { + try w.writeAll(" "); + } else { + try w.writeAll(", "); + } + try w.printValue(ANY, options, @field(value, f.name), max_depth - 1); + } + try w.writeAll(" }"); + return; + } + try w.writeAll(@typeName(T)); + if (max_depth == 0) { + try w.writeAll("{ ... }"); + return; + } + try w.writeAll("{"); + inline for (info.fields, 0..) |f, i| { + if (i == 0) { + try w.writeAll(" ."); + } else { + try w.writeAll(", ."); + } + try w.writeAll(f.name); + try w.writeAll(" = "); + try w.printValue(ANY, options, @field(value, f.name), max_depth - 1); + } + try w.writeAll(" }"); + }, + .pointer => |ptr_info| switch (ptr_info.size) { + .one => switch (@typeInfo(ptr_info.child)) { + .array, .@"enum", .@"union", .@"struct" => { + return w.printValue(fmt, options, value.*, max_depth); + }, + else => { + var buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" }; + try w.writeVecAll(&buffers); + try w.printIntOptions(@intFromPtr(value), 16, .lower, options); + return; + }, + }, + .many, .c => { + if (ptr_info.sentinel() != null) + return w.printValue(fmt, options, std.mem.span(value), max_depth); + if (fmt.len == 1 and fmt[0] == 's' and ptr_info.child == u8) + return w.alignBufferOptions(std.mem.span(value), options); + if (!is_any and fmt.len == 0) + @compileError("cannot format pointer without a specifier (i.e. {s} or {*})"); + if (!is_any and fmt.len != 0) + invalidFmtError(fmt, value); + try w.printAddress(value); + }, + .slice => { + if (!is_any and fmt.len == 0) + @compileError("cannot format slice without a specifier (i.e. {s}, {x}, {b64}, or {any})"); + if (max_depth == 0) + return w.writeAll("{ ... }"); + if (ptr_info.child == u8) switch (fmt.len) { + 1 => switch (fmt[0]) { + 's' => return w.alignBufferOptions(value, options), + 'x' => return w.printHex(value, .lower), + 'X' => return w.printHex(value, .upper), + else => {}, + }, + 3 => if (fmt[0] == 'b' and fmt[1] == '6' and fmt[2] == '4') { + return w.printBase64(value); + }, + else => {}, + }; + try w.writeAll("{ "); + for (value, 0..) |elem, i| { + try w.printValue(fmt, options, elem, max_depth - 1); + if (i != value.len - 1) { + try w.writeAll(", "); + } + } + try w.writeAll(" }"); + }, + }, + .array => |info| { + if (fmt.len == 0) + @compileError("cannot format array without a specifier (i.e. {s} or {any})"); + if (max_depth == 0) { + return w.writeAll("{ ... }"); + } + if (info.child == u8) { + if (fmt[0] == 's') { + return w.alignBufferOptions(&value, options); + } else if (fmt[0] == 'x') { + return w.printHex(&value, .lower); + } else if (fmt[0] == 'X') { + return w.printHex(&value, .upper); + } + } + try w.writeAll("{ "); + for (value, 0..) |elem, i| { + try w.printValue(fmt, options, elem, max_depth - 1); + if (i < value.len - 1) { + try w.writeAll(", "); + } + } + try w.writeAll(" }"); + }, + .vector => |info| { + if (max_depth == 0) { + return w.writeAll("{ ... }"); + } + try w.writeAll("{ "); + var i: usize = 0; + while (i < info.len) : (i += 1) { + try w.printValue(fmt, options, value[i], max_depth - 1); + if (i < info.len - 1) { + try w.writeAll(", "); + } + } + try w.writeAll(" }"); + }, + .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"), + .type => { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + return w.alignBufferOptions(@typeName(value), options); + }, + .enum_literal => { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + const buffer = [_]u8{'.'} ++ @tagName(value); + return w.alignBufferOptions(buffer, options); + }, + .null => { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + return w.alignBufferOptions("null", options); + }, + else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"), + } +} + +fn printErrorSet(w: *Writer, error_set: anyerror) Error!void { + var vecs: [2][]const u8 = .{ "error.", @errorName(error_set) }; + try w.writeVecAll(&vecs); +} + +pub fn printInt( + w: *Writer, + comptime fmt: []const u8, + options: std.fmt.Options, + value: anytype, +) Error!void { + const int_value = if (@TypeOf(value) == comptime_int) blk: { + const Int = std.math.IntFittingRange(value, value); + break :blk @as(Int, value); + } else value; + + switch (fmt.len) { + 0 => return w.printIntOptions(int_value, 10, .lower, options), + 1 => switch (fmt[0]) { + 'd' => return w.printIntOptions(int_value, 10, .lower, options), + 'c' => { + if (@typeInfo(@TypeOf(int_value)).int.bits <= 8) { + return w.printAsciiChar(@as(u8, int_value), options); + } else { + @compileError("cannot print integer that is larger than 8 bits as an ASCII character"); + } + }, + 'u' => { + if (@typeInfo(@TypeOf(int_value)).int.bits <= 21) { + return w.printUnicodeCodepoint(@as(u21, int_value), options); + } else { + @compileError("cannot print integer that is larger than 21 bits as an UTF-8 sequence"); + } + }, + 'b' => return w.printIntOptions(int_value, 2, .lower, options), + 'x' => return w.printIntOptions(int_value, 16, .lower, options), + 'X' => return w.printIntOptions(int_value, 16, .upper, options), + 'o' => return w.printIntOptions(int_value, 8, .lower, options), + 'B' => return w.printByteSize(int_value, .decimal, options), + 'D' => return w.printDuration(int_value, options), + else => invalidFmtError(fmt, value), + }, + 2 => { + if (fmt[0] == 'B' and fmt[1] == 'i') { + return w.printByteSize(int_value, .binary, options); + } else { + invalidFmtError(fmt, value); + } + }, + else => invalidFmtError(fmt, value), + } + comptime unreachable; +} + +pub fn printAsciiChar(w: *Writer, c: u8, options: std.fmt.Options) Error!void { + return w.alignBufferOptions(@as(*const [1]u8, &c), options); +} + +pub fn printAscii(w: *Writer, bytes: []const u8, options: std.fmt.Options) Error!void { + return w.alignBufferOptions(bytes, options); +} + +pub fn printUnicodeCodepoint(w: *Writer, c: u21, options: std.fmt.Options) Error!void { + var buf: [4]u8 = undefined; + const len = try std.unicode.utf8Encode(c, &buf); + return w.alignBufferOptions(buf[0..len], options); +} + +pub fn printIntOptions( + w: *Writer, + value: anytype, + base: u8, + case: std.fmt.Case, + options: std.fmt.Options, +) Error!void { + assert(base >= 2); + + const int_value = if (@TypeOf(value) == comptime_int) blk: { + const Int = std.math.IntFittingRange(value, value); + break :blk @as(Int, value); + } else value; + + const value_info = @typeInfo(@TypeOf(int_value)).int; + + // The type must have the same size as `base` or be wider in order for the + // division to work + const min_int_bits = comptime @max(value_info.bits, 8); + const MinInt = std.meta.Int(.unsigned, min_int_bits); + + const abs_value = @abs(int_value); + // The worst case in terms of space needed is base 2, plus 1 for the sign + var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined; + + var a: MinInt = abs_value; + var index: usize = buf.len; + + if (base == 10) { + while (a >= 100) : (a = @divTrunc(a, 100)) { + index -= 2; + buf[index..][0..2].* = std.fmt.digits2(@intCast(a % 100)); + } + + if (a < 10) { + index -= 1; + buf[index] = '0' + @as(u8, @intCast(a)); + } else { + index -= 2; + buf[index..][0..2].* = std.fmt.digits2(@intCast(a)); + } + } else { + while (true) { + const digit = a % base; + index -= 1; + buf[index] = std.fmt.digitToChar(@intCast(digit), case); + a /= base; + if (a == 0) break; + } + } + + if (value_info.signedness == .signed) { + if (value < 0) { + // Negative integer + index -= 1; + buf[index] = '-'; + } else if (options.width == null or options.width.? == 0) { + // Positive integer, omit the plus sign + } else { + // Positive integer + index -= 1; + buf[index] = '+'; + } + } + + return w.alignBufferOptions(buf[index..], options); +} + +pub fn printFloat( + w: *Writer, + comptime fmt: []const u8, + options: std.fmt.Options, + value: anytype, +) Error!void { + var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined; + + if (fmt.len > 1) invalidFmtError(fmt, value); + switch (if (fmt.len == 0) 'e' else fmt[0]) { + 'e' => { + const s = std.fmt.float.render(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) { + error.BufferTooSmall => "(float)", + }; + return w.alignBufferOptions(s, options); + }, + 'd' => { + const s = std.fmt.float.render(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { + error.BufferTooSmall => "(float)", + }; + return w.alignBufferOptions(s, options); + }, + 'x' => { + var sub_bw: Writer = .fixed(&buf); + sub_bw.printFloatHexadecimal(value, options.precision) catch unreachable; + return w.alignBufferOptions(sub_bw.buffered(), options); + }, + else => invalidFmtError(fmt, value), + } +} + +pub fn printFloatHexadecimal(w: *Writer, value: anytype, opt_precision: ?usize) Error!void { + if (std.math.signbit(value)) try w.writeByte('-'); + if (std.math.isNan(value)) return w.writeAll("nan"); + if (std.math.isInf(value)) return w.writeAll("inf"); + + const T = @TypeOf(value); + const TU = std.meta.Int(.unsigned, @bitSizeOf(T)); + + const mantissa_bits = std.math.floatMantissaBits(T); + const fractional_bits = std.math.floatFractionalBits(T); + const exponent_bits = std.math.floatExponentBits(T); + const mantissa_mask = (1 << mantissa_bits) - 1; + const exponent_mask = (1 << exponent_bits) - 1; + const exponent_bias = (1 << (exponent_bits - 1)) - 1; + + const as_bits: TU = @bitCast(value); + var mantissa = as_bits & mantissa_mask; + var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask)); + + const is_denormal = exponent == 0 and mantissa != 0; + const is_zero = exponent == 0 and mantissa == 0; + + if (is_zero) { + // Handle this case here to simplify the logic below. + try w.writeAll("0x0"); + if (opt_precision) |precision| { + if (precision > 0) { + try w.writeAll("."); + try w.splatByteAll('0', precision); + } + } else { + try w.writeAll(".0"); + } + try w.writeAll("p0"); + return; + } + + if (is_denormal) { + // Adjust the exponent for printing. + exponent += 1; + } else { + if (fractional_bits == mantissa_bits) + mantissa |= 1 << fractional_bits; // Add the implicit integer bit. + } + + const mantissa_digits = (fractional_bits + 3) / 4; + // Fill in zeroes to round the fraction width to a multiple of 4. + mantissa <<= mantissa_digits * 4 - fractional_bits; + + if (opt_precision) |precision| { + // Round if needed. + if (precision < mantissa_digits) { + // We always have at least 4 extra bits. + var extra_bits = (mantissa_digits - precision) * 4; + // The result LSB is the Guard bit, we need two more (Round and + // Sticky) to round the value. + while (extra_bits > 2) { + mantissa = (mantissa >> 1) | (mantissa & 1); + extra_bits -= 1; + } + // Round to nearest, tie to even. + mantissa |= @intFromBool(mantissa & 0b100 != 0); + mantissa += 1; + // Drop the excess bits. + mantissa >>= 2; + // Restore the alignment. + mantissa <<= @as(std.math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4)); + + const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0; + // Prefer a normalized result in case of overflow. + if (overflow) { + mantissa >>= 1; + exponent += 1; + } + } + } + + // +1 for the decimal part. + var buf: [1 + mantissa_digits]u8 = undefined; + assert(std.fmt.printInt(&buf, mantissa, 16, .lower, .{ .fill = '0', .width = 1 + mantissa_digits }) == buf.len); + + try w.writeAll("0x"); + try w.writeByte(buf[0]); + const trimmed = std.mem.trimRight(u8, buf[1..], "0"); + if (opt_precision) |precision| { + if (precision > 0) try w.writeAll("."); + } else if (trimmed.len > 0) { + try w.writeAll("."); + } + try w.writeAll(trimmed); + // Add trailing zeros if explicitly requested. + if (opt_precision) |precision| if (precision > 0) { + if (precision > trimmed.len) + try w.splatByteAll('0', precision - trimmed.len); + }; + try w.writeAll("p"); + try w.printIntOptions(exponent - exponent_bias, 10, .lower, .{}); +} + +pub const ByteSizeUnits = enum { + /// This formatter represents the number as multiple of 1000 and uses the SI + /// measurement units (kB, MB, GB, ...). + decimal, + /// This formatter represents the number as multiple of 1024 and uses the IEC + /// measurement units (KiB, MiB, GiB, ...). + binary, +}; + +/// Format option `precision` is ignored when `value` is less than 1kB +pub fn printByteSize( + w: *std.io.Writer, + value: u64, + comptime units: ByteSizeUnits, + options: std.fmt.Options, +) Error!void { + if (value == 0) return w.alignBufferOptions("0B", options); + // The worst case in terms of space needed is 32 bytes + 3 for the suffix. + var buf: [std.fmt.float.min_buffer_size + 3]u8 = undefined; + + const mags_si = " kMGTPEZY"; + const mags_iec = " KMGTPEZY"; + + const log2 = std.math.log2(value); + const base = switch (units) { + .decimal => 1000, + .binary => 1024, + }; + const magnitude = switch (units) { + .decimal => @min(log2 / comptime std.math.log2(1000), mags_si.len - 1), + .binary => @min(log2 / 10, mags_iec.len - 1), + }; + const new_value = std.math.lossyCast(f64, value) / std.math.pow(f64, std.math.lossyCast(f64, base), std.math.lossyCast(f64, magnitude)); + const suffix = switch (units) { + .decimal => mags_si[magnitude], + .binary => mags_iec[magnitude], + }; + + const s = switch (magnitude) { + 0 => buf[0..std.fmt.printInt(&buf, value, 10, .lower, .{})], + else => std.fmt.float.render(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { + error.BufferTooSmall => unreachable, + }, + }; + + var i: usize = s.len; + if (suffix == ' ') { + buf[i] = 'B'; + i += 1; + } else switch (units) { + .decimal => { + buf[i..][0..2].* = [_]u8{ suffix, 'B' }; + i += 2; + }, + .binary => { + buf[i..][0..3].* = [_]u8{ suffix, 'i', 'B' }; + i += 3; + }, + } + + return w.alignBufferOptions(buf[0..i], options); +} + +// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948 +const ANY = "any"; + +fn stripOptionalOrErrorUnionSpec(comptime fmt: []const u8) []const u8 { + return if (std.mem.eql(u8, fmt[1..], ANY)) + ANY + else + fmt[1..]; +} + +pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) noreturn { + @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'"); +} + +pub fn printDurationSigned(w: *Writer, ns: i64) Error!void { + if (ns < 0) try w.writeByte('-'); + return w.printDurationUnsigned(@abs(ns)); +} + +pub fn printDurationUnsigned(w: *Writer, ns: u64) Error!void { + var ns_remaining = ns; + inline for (.{ + .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' }, + .{ .ns = std.time.ns_per_week, .sep = 'w' }, + .{ .ns = std.time.ns_per_day, .sep = 'd' }, + .{ .ns = std.time.ns_per_hour, .sep = 'h' }, + .{ .ns = std.time.ns_per_min, .sep = 'm' }, + }) |unit| { + if (ns_remaining >= unit.ns) { + const units = ns_remaining / unit.ns; + try w.printIntOptions(units, 10, .lower, .{}); + try w.writeByte(unit.sep); + ns_remaining -= units * unit.ns; + if (ns_remaining == 0) return; + } + } + + inline for (.{ + .{ .ns = std.time.ns_per_s, .sep = "s" }, + .{ .ns = std.time.ns_per_ms, .sep = "ms" }, + .{ .ns = std.time.ns_per_us, .sep = "us" }, + }) |unit| { + const kunits = ns_remaining * 1000 / unit.ns; + if (kunits >= 1000) { + try w.printIntOptions(kunits / 1000, 10, .lower, .{}); + const frac = kunits % 1000; + if (frac > 0) { + // Write up to 3 decimal places + var decimal_buf = [_]u8{ '.', 0, 0, 0 }; + var inner: Writer = .fixed(decimal_buf[1..]); + inner.printIntOptions(frac, 10, .lower, .{ .fill = '0', .width = 3 }) catch unreachable; + var end: usize = 4; + while (end > 1) : (end -= 1) { + if (decimal_buf[end - 1] != '0') break; + } + try w.writeAll(decimal_buf[0..end]); + } + return w.writeAll(unit.sep); + } + } + + try w.printIntOptions(ns_remaining, 10, .lower, .{}); + try w.writeAll("ns"); +} + +/// Writes number of nanoseconds according to its signed magnitude: +/// `[#y][#w][#d][#h][#m]#[.###][n|u|m]s` +/// `nanoseconds` must be an integer that coerces into `u64` or `i64`. +pub fn printDuration(w: *Writer, nanoseconds: anytype, options: std.fmt.Options) Error!void { + // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24 + var buf: [24]u8 = undefined; + var sub_bw: Writer = .fixed(&buf); + switch (@typeInfo(@TypeOf(nanoseconds)).int.signedness) { + .signed => sub_bw.printDurationSigned(nanoseconds) catch unreachable, + .unsigned => sub_bw.printDurationUnsigned(nanoseconds) catch unreachable, + } + return w.alignBufferOptions(sub_bw.buffered(), options); +} + +pub fn printHex(w: *Writer, bytes: []const u8, case: std.fmt.Case) Error!void { + const charset = switch (case) { + .upper => "0123456789ABCDEF", + .lower => "0123456789abcdef", + }; + for (bytes) |c| { + try w.writeByte(charset[c >> 4]); + try w.writeByte(charset[c & 15]); + } +} + +pub fn printBase64(w: *Writer, bytes: []const u8) Error!void { + var chunker = std.mem.window(u8, bytes, 3, 3); + var temp: [5]u8 = undefined; + while (chunker.next()) |chunk| { + try w.writeAll(std.base64.standard.Encoder.encode(&temp, chunk)); + } +} + +/// Write a single unsigned integer as LEB128 to the given writer. +pub fn writeUleb128(w: *Writer, value: anytype) Error!void { + try w.writeLeb128(switch (@typeInfo(@TypeOf(value))) { + .comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value), + .int => |value_info| switch (value_info.signedness) { + .signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)), + .unsigned => value, + }, + else => comptime unreachable, + }); +} + +/// Write a single signed integer as LEB128 to the given writer. +pub fn writeSleb128(w: *Writer, value: anytype) Error!void { + try w.writeLeb128(switch (@typeInfo(@TypeOf(value))) { + .comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value), + .int => |value_info| switch (value_info.signedness) { + .signed => value, + .unsigned => @as(@Type(.{ .int = .{ .signedness = .signed, .bits = value_info.bits + 1 } }), value), + }, + else => comptime unreachable, + }); +} + +/// Write a single integer as LEB128 to the given writer. +pub fn writeLeb128(w: *Writer, value: anytype) Error!void { + const value_info = @typeInfo(@TypeOf(value)).int; + try w.writeMultipleOf7Leb128(@as(@Type(.{ .int = .{ + .signedness = value_info.signedness, + .bits = std.mem.alignForwardAnyAlign(u16, value_info.bits, 7), + } }), value)); +} + +fn writeMultipleOf7Leb128(w: *Writer, value: anytype) Error!void { + const value_info = @typeInfo(@TypeOf(value)).int; + comptime assert(value_info.bits % 7 == 0); + var remaining = value; + while (true) { + const buffer: []packed struct(u8) { bits: u7, more: bool } = @ptrCast(try w.writableSliceGreedy(1)); + for (buffer, 1..) |*byte, len| { + const more = switch (value_info.signedness) { + .signed => remaining >> 6 != remaining >> (value_info.bits - 1), + .unsigned => remaining > std.math.maxInt(u7), + }; + byte.* = if (@inComptime()) @typeInfo(@TypeOf(buffer)).pointer.child{ + .bits = @bitCast(@as(@Type(.{ .int = .{ + .signedness = value_info.signedness, + .bits = 7, + } }), @truncate(remaining))), + .more = more, + } else .{ + .bits = @bitCast(@as(@Type(.{ .int = .{ + .signedness = value_info.signedness, + .bits = 7, + } }), @truncate(remaining))), + .more = more, + }; + if (value_info.bits > 7) remaining >>= 7; + if (!more) return w.advance(len); + } + w.advance(buffer.len); + } +} + +test "formatValue max_depth" { + const Vec2 = struct { + const SelfType = @This(); + x: f32, + y: f32, + + pub fn format( + self: SelfType, + comptime fmt: []const u8, + options: std.fmt.Options, + w: *Writer, + ) Error!void { + _ = options; + if (fmt.len == 0) { + return w.print("({d:.3},{d:.3})", .{ self.x, self.y }); + } else { + @compileError("unknown format string: '" ++ fmt ++ "'"); + } + } + }; + const E = enum { + One, + Two, + Three, + }; + const TU = union(enum) { + const SelfType = @This(); + float: f32, + int: u32, + ptr: ?*SelfType, + }; + const S = struct { + const SelfType = @This(); + a: ?*SelfType, + tu: TU, + e: E, + vec: Vec2, + }; + + var inst = S{ + .a = null, + .tu = TU{ .ptr = null }, + .e = E.Two, + .vec = Vec2{ .x = 10.2, .y = 2.22 }, + }; + inst.a = &inst; + inst.tu.ptr = &inst.tu; + + var buf: [1000]u8 = undefined; + var w: Writer = .fixed(&buf); + try w.printValue("", .{}, inst, 0); + try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ ... }", w.buffered()); + + w.reset(); + try w.printValue("", .{}, inst, 1); + try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered()); + + w.reset(); + try w.printValue("", .{}, inst, 2); + try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered()); + + w.reset(); + try w.printValue("", .{}, inst, 3); + try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered()); + + const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 }; + w.reset(); + try w.printValue("", .{}, vec, 0); + try testing.expectEqualStrings("{ ... }", w.buffered()); + + w.reset(); + try w.printValue("", .{}, vec, 1); + try testing.expectEqualStrings("{ 1, 2, 3, 4 }", w.buffered()); +} + +test printDuration { + testDurationCase("0ns", 0); + testDurationCase("1ns", 1); + testDurationCase("999ns", std.time.ns_per_us - 1); + testDurationCase("1us", std.time.ns_per_us); + testDurationCase("1.45us", 1450); + testDurationCase("1.5us", 3 * std.time.ns_per_us / 2); + testDurationCase("14.5us", 14500); + testDurationCase("145us", 145000); + testDurationCase("999.999us", std.time.ns_per_ms - 1); + testDurationCase("1ms", std.time.ns_per_ms + 1); + testDurationCase("1.5ms", 3 * std.time.ns_per_ms / 2); + testDurationCase("1.11ms", 1110000); + testDurationCase("1.111ms", 1111000); + testDurationCase("1.111ms", 1111100); + testDurationCase("999.999ms", std.time.ns_per_s - 1); + testDurationCase("1s", std.time.ns_per_s); + testDurationCase("59.999s", std.time.ns_per_min - 1); + testDurationCase("1m", std.time.ns_per_min); + testDurationCase("1h", std.time.ns_per_hour); + testDurationCase("1d", std.time.ns_per_day); + testDurationCase("1w", std.time.ns_per_week); + testDurationCase("1y", 365 * std.time.ns_per_day); + testDurationCase("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1 + testDurationCase("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms); + testDurationCase("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us); + testDurationCase("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1); + testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms); + testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1); + testDurationCase("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999); + testDurationCase("584y49w23h34m33.709s", std.math.maxInt(u64)); + + testing.expectFmt("=======0ns", "{D:=>10}", .{0}); + testing.expectFmt("1ns=======", "{D:=<10}", .{1}); + testing.expectFmt(" 999ns ", "{D:^10}", .{std.time.ns_per_us - 1}); +} + +test printDurationSigned { + testDurationCaseSigned("0ns", 0); + testDurationCaseSigned("1ns", 1); + testDurationCaseSigned("-1ns", -(1)); + testDurationCaseSigned("999ns", std.time.ns_per_us - 1); + testDurationCaseSigned("-999ns", -(std.time.ns_per_us - 1)); + testDurationCaseSigned("1us", std.time.ns_per_us); + testDurationCaseSigned("-1us", -(std.time.ns_per_us)); + testDurationCaseSigned("1.45us", 1450); + testDurationCaseSigned("-1.45us", -(1450)); + testDurationCaseSigned("1.5us", 3 * std.time.ns_per_us / 2); + testDurationCaseSigned("-1.5us", -(3 * std.time.ns_per_us / 2)); + testDurationCaseSigned("14.5us", 14500); + testDurationCaseSigned("-14.5us", -(14500)); + testDurationCaseSigned("145us", 145000); + testDurationCaseSigned("-145us", -(145000)); + testDurationCaseSigned("999.999us", std.time.ns_per_ms - 1); + testDurationCaseSigned("-999.999us", -(std.time.ns_per_ms - 1)); + testDurationCaseSigned("1ms", std.time.ns_per_ms + 1); + testDurationCaseSigned("-1ms", -(std.time.ns_per_ms + 1)); + testDurationCaseSigned("1.5ms", 3 * std.time.ns_per_ms / 2); + testDurationCaseSigned("-1.5ms", -(3 * std.time.ns_per_ms / 2)); + testDurationCaseSigned("1.11ms", 1110000); + testDurationCaseSigned("-1.11ms", -(1110000)); + testDurationCaseSigned("1.111ms", 1111000); + testDurationCaseSigned("-1.111ms", -(1111000)); + testDurationCaseSigned("1.111ms", 1111100); + testDurationCaseSigned("-1.111ms", -(1111100)); + testDurationCaseSigned("999.999ms", std.time.ns_per_s - 1); + testDurationCaseSigned("-999.999ms", -(std.time.ns_per_s - 1)); + testDurationCaseSigned("1s", std.time.ns_per_s); + testDurationCaseSigned("-1s", -(std.time.ns_per_s)); + testDurationCaseSigned("59.999s", std.time.ns_per_min - 1); + testDurationCaseSigned("-59.999s", -(std.time.ns_per_min - 1)); + testDurationCaseSigned("1m", std.time.ns_per_min); + testDurationCaseSigned("-1m", -(std.time.ns_per_min)); + testDurationCaseSigned("1h", std.time.ns_per_hour); + testDurationCaseSigned("-1h", -(std.time.ns_per_hour)); + testDurationCaseSigned("1d", std.time.ns_per_day); + testDurationCaseSigned("-1d", -(std.time.ns_per_day)); + testDurationCaseSigned("1w", std.time.ns_per_week); + testDurationCaseSigned("-1w", -(std.time.ns_per_week)); + testDurationCaseSigned("1y", 365 * std.time.ns_per_day); + testDurationCaseSigned("-1y", -(365 * std.time.ns_per_day)); + testDurationCaseSigned("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1d + testDurationCaseSigned("-1y52w23h59m59.999s", -(730 * std.time.ns_per_day - 1)); // 365d = 52w1d + testDurationCaseSigned("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms); + testDurationCaseSigned("-1y1h1.001s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms)); + testDurationCaseSigned("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us); + testDurationCaseSigned("-1y1h1s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us)); + testDurationCaseSigned("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1); + testDurationCaseSigned("-1y1h999.999us", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1)); + testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms); + testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms)); + testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1); + testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1)); + testDurationCaseSigned("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999); + testDurationCaseSigned("-1y1m999ns", -(365 * std.time.ns_per_day + std.time.ns_per_min + 999)); + testDurationCaseSigned("292y24w3d23h47m16.854s", std.math.maxInt(i64)); + testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64) + 1); + testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64)); + + testing.expectFmt("=======0ns", "{s:=>10}", .{0}); + testing.expectFmt("1ns=======", "{s:=<10}", .{1}); + testing.expectFmt("-1ns======", "{s:=<10}", .{-(1)}); + testing.expectFmt(" -999ns ", "{s:^10}", .{-(std.time.ns_per_us - 1)}); +} + +fn testDurationCase(expected: []const u8, input: u64) !void { + var buf: [24]u8 = undefined; + var w: Writer = .fixed(&buf); + try w.printDurationUnsigned(input); + try testing.expectEqualStrings(expected, w.buffered()); +} + +fn testDurationCaseSigned(expected: []const u8, input: i64) !void { + var buf: [24]u8 = undefined; + var w: Writer = .fixed(&buf); + try w.printDurationSigned(input); + try testing.expectEqualStrings(expected, w.buffered()); +} + +test printIntOptions { + try testPrintIntCase("-1", @as(i1, -1), 10, .lower, .{}); + + try testPrintIntCase("-101111000110000101001110", @as(i32, -12345678), 2, .lower, .{}); + try testPrintIntCase("-12345678", @as(i32, -12345678), 10, .lower, .{}); + try testPrintIntCase("-bc614e", @as(i32, -12345678), 16, .lower, .{}); + try testPrintIntCase("-BC614E", @as(i32, -12345678), 16, .upper, .{}); + + try testPrintIntCase("12345678", @as(u32, 12345678), 10, .upper, .{}); + + try testPrintIntCase(" 666", @as(u32, 666), 10, .lower, .{ .width = 6 }); + try testPrintIntCase(" 1234", @as(u32, 0x1234), 16, .lower, .{ .width = 6 }); + try testPrintIntCase("1234", @as(u32, 0x1234), 16, .lower, .{ .width = 1 }); + + try testPrintIntCase("+42", @as(i32, 42), 10, .lower, .{ .width = 3 }); + try testPrintIntCase("-42", @as(i32, -42), 10, .lower, .{ .width = 3 }); +} + +test "printInt with comptime_int" { + var buf: [20]u8 = undefined; + var w: Writer = .fixed(&buf); + try w.printInt(@as(comptime_int, 123456789123456789), "", .{}); + try std.testing.expectEqualStrings("123456789123456789", w.buffered()); +} + +test "printFloat with comptime_float" { + var buf: [20]u8 = undefined; + var w: Writer = .fixed(&buf); + try w.printFloat("", .{}, @as(comptime_float, 1.0)); + try std.testing.expectEqualStrings(w.buffered(), "1e0"); + try std.testing.expectFmt("1e0", "{}", .{1.0}); +} + +fn testPrintIntCase(expected: []const u8, value: anytype, base: u8, case: std.fmt.Case, options: std.fmt.Options) !void { + var buffer: [100]u8 = undefined; + var w: Writer = .fixed(&buffer); + w.printIntOptions(value, base, case, options); + try testing.expectEqualStrings(expected, w.buffered()); +} + +test printByteSize { + try testing.expectFmt("file size: 42B\n", "file size: {B}\n", .{42}); + try testing.expectFmt("file size: 42B\n", "file size: {Bi}\n", .{42}); + try testing.expectFmt("file size: 63MB\n", "file size: {B}\n", .{63 * 1000 * 1000}); + try testing.expectFmt("file size: 63MiB\n", "file size: {Bi}\n", .{63 * 1024 * 1024}); + try testing.expectFmt("file size: 42B\n", "file size: {B:.2}\n", .{42}); + try testing.expectFmt("file size: 42B\n", "file size: {B:>9.2}\n", .{42}); + try testing.expectFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{63 * 1024 * 1024}); + try testing.expectFmt("file size: 60.08MiB\n", "file size: {Bi:.2}\n", .{63 * 1000 * 1000}); + try testing.expectFmt("file size: =66.06MB=\n", "file size: {B:=^9.2}\n", .{63 * 1024 * 1024}); + try testing.expectFmt("file size: 66.06MB\n", "file size: {B: >9.2}\n", .{63 * 1024 * 1024}); + try testing.expectFmt("file size: 66.06MB \n", "file size: {B: <9.2}\n", .{63 * 1024 * 1024}); + try testing.expectFmt("file size: 0.01844674407370955ZB\n", "file size: {B}\n", .{std.math.maxInt(u64)}); +} + +test "bytes.hex" { + const some_bytes = "\xCA\xFE\xBA\xBE"; + try std.testing.expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes}); + try std.testing.expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes}); + try std.testing.expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]}); + try std.testing.expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]}); + const bytes_with_zeros = "\x00\x0E\xBA\xBE"; + try std.testing.expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros}); +} + +test fixed { + { + var buf: [255]u8 = undefined; + var w: Writer = .fixed(&buf); + try w.print("{s}{s}!", .{ "Hello", "World" }); + try testing.expectEqualStrings("HelloWorld!", w.buffered()); + } + + comptime { + var buf: [255]u8 = undefined; + var w: Writer = .fixed(&buf); + try w.print("{s}{s}!", .{ "Hello", "World" }); + try testing.expectEqualStrings("HelloWorld!", w.buffered()); + } +} + +test "fixed output" { + var buffer: [10]u8 = undefined; + var w: Writer = .fixed(&buffer); + + try w.writeAll("Hello"); + try testing.expect(std.mem.eql(u8, w.buffered(), "Hello")); + + try w.writeAll("world"); + try testing.expect(std.mem.eql(u8, w.buffered(), "Helloworld")); + + try testing.expectError(error.WriteStreamEnd, w.writeAll("!")); + try testing.expect(std.mem.eql(u8, w.buffered(), "Helloworld")); + + w.reset(); + try testing.expect(w.buffered().len == 0); + + try testing.expectError(error.WriteStreamEnd, w.writeAll("Hello world!")); + try testing.expect(std.mem.eql(u8, w.buffered(), "Hello worl")); + + try w.seekTo((try w.getEndPos()) + 1); + try testing.expectError(error.WriteStreamEnd, w.writeAll("H")); +} + +pub fn failingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + _ = w; + _ = data; + _ = splat; + return error.WriteFailed; +} + +pub fn failingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { + _ = w; + _ = file_reader; + _ = limit; + return error.WriteFailed; +} + +pub fn discardingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + const slice = data[0 .. data.len - 1]; + const pattern = data[slice.len..]; var written: usize = pattern.len * splat; - for (headers) |bytes| written += bytes.len; + for (slice) |bytes| written += bytes.len; + w.end = 0; return written; } -pub fn discardingWriteFile( - context: ?*anyopaque, - file_reader: *std.fs.File.Reader, - limit: Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, -) Writer.FileError!usize { - _ = context; - if (file_reader.getSize()) |size| { - const remaining = size - file_reader.pos; - const seek_amt = limit.minInt(remaining); - // Error is observable on `file_reader` instance, and is safe to ignore - // depending on the caller's needs. Caller can make that decision. - file_reader.seekBy(@intCast(seek_amt)) catch {}; - var n: usize = seek_amt; - for (headers_and_trailers[0..headers_len]) |bytes| n += bytes.len; - if (seek_amt == remaining) { - // Since we made it all the way through the file, the trailers are - // also included. - for (headers_and_trailers[headers_len..]) |bytes| n += bytes.len; +pub fn discardingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { + if (File.Handle == void) return error.Unimplemented; + if (w.end != 0) { + if (@intFromEnum(limit) >= w.end) { + w.end = 0; + } else { + const remaining = w.buffer[@intFromEnum(limit)..w.end]; + @memmove(w.buffer[0..remaining.len], remaining); + w.end = remaining.len; } + return 0; + } + if (file_reader.getSize()) |size| { + const n = limit.minInt(size - file_reader.pos); + file_reader.seekBy(@intCast(n)) catch return error.Unimplemented; + w.end = 0; return n; } else |_| { // Error is observable on `file_reader` instance, and it is better to @@ -169,33 +1694,52 @@ pub fn discardingWriteFile( } } -pub const discarding: Writer = .{ - .context = undefined, - .vtable = &.{ - .writeSplat = discardingWriteSplat, - .writeFile = discardingWriteFile, - }, -}; - /// For use when the `Writer` implementation can cannot offer a more efficient /// implementation than a basic read/write loop on the file. -pub fn unimplementedWriteFile( - context: ?*anyopaque, - file_reader: *File.Reader, - limit: Limit, - headers_and_trailers: []const []const u8, - headers_len: usize, -) FileError!usize { - _ = context; +pub fn unimplementedSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { + _ = w; _ = file_reader; _ = limit; - _ = headers_and_trailers; - _ = headers_len; return error.Unimplemented; } +/// When this function is called it usually means the buffer got full, so it's +/// time to return an error. However, we still need to make sure all of the +/// available buffer has been filled. Also, it may be called from `flush` in +/// which case it should return successfully. +fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + for (data[0 .. data.len - 1]) |bytes| { + const dest = w.buffer[w.end..]; + const len = @min(bytes.len, dest.len); + @memcpy(dest[0..len], bytes[0..len]); + w.end += len; + if (bytes.len > dest.len) return error.WriteFailed; + } + const pattern = data[data.len - 1]; + const dest = w.buffer[w.end..]; + switch (pattern.len) { + 0 => return w.end, + 1 => { + assert(splat >= dest.len); + @memset(dest, pattern[0]); + w.end += dest.len; + return error.WriteFailed; + }, + else => { + for (0..splat) |i| { + const remaining = dest[i * pattern.len ..]; + const len = @min(pattern.len, remaining.len); + @memcpy(remaining[0..len], pattern[0..len]); + w.end += len; + if (pattern.len > remaining.len) return error.WriteFailed; + } + unreachable; + }, + } +} + /// Provides a `Writer` implementation based on calling `Hasher.update`, sending -/// all data also to an underlying `std.io.BufferedWriter`. +/// all data also to an underlying `Writer`. /// /// When using this, the underlying writer is best unbuffered because all /// writes are passed on directly to it. @@ -206,27 +1750,35 @@ pub fn unimplementedWriteFile( /// details. pub fn Hashed(comptime Hasher: type) type { return struct { - out: *std.io.BufferedWriter, + out: *Writer, hasher: Hasher, + interface: Writer, - pub fn writable(this: *@This(), buffer: []u8) std.io.BufferedWriter { + pub fn init(out: *Writer) @This() { return .{ - .unbuffered_writer = .{ - .context = this, - .vtable = &.{ - .writeSplat = @This().writeSplat, - .writeFile = Writer.unimplementedWriteFile, - }, + .out = out, + .hasher = .{}, + .interface = .{ + .context = undefined, + .vtable = &.{@This().drain}, }, - .buffer = buffer, }; } - fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Writer.Error!usize { - const this: *@This() = @alignCast(@ptrCast(context)); - const n = try this.out.writeSplat(data, splat); - const short_data = data[0 .. data.len - @intFromBool(splat == 0)]; + fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + const this: *@This() = @alignCast(@fieldParentPtr("interface", w)); + const aux_n = try this.out.writeSplatAux(w.buffered(), data, splat); + if (aux_n <= w.end) { + this.hasher.update(w.buffer[0..aux_n]); + const remaining = w.buffer[aux_n..w.end]; + @memmove(w.buffer[0..remaining.len], remaining); + w.end = remaining.len; + return 0; + } + const n = aux_n - w.end; + w.end = 0; var remaining: usize = n; + const short_data = data[0 .. data.len - @intFromBool(splat == 0)]; for (short_data) |slice| { if (remaining < slice.len) { this.hasher.update(slice[0..remaining]); @@ -243,31 +1795,185 @@ pub fn Hashed(comptime Hasher: type) type { }, else => splat - 1, }; - const last = data[data.len - 1]; - assert(remaining == remaining_splat * last.len); - switch (last.len) { + const pattern = data[data.len - 1]; + assert(remaining == remaining_splat * pattern.len); + switch (pattern.len) { 0 => { assert(remaining == 0); - return n; }, 1 => { var buffer: [64]u8 = undefined; - @memset(&buffer, last[0]); + @memset(&buffer, pattern[0]); while (remaining > 0) { const update_len = @min(remaining, buffer.len); this.hasher.update(buffer[0..update_len]); remaining -= update_len; } - return n; }, - else => {}, - } - while (remaining > 0) { - const update_len = @min(remaining, last.len); - this.hasher.update(last[0..update_len]); - remaining -= update_len; + else => { + while (remaining > 0) { + const update_len = @min(remaining, pattern.len); + this.hasher.update(pattern[0..update_len]); + remaining -= update_len; + } + }, } return n; } }; } + +/// Maintains `Writer` state such that it writes to the unused capacity of an +/// array list, filling it up completely before making a call through the +/// vtable, causing a resize. Consequently, the same, optimized, non-generic +/// machine code that uses `std.io.Reader`, such as formatted printing, takes +/// the hot paths when using this API. +/// +/// When using this API, it is not necessary to call `flush`. +pub const Allocating = struct { + allocator: Allocator, + interface: Writer, + + pub fn init(allocator: Allocator) Allocating { + return .{ + .allocator = allocator, + .interface = init_interface, + .buffer = &.{}, + }; + } + + pub fn initCapacity(allocator: Allocator, capacity: usize) error{OutOfMemory}!Allocating { + return .{ + .allocator = allocator, + .interface = init_interface, + .buffer = try allocator.alloc(u8, capacity), + }; + } + + pub fn initOwnedSlice(allocator: Allocator, slice: []u8) Allocating { + return .{ + .allocator = allocator, + .interface = init_interface, + .buffer = slice, + }; + } + + /// Replaces `array_list` with empty, taking ownership of the memory. + pub fn fromArrayList(allocator: Allocator, array_list: *std.ArrayListUnmanaged(u8)) Allocating { + defer array_list.* = .empty; + return .{ + .allocator = allocator, + .interface = init_interface, + .buffer = array_list.allocatedSlice(), + .end = array_list.items.len, + }; + } + + const init_interface: Writer = .{ + .interface = .{ + .context = undefined, + .vtable = &.{ + .drain = Allocating.drain, + .sendFile = Allocating.sendFile, + }, + }, + }; + + pub fn deinit(a: *Allocating) void { + a.allocator.free(a.buffer); + a.* = undefined; + } + + /// Returns an array list that takes ownership of the allocated memory. + /// Resets the `Allocating` to an empty state. + pub fn toArrayList(a: *Allocating) std.ArrayListUnmanaged(u8) { + const w = &a.interface; + const result: std.ArrayListUnmanaged(u8) = .{ + .items = w.buffer[0..w.end], + .capacity = w.buffer.len, + }; + w.buffer = &.{}; + w.end = 0; + return result; + } + + pub fn toOwnedSlice(a: *Allocating) error{OutOfMemory}![]u8 { + var list = a.toArrayList(); + return list.toOwnedSlice(a.allocator); + } + + pub fn toOwnedSliceSentinel(a: *Allocating, comptime sentinel: u8) error{OutOfMemory}![:sentinel]u8 { + const gpa = a.allocator; + var list = toArrayList(a); + return list.toOwnedSliceSentinel(gpa, sentinel); + } + + pub fn getWritten(a: *Allocating) []u8 { + return a.interface.buffered(); + } + + pub fn shrinkRetainingCapacity(a: *Allocating, new_len: usize) void { + const shrink_by = a.interface.end - new_len; + a.interface.end = new_len; + a.interface.count -= shrink_by; + } + + pub fn clearRetainingCapacity(a: *Allocating) void { + a.shrinkRetainingCapacity(0); + } + + fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { + const a: *Allocating = @fieldParentPtr("interface", w); + const gpa = a.allocator; + const pattern = data[data.len - 1]; + const splat_len = pattern.len * splat; + var list = a.toArrayList(); + defer setArrayList(a, list); + const start_len = list.items.len; + for (data[0 .. data.len - 1]) |bytes| { + list.ensureUnusedCapacity(gpa, bytes.len + splat_len) catch return error.WriteFailed; + list.appendSliceAssumeCapacity(bytes); + } + switch (pattern.len) { + 0 => {}, + 1 => list.appendNTimesAssumeCapacity(pattern[0], splat), + else => for (0..splat) |_| list.appendSliceAssumeCapacity(pattern), + } + return list.items.len - start_len; + } + + fn sendFile(w: *Writer, file_reader: *File.Reader, limit: std.io.Limit) FileError!usize { + if (File.Handle == void) return error.Unimplemented; + const a: *Allocating = @fieldParentPtr("interface", w); + const gpa = a.allocator; + var list = a.toArrayList(); + defer setArrayList(a, list); + const pos = file_reader.pos; + const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line; + list.ensureUnusedCapacity(gpa, limit.minInt(additional)) catch return error.WriteFailed; + const dest = limit.slice(list.unusedCapacitySlice()); + const n = file_reader.read(dest) catch |err| switch (err) { + error.ReadFailed => return error.ReadFailed, + error.EndOfStream => 0, + }; + list.items.len += n; + return n; + } + + fn setArrayList(a: *Allocating, list: std.ArrayListUnmanaged(u8)) void { + a.buffer = list.allocatedSlice(); + a.end = list.items.len; + } + + test Allocating { + var a: Allocating = .init(std.testing.allocator); + defer a.deinit(); + const w = &a.interface; + + const x: i32 = 42; + const y: i32 = 1234; + try w.print("x: {}\ny: {}\n", .{ x, y }); + + try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", a.getWritten()); + } +}; diff --git a/lib/std/io/tty.zig b/lib/std/io/tty.zig index 874f6a4e41..1e9cd0d9bc 100644 --- a/lib/std/io/tty.zig +++ b/lib/std/io/tty.zig @@ -73,7 +73,7 @@ pub const Config = union(enum) { pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || std.io.Writer.Error; - pub fn setColor(conf: Config, bw: *std.io.BufferedWriter, color: Color) SetColorError!void { + pub fn setColor(conf: Config, w: *std.io.Writer, color: Color) SetColorError!void { nosuspend switch (conf) { .no_color => return, .escape_codes => { @@ -98,7 +98,7 @@ pub const Config = union(enum) { .dim => "\x1b[2m", .reset => "\x1b[0m", }; - try bw.writeAll(color_string); + try w.writeAll(color_string); }, .windows_api => |ctx| if (native_os == .windows) { const attributes = switch (color) { diff --git a/lib/std/json.zig b/lib/std/json.zig index 321c1c1bd8..b67082507b 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -127,9 +127,9 @@ pub fn Formatter(comptime T: type) type { self: @This(), comptime fmt_spec: []const u8, options: std.fmt.FormatOptions, - writer: *std.io.BufferedWriter, + writer: *std.io.Writer, ) !void { - _ = fmt_spec; + comptime std.debug.assert(fmt_spec.len == 0); _ = options; try Stringify.value(self.value, self.options, writer); } diff --git a/lib/std/json/Stringify.zig b/lib/std/json/Stringify.zig index e6974bf2c8..e9d3c880d2 100644 --- a/lib/std/json/Stringify.zig +++ b/lib/std/json/Stringify.zig @@ -23,13 +23,14 @@ const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; const BitStack = std.BitStack; const Stringify = @This(); +const Writer = std.io.Writer; const IndentationMode = enum(u1) { object = 0, array = 1, }; -writer: *std.io.BufferedWriter, +writer: *Writer, options: Options = .{}, indent_level: usize = 0, next_punctuation: enum { @@ -77,7 +78,7 @@ const safety_checks: @TypeOf(safety_checks_hint) = if (build_mode_has_safety) else .assumed_correct; -pub const Error = std.io.Writer.Error; +pub const Error = Writer.Error; pub fn beginArray(self: *Stringify) Error!void { if (build_mode_has_safety) assert(self.raw_streaming_mode == .none); @@ -224,8 +225,7 @@ pub fn print(self: *Stringify, comptime fmt: []const u8, args: anytype) Error!vo test print { var out_buf: [1024]u8 = undefined; - var out: std.io.BufferedWriter = undefined; - out.initFixed(&out_buf); + var out: Writer = .fixed(&out_buf); var w: Stringify = .{ .writer = &out, .options = .{ .whitespace = .indent_2 } }; @@ -567,10 +567,10 @@ pub const Options = struct { emit_nonportable_numbers_as_strings: bool = false, }; -/// Writes the given value to the `std.io.Writer` writer. +/// Writes the given value to the `Writer` writer. /// See `Stringify` for how the given value is serialized into JSON. /// The maximum nesting depth of the output JSON document is 256. -pub fn value(v: anytype, options: Options, writer: *std.io.BufferedWriter) Error!void { +pub fn value(v: anytype, options: Options, writer: *Writer) Error!void { var s: Stringify = .{ .writer = writer, .options = options }; try s.write(v); } @@ -634,7 +634,7 @@ test valueAlloc { try std.testing.expectEqualStrings(expected, actual); } -fn outputUnicodeEscape(codepoint: u21, bw: *std.io.BufferedWriter) Error!void { +fn outputUnicodeEscape(codepoint: u21, bw: *Writer) Error!void { if (codepoint <= 0xFFFF) { // If the character is in the Basic Multilingual Plane (U+0000 through U+FFFF), // then it may be represented as a six-character sequence: a reverse solidus, followed @@ -654,7 +654,7 @@ fn outputUnicodeEscape(codepoint: u21, bw: *std.io.BufferedWriter) Error!void { } } -fn outputSpecialEscape(c: u8, writer: *std.io.BufferedWriter) Error!void { +fn outputSpecialEscape(c: u8, writer: *Writer) Error!void { switch (c) { '\\' => try writer.writeAll("\\\\"), '\"' => try writer.writeAll("\\\""), @@ -668,14 +668,14 @@ fn outputSpecialEscape(c: u8, writer: *std.io.BufferedWriter) Error!void { } /// Write `string` to `writer` as a JSON encoded string. -pub fn encodeJsonString(string: []const u8, options: Options, writer: *std.io.BufferedWriter) Error!void { +pub fn encodeJsonString(string: []const u8, options: Options, writer: *Writer) Error!void { try writer.writeByte('\"'); try encodeJsonStringChars(string, options, writer); try writer.writeByte('\"'); } /// Write `chars` to `writer` as JSON encoded string characters. -pub fn encodeJsonStringChars(chars: []const u8, options: Options, writer: *std.io.BufferedWriter) Error!void { +pub fn encodeJsonStringChars(chars: []const u8, options: Options, writer: *Writer) Error!void { var write_cursor: usize = 0; var i: usize = 0; if (options.escape_unicode) { @@ -718,8 +718,7 @@ pub fn encodeJsonStringChars(chars: []const u8, options: Options, writer: *std.i test "json write stream" { var out_buf: [1024]u8 = undefined; - var out: std.io.BufferedWriter = undefined; - out.initFixed(&out_buf); + var out: Writer = .fixed(&out_buf); var w: Stringify = .{ .writer = &out, .options = .{ .whitespace = .indent_2 } }; try testBasicWriteStream(&w); } @@ -971,16 +970,14 @@ test "stringify struct with custom stringifier" { fn testStringify(expected: []const u8, v: anytype, options: Options) !void { var buffer: [4096]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buffer); + var bw: Writer = .fixed(&buffer); try value(v, options, &bw); try std.testing.expectEqualStrings(expected, bw.getWritten()); } test "raw streaming" { var out_buf: [1024]u8 = undefined; - var out: std.io.BufferedWriter = undefined; - out.initFixed(&out_buf); + var out: Writer = .fixed(&out_buf); var w: Stringify = .{ .writer = &out, .options = .{ .whitespace = .indent_2 } }; try w.beginObject(); diff --git a/lib/std/json/dynamic_test.zig b/lib/std/json/dynamic_test.zig index 6537685b48..d54b930fae 100644 --- a/lib/std/json/dynamic_test.zig +++ b/lib/std/json/dynamic_test.zig @@ -4,6 +4,7 @@ const mem = std.mem; const testing = std.testing; const ArenaAllocator = std.heap.ArenaAllocator; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; const ObjectMap = @import("dynamic.zig").ObjectMap; const Array = @import("dynamic.zig").Array; @@ -73,8 +74,7 @@ test "json.parser.dynamic" { test "write json then parse it" { var out_buffer: [1000]u8 = undefined; - var fixed_writer: std.io.BufferedWriter = undefined; - fixed_writer.initFixed(&out_buffer); + var fixed_writer: Writer = .fixed(&out_buffer); var jw: json.Stringify = .{ .writer = &fixed_writer, .options = .{} }; try jw.beginObject(); @@ -240,8 +240,7 @@ test "Value.jsonStringify" { .{ .object = obj }, }; var buffer: [0x1000]u8 = undefined; - var fixed_writer: std.io.BufferedWriter = undefined; - fixed_writer.initFixed(&buffer); + var fixed_writer: Writer = .fixed(&buffer); var jw: json.Stringify = .{ .writer = &fixed_writer, .options = .{ .whitespace = .indent_1 } }; try jw.write(array); diff --git a/lib/std/leb128.zig b/lib/std/leb128.zig index 861125fe31..82d693ef0d 100644 --- a/lib/std/leb128.zig +++ b/lib/std/leb128.zig @@ -1,6 +1,7 @@ const builtin = @import("builtin"); const std = @import("std"); const testing = std.testing; +const Writer = std.io.Writer; /// This is an "advanced" function. It allows one to use a fixed amount of memory to store a /// ULEB128. This defeats the entire purpose of using this data encoding; it will no longer use @@ -241,7 +242,7 @@ fn test_write_leb128(value: anytype) !void { const signedness = @typeInfo(T).int.signedness; const t_signed = signedness == .signed; - const writeStream = if (t_signed) std.io.BufferedWriter.writeIleb128 else std.io.BufferedWriter.writeUleb128; + const writeStream = if (t_signed) Writer.writeIleb128 else Writer.writeUleb128; const readStream = if (t_signed) std.io.Reader.readIleb128 else std.io.Reader.readUleb128; // decode to a larger bit size too, to ensure sign extension @@ -261,8 +262,7 @@ fn test_write_leb128(value: anytype) !void { const max_groups = if (@typeInfo(T).int.bits == 0) 1 else (@typeInfo(T).int.bits + 6) / 7; var buf: [max_groups]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buf); + var bw: Writer = .fixed(&buf); // stream write try testing.expect((try writeStream(&bw, value)) == bytes_needed); diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index bf64746e05..a8bb42f3a6 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -2322,7 +2322,7 @@ pub const Const = struct { /// this function will fail to print the string, printing "(BigInt)" instead of a number. /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory. /// See `toString` and `toStringAlloc` for a way to print big integers without failure. - pub fn format(self: Const, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { + pub fn format(self: Const, bw: *std.io.Writer, comptime fmt: []const u8) !void { comptime var base = 10; comptime var case: std.fmt.Case = .lower; diff --git a/lib/std/net.zig b/lib/std/net.zig index a33898d3b6..d13d69ef87 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -1915,7 +1915,7 @@ pub const Stream = struct { fn read( context: ?*anyopaque, - bw: *std.io.BufferedWriter, + bw: *std.io.Writer, limit: std.io.Limit, ) std.io.Reader.Error!usize { const buf = limit.slice(try bw.writableSliceGreedy(1)); diff --git a/lib/std/tar.zig b/lib/std/tar.zig index ff7baf9d69..157bcf0486 100644 --- a/lib/std/tar.zig +++ b/lib/std/tar.zig @@ -358,7 +358,7 @@ pub const Iterator = struct { }; } - fn read(context: ?*anyopaque, bw: *std.io.BufferedWriter, limit: std.io.Limit) std.io.Reader.StreamError!usize { + fn read(context: ?*anyopaque, bw: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { const file: *File = @ptrCast(@alignCast(context)); if (file.unread_bytes.* == 0) return error.EndOfStream; const n = try file.parent_reader.read(bw, limit.min(.limited(file.unread_bytes.*))); @@ -381,7 +381,7 @@ pub const Iterator = struct { return n; } - pub fn readRemaining(file: *File, out: *std.io.BufferedWriter) std.io.Reader.StreamRemainingError!void { + pub fn readRemaining(file: *File, out: *std.io.Writer) std.io.Reader.StreamRemainingError!void { return file.reader().readRemaining(out); } }; @@ -818,8 +818,7 @@ test PaxIterator { var buffer: [1024]u8 = undefined; outer: for (cases) |case| { - var br: std.io.Reader = undefined; - br.initFixed(case.data); + var br: std.io.Reader = .fixed(case.data); var iter: PaxIterator = .init(&br, case.data.len); var i: usize = 0; @@ -955,8 +954,7 @@ test Iterator { // example/empty/ const data = @embedFile("tar/testdata/example.tar"); - var br: std.io.Reader = undefined; - br.initFixed(data); + var br: std.io.Reader = .fixed(data); // User provided buffers to the iterator var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; @@ -1015,8 +1013,7 @@ test pipeToFileSystem { // example/empty/ const data = @embedFile("tar/testdata/example.tar"); - var br: std.io.Reader = undefined; - br.initFixed(data); + var br: std.io.Reader = .fixed(data); var tmp = testing.tmpDir(.{ .no_follow = true }); defer tmp.cleanup(); @@ -1047,8 +1044,7 @@ test pipeToFileSystem { test "pipeToFileSystem root_dir" { const data = @embedFile("tar/testdata/example.tar"); - var br: std.io.Reader = undefined; - br.initFixed(data); + var br: std.io.Reader = .fixed(data); // with strip_components = 1 { @@ -1073,7 +1069,7 @@ test "pipeToFileSystem root_dir" { // with strip_components = 0 { - br.initFixed(data); + br = .fixed(data); var tmp = testing.tmpDir(.{ .no_follow = true }); defer tmp.cleanup(); var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; @@ -1096,8 +1092,7 @@ test "pipeToFileSystem root_dir" { test "findRoot with single file archive" { const data = @embedFile("tar/testdata/22752.tar"); - var br: std.io.Reader = undefined; - br.initFixed(data); + var br: std.io.Reader = .fixed(data); var tmp = testing.tmpDir(.{}); defer tmp.cleanup(); @@ -1111,8 +1106,7 @@ test "findRoot with single file archive" { test "findRoot without explicit root dir" { const data = @embedFile("tar/testdata/19820.tar"); - var br: std.io.Reader = undefined; - br.initFixed(data); + var br: std.io.Reader = .fixed(data); var tmp = testing.tmpDir(.{}); defer tmp.cleanup(); @@ -1126,8 +1120,7 @@ test "findRoot without explicit root dir" { test "pipeToFileSystem strip_components" { const data = @embedFile("tar/testdata/example.tar"); - var br: std.io.Reader = undefined; - br.initFixed(data); + var br: std.io.Reader = .fixed(data); var tmp = testing.tmpDir(.{ .no_follow = true }); defer tmp.cleanup(); @@ -1188,8 +1181,7 @@ test "executable bit" { const data = @embedFile("tar/testdata/example.tar"); for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| { - var br: std.io.Reader = undefined; - br.initFixed(data); + var br: std.io.Reader = .fixed(data); var tmp = testing.tmpDir(.{ .no_follow = true }); //defer tmp.cleanup(); diff --git a/lib/std/tar/Writer.zig b/lib/std/tar/Writer.zig index a108674db2..118a21b60a 100644 --- a/lib/std/tar/Writer.zig +++ b/lib/std/tar/Writer.zig @@ -14,7 +14,7 @@ pub const Options = struct { mtime: u64 = 0, }; -underlying_writer: *std.io.BufferedWriter, +underlying_writer: *std.io.Writer, prefix: []const u8 = "", mtime_now: u64 = 0, @@ -277,7 +277,7 @@ pub const Header = extern struct { try octal(&w.checksum, checksum); } - pub fn write(h: *Header, bw: *std.io.BufferedWriter) error{ OctalOverflow, WriteFailed }!void { + pub fn write(h: *Header, bw: *std.io.Writer) error{ OctalOverflow, WriteFailed }!void { try h.updateChecksum(); try bw.writeAll(std.mem.asBytes(h)); } @@ -433,16 +433,14 @@ test "write files" { { const root = "root"; - var output: std.io.AllocatingWriter = undefined; - output.init(testing.allocator); + var output: std.io.AllocatingWriter = .init(testing.allocator); var wrt: Writer = .{ .underlying_writer = &output.buffered_writer }; defer output.deinit(); try wrt.setRoot(root); for (files) |file| try wrt.writeFileBytes(file.path, file.content, .{}); - var input: std.io.Reader = undefined; - input.initFixed(output.getWritten()); + var input: std.io.Reader = .fixed(output.getWritten()); var iter = std.tar.iterator(&input, .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer, @@ -476,13 +474,11 @@ test "write files" { var wrt: Writer = .{ .underlying_writer = &output.buffered_writer }; defer output.deinit(); for (files) |file| { - var content: std.io.Reader = undefined; - content.initFixed(file.content); + var content: std.io.Reader = .fixed(file.content); try wrt.writeFileStream(file.path, file.content.len, &content, .{}); } - var input: std.io.Reader = undefined; - input.initFixed(output.getWritten()); + var input: std.io.Reader = .fixed(output.getWritten()); var iter = std.tar.iterator(&input, .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer, diff --git a/lib/std/testing.zig b/lib/std/testing.zig index edd7b93486..c04eaf670c 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -2,6 +2,7 @@ const std = @import("std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; const math = std.math; +const Writer = std.io.Writer; /// Provides deterministic randomness in unit tests. /// Initialized on startup. Read-only after that. @@ -459,7 +460,7 @@ fn SliceDiffer(comptime T: type) type { const Self = @This(); - pub fn write(self: Self, bw: *std.io.BufferedWriter) !void { + pub fn write(self: Self, bw: *Writer) !void { for (self.expected, 0..) |value, i| { const full_index = self.start_index + i; const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true; @@ -480,7 +481,7 @@ const BytesDiffer = struct { actual: []const u8, ttyconf: std.io.tty.Config, - pub fn write(self: BytesDiffer, bw: *std.io.BufferedWriter) !void { + pub fn write(self: BytesDiffer, bw: *Writer) !void { var expected_iterator = std.mem.window(u8, self.expected, 16, 16); var row: usize = 0; while (expected_iterator.next()) |chunk| { @@ -526,7 +527,7 @@ const BytesDiffer = struct { } } - fn writeDiff(self: BytesDiffer, bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytype, diff: bool) !void { + fn writeDiff(self: BytesDiffer, bw: *Writer, comptime fmt: []const u8, args: anytype, diff: bool) !void { if (diff) try self.ttyconf.setColor(bw, .red); try bw.print(fmt, args); if (diff) try self.ttyconf.setColor(bw, .reset); diff --git a/lib/std/tz.zig b/lib/std/tz.zig index 8f1accb3a5..ccfe13fc3f 100644 --- a/lib/std/tz.zig +++ b/lib/std/tz.zig @@ -215,8 +215,7 @@ pub const Tz = struct { test "slim" { const data = @embedFile("tz/asia_tokyo.tzif"); - var in_stream: std.io.Reader = undefined; - in_stream.initFixed(data); + var in_stream: std.io.Reader = .fixed(data); var tz = try std.Tz.parse(std.testing.allocator, &in_stream); defer tz.deinit(); @@ -229,8 +228,7 @@ test "slim" { test "fat" { const data = @embedFile("tz/antarctica_davis.tzif"); - var in_stream: std.io.Reader = undefined; - in_stream.initFixed(data); + var in_stream: std.io.Reader = .fixed(data); var tz = try std.Tz.parse(std.testing.allocator, &in_stream); defer tz.deinit(); @@ -243,8 +241,7 @@ test "fat" { test "legacy" { // Taken from Slackware 8.0, from 2001 const data = @embedFile("tz/europe_vatican.tzif"); - var in_stream: std.io.Reader = undefined; - in_stream.initFixed(data); + var in_stream: std.io.Reader = .fixed(data); var tz = try std.Tz.parse(std.testing.allocator, &in_stream); defer tz.deinit(); diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 25e498d53b..8d9346226a 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -2,6 +2,12 @@ //! source lives here. These APIs are provided as-is and have absolutely no API //! guarantees whatsoever. +const std = @import("std.zig"); +const tokenizer = @import("zig/tokenizer.zig"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; + pub const ErrorBundle = @import("zig/ErrorBundle.zig"); pub const Server = @import("zig/Server.zig"); pub const Client = @import("zig/Client.zig"); @@ -356,11 +362,6 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![ return buffer.toOwnedSlice(); } -const std = @import("std.zig"); -const tokenizer = @import("zig/tokenizer.zig"); -const assert = std.debug.assert; -const Allocator = std.mem.Allocator; - /// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed. /// /// - An empty `{}` format specifier escapes invalid identifiers, identifiers that shadow primitives @@ -412,11 +413,7 @@ test fmtId { } /// Print the string as a Zig identifier, escaping it with `@""` syntax if needed. -fn formatId( - bytes: []const u8, - bw: *std.io.BufferedWriter, - comptime fmt: []const u8, -) !void { +fn formatId(bytes: []const u8, bw: *Writer, comptime fmt: []const u8) !void { const allow_primitive, const allow_underscore = comptime parse_fmt: { var allow_primitive = false; var allow_underscore = false; @@ -470,11 +467,7 @@ test fmtEscapes { /// Print the string as escaped contents of a double quoted or single-quoted string. /// Format `{}` treats contents as a double-quoted string. /// Format `{'}` treats contents as a single-quoted string. -pub fn stringEscape( - bytes: []const u8, - bw: *std.io.BufferedWriter, - comptime f: []const u8, -) !void { +pub fn stringEscape(bytes: []const u8, bw: *Writer, comptime f: []const u8) !void { for (bytes) |byte| switch (byte) { '\n' => try bw.writeAll("\\n"), '\r' => try bw.writeAll("\\r"), diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 13af544670..1377ff66d2 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -4,6 +4,16 @@ //! For Zon syntax, the root node is at nodes[0] and contains lhs as the node //! index of the main expression. +const std = @import("../std.zig"); +const assert = std.debug.assert; +const testing = std.testing; +const mem = std.mem; +const Token = std.zig.Token; +const Ast = @This(); +const Allocator = std.mem.Allocator; +const Parse = @import("Parse.zig"); +const Writer = std.io.Writer; + /// Reference to externally-owned data. source: [:0]const u8, @@ -205,7 +215,7 @@ pub fn renderAlloc(tree: Ast, gpa: Allocator) error{OutOfMemory}![]u8 { pub const Render = @import("Ast/Render.zig"); -pub fn render(tree: Ast, gpa: Allocator, bw: *std.io.BufferedWriter, fixups: Render.Fixups) Render.Error!void { +pub fn render(tree: Ast, gpa: Allocator, bw: *Writer, fixups: Render.Fixups) Render.Error!void { return Render.tree(gpa, bw, tree, fixups); } @@ -311,7 +321,7 @@ pub fn rootDecls(tree: Ast) []const Node.Index { } } -pub fn renderError(tree: Ast, parse_error: Error, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn renderError(tree: Ast, parse_error: Error, bw: *Writer) Writer.Error!void { switch (parse_error.tag) { .asterisk_after_ptr_deref => { // Note that the token will point at the `.*` but ideally the source @@ -4118,15 +4128,6 @@ pub fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex return Span{ .start = start_off, .end = end_off, .main = tree.tokenStart(main) }; } -const std = @import("../std.zig"); -const assert = std.debug.assert; -const testing = std.testing; -const mem = std.mem; -const Token = std.zig.Token; -const Ast = @This(); -const Allocator = std.mem.Allocator; -const Parse = @import("Parse.zig"); - test { _ = Parse; _ = Render; diff --git a/lib/std/zig/Ast/Render.zig b/lib/std/zig/Ast/Render.zig index 79ef4004ee..a9ffb2343a 100644 --- a/lib/std/zig/Ast/Render.zig +++ b/lib/std/zig/Ast/Render.zig @@ -6,6 +6,7 @@ const meta = std.meta; const Ast = std.zig.Ast; const Token = std.zig.Token; const primitives = std.zig.primitives; +const Writer = std.io.Writer; const Render = @This(); @@ -82,7 +83,7 @@ pub const Fixups = struct { } }; -pub fn renderTree(gpa: Allocator, bw: *std.io.BufferedWriter, tree: Ast, fixups: Fixups) Error!void { +pub fn renderTree(gpa: Allocator, bw: *Writer, tree: Ast, fixups: Fixups) Error!void { assert(tree.errors.len == 0); // Cannot render an invalid tree. var auto_indenting_stream: AutoIndentingStream = .init(gpa, bw, indent_delta); defer auto_indenting_stream.deinit(); @@ -3136,7 +3137,7 @@ fn anythingBetween(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.TokenI return false; } -fn writeFixingWhitespace(bw: *std.io.BufferedWriter, slice: []const u8) Error!void { +fn writeFixingWhitespace(bw: *Writer, slice: []const u8) Error!void { for (slice) |byte| switch (byte) { '\t' => try bw.splatByteAll(' ', indent_delta), '\r' => {}, @@ -3266,7 +3267,7 @@ fn rowSize(tree: Ast, exprs: []const Ast.Node.Index, rtoken: Ast.TokenIndex) usi /// This should be done whenever a scope that ends in a .semicolon or a /// .comma is introduced. const AutoIndentingStream = struct { - underlying_writer: *std.io.BufferedWriter, + underlying_writer: *Writer, /// Offset into the source at which formatting has been disabled with /// a `zig fmt: off` comment. @@ -3301,10 +3302,10 @@ const AutoIndentingStream = struct { indent_count: usize, }; - pub fn init(gpa: Allocator, bw: *std.io.BufferedWriter, indent_delta_: usize) AutoIndentingStream { + pub fn init(gpa: Allocator, bw: *Writer, starting_indent_delta: usize) AutoIndentingStream { return .{ .underlying_writer = bw, - .indent_delta = indent_delta_, + .indent_delta = starting_indent_delta, .indent_stack = .init(gpa), .space_stack = .init(gpa), }; diff --git a/lib/std/zig/ErrorBundle.zig b/lib/std/zig/ErrorBundle.zig index 592eb872b8..7984990b07 100644 --- a/lib/std/zig/ErrorBundle.zig +++ b/lib/std/zig/ErrorBundle.zig @@ -7,6 +7,12 @@ //! empty, it means there are no errors. This special encoding exists so that //! heap allocation is not needed in the common case of no errors. +const std = @import("std"); +const ErrorBundle = @This(); +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const Writer = std.io.Writer; + string_bytes: []const u8, /// The first thing in this array is an `ErrorMessageList`. extra: []const u32, @@ -163,7 +169,7 @@ pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void { renderToWriter(eb, options, bw) catch return; } -pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, bw: *std.io.BufferedWriter) (std.io.Writer.Error || std.posix.UnexpectedError)!void { +pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, bw: *Writer) (Writer.Error || std.posix.UnexpectedError)!void { if (eb.extra.len == 0) return; for (eb.getMessages()) |err_msg| { try renderErrorMessageToWriter(eb, options, err_msg, bw, "error", .red, 0); @@ -182,11 +188,11 @@ fn renderErrorMessageToWriter( eb: ErrorBundle, options: RenderOptions, err_msg_index: MessageIndex, - bw: *std.io.BufferedWriter, + bw: *Writer, kind: []const u8, color: std.io.tty.Color, indent: usize, -) (std.io.Writer.Error || std.posix.UnexpectedError)!void { +) (Writer.Error || std.posix.UnexpectedError)!void { const ttyconf = options.ttyconf; const err_msg = eb.getErrorMessage(err_msg_index); const prefix_start = bw.count; @@ -294,7 +300,7 @@ fn renderErrorMessageToWriter( /// to allow for long, good-looking error messages. /// /// This is used to split the message in `@compileError("hello\nworld")` for example. -fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *std.io.BufferedWriter, indent: usize) !void { +fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *Writer, indent: usize) !void { var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n'); while (lines.next()) |line| { try bw.writeAll(line); @@ -304,11 +310,6 @@ fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *std.io.BufferedWriter, } } -const std = @import("std"); -const ErrorBundle = @This(); -const Allocator = std.mem.Allocator; -const assert = std.debug.assert; - pub const Wip = struct { gpa: Allocator, string_bytes: std.ArrayListUnmanaged(u8), diff --git a/lib/std/zig/Server.zig b/lib/std/zig/Server.zig index fef8ffd20f..f317dceea8 100644 --- a/lib/std/zig/Server.zig +++ b/lib/std/zig/Server.zig @@ -1,5 +1,5 @@ in: *std.io.Reader, -out: *std.io.BufferedWriter, +out: *Writer, pub const Message = struct { pub const Header = extern struct { @@ -94,7 +94,7 @@ pub const Message = struct { pub const Options = struct { in: *std.io.Reader, - out: *std.io.BufferedWriter, + out: *Writer, zig_version: []const u8, }; @@ -215,3 +215,4 @@ const assert = std.debug.assert; const native_endian = builtin.target.cpu.arch.endian(); const need_bswap = native_endian != .little; const Cache = std.Build.Cache; +const Writer = std.io.Writer; diff --git a/lib/std/zig/WindowsSdk.zig b/lib/std/zig/WindowsSdk.zig index 2222613a4c..96a47395b6 100644 --- a/lib/std/zig/WindowsSdk.zig +++ b/lib/std/zig/WindowsSdk.zig @@ -1,11 +1,12 @@ +const WindowsSdk = @This(); +const builtin = @import("builtin"); +const std = @import("std"); +const Writer = std.io.Writer; + windows10sdk: ?Installation, windows81sdk: ?Installation, msvc_lib_dir: ?[]const u8, -const WindowsSdk = @This(); -const std = @import("std"); -const builtin = @import("builtin"); - const windows = std.os.windows; const RRF = windows.advapi32.RRF; @@ -759,8 +760,7 @@ const MsvcLibDir = struct { while (instances_dir_it.next() catch return error.PathNotFound) |entry| { if (entry.kind != .directory) continue; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&state_subpath_buf); + var bw: Writer = .fixed(&state_subpath_buf); bw.writeAll(entry.name) catch unreachable; bw.writeByte(std.fs.path.sep) catch unreachable; diff --git a/lib/std/zig/ZonGen.zig b/lib/std/zig/ZonGen.zig index e52d315d0b..8651f01223 100644 --- a/lib/std/zig/ZonGen.zig +++ b/lib/std/zig/ZonGen.zig @@ -521,8 +521,8 @@ pub fn strLitSizeHint(tree: Ast, node: Ast.Node.Index) usize { pub fn parseStrLit( tree: Ast, node: Ast.Node.Index, - writer: *std.io.BufferedWriter, -) std.io.Writer.Error!std.zig.string_literal.Result { + writer: *Writer, +) Writer.Error!std.zig.string_literal.Result { switch (tree.nodeTag(node)) { .string_literal => { const token = tree.nodeMainToken(node); @@ -933,3 +933,4 @@ const StringIndexContext = std.hash_map.StringIndexContext; const ZonGen = @This(); const Zoir = @import("Zoir.zig"); const Ast = @import("Ast.zig"); +const Writer = std.io.Writer; diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index 1d01f63f8b..209531d119 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -91,7 +91,7 @@ pub const String = enum(u32) { string: String, builder: *const Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); assert(data.string != .none); @@ -649,7 +649,7 @@ pub const Type = enum(u32) { type: Type, builder: *const Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { assert(data.type != .none); if (comptime std.mem.eql(u8, fmt_str, "m")) { const item = data.builder.type_items.items[@intFromEnum(data.type)]; @@ -1129,7 +1129,7 @@ pub const Attribute = union(Kind) { attribute_index: Index, builder: *const Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); const attribute = data.attribute_index.toAttribute(data.builder); @@ -1568,7 +1568,7 @@ pub const Attributes = enum(u32) { attributes: Attributes, builder: *const Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{ .attribute_index = attribute_index, .builder = data.builder, @@ -1761,11 +1761,11 @@ pub const Linkage = enum(u4) { extern_weak = 7, external = 0, - pub fn format(self: Linkage, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: Linkage, bw: *Writer, comptime _: []const u8) Writer.Error!void { if (self != .external) try bw.print(" {s}", .{@tagName(self)}); } - fn formatOptional(data: ?Linkage, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + fn formatOptional(data: ?Linkage, bw: *Writer, comptime _: []const u8) Writer.Error!void { if (data) |linkage| try bw.print(" {s}", .{@tagName(linkage)}); } pub fn fmtOptional(self: ?Linkage) std.fmt.Formatter(formatOptional) { @@ -1778,7 +1778,7 @@ pub const Preemption = enum { dso_local, implicit_dso_local, - pub fn format(self: Preemption, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: Preemption, bw: *Writer, comptime _: []const u8) Writer.Error!void { if (self == .dso_local) try bw.print(" {s}", .{@tagName(self)}); } }; @@ -1796,11 +1796,7 @@ pub const Visibility = enum(u2) { }; } - pub fn format( - self: Visibility, - comptime format_string: []const u8, - writer: *std.io.BufferedWriter, - ) std.io.Writer.Error!void { + pub fn format(self: Visibility, comptime format_string: []const u8, writer: *Writer) Writer.Error!void { comptime assert(format_string.len == 0); if (self != .default) try writer.print(" {s}", .{@tagName(self)}); } @@ -1811,7 +1807,7 @@ pub const DllStorageClass = enum(u2) { dllimport = 1, dllexport = 2, - pub fn format(self: DllStorageClass, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: DllStorageClass, bw: *Writer, comptime _: []const u8) Writer.Error!void { if (self != .default) try bw.print(" {s}", .{@tagName(self)}); } }; @@ -1823,7 +1819,7 @@ pub const ThreadLocal = enum(u3) { initialexec = 3, localexec = 4, - pub fn format(self: ThreadLocal, bw: *std.io.BufferedWriter, comptime prefix: []const u8) std.io.Writer.Error!void { + pub fn format(self: ThreadLocal, bw: *Writer, comptime prefix: []const u8) Writer.Error!void { if (self == .default) return; try bw.print("{s}thread_local", .{prefix}); if (self != .generaldynamic) try bw.print("({s})", .{@tagName(self)}); @@ -1837,7 +1833,7 @@ pub const UnnamedAddr = enum(u2) { unnamed_addr = 1, local_unnamed_addr = 2, - pub fn format(self: UnnamedAddr, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: UnnamedAddr, bw: *Writer, comptime _: []const u8) Writer.Error!void { if (self != .default) try bw.print(" {s}", .{@tagName(self)}); } }; @@ -1931,7 +1927,7 @@ pub const AddrSpace = enum(u24) { pub const funcref: AddrSpace = @enumFromInt(20); }; - pub fn format(self: AddrSpace, bw: *std.io.BufferedWriter, comptime prefix: []const u8) std.io.Writer.Error!void { + pub fn format(self: AddrSpace, bw: *Writer, comptime prefix: []const u8) Writer.Error!void { if (self != .default) try bw.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) }); } }; @@ -1940,7 +1936,7 @@ pub const ExternallyInitialized = enum { default, externally_initialized, - pub fn format(self: ExternallyInitialized, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: ExternallyInitialized, bw: *Writer, comptime _: []const u8) Writer.Error!void { if (self != .default) try bw.print(" {s}", .{@tagName(self)}); } }; @@ -1964,7 +1960,7 @@ pub const Alignment = enum(u6) { return if (self == .default) 0 else (@intFromEnum(self) + 1); } - pub fn format(self: Alignment, bw: *std.io.BufferedWriter, comptime prefix: []const u8) std.io.Writer.Error!void { + pub fn format(self: Alignment, bw: *Writer, comptime prefix: []const u8) Writer.Error!void { try bw.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return }); } }; @@ -2038,7 +2034,7 @@ pub const CallConv = enum(u10) { pub const default = CallConv.ccc; - pub fn format(self: CallConv, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: CallConv, bw: *Writer, comptime _: []const u8) Writer.Error!void { switch (self) { default => {}, .fastcc, @@ -2119,7 +2115,7 @@ pub const StrtabString = enum(u32) { string: StrtabString, builder: *const Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); assert(data.string != .none); @@ -2306,7 +2302,7 @@ pub const Global = struct { global: Index, builder: *const Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime _: []const u8) Writer.Error!void { try bw.print("@{f}", .{ data.global.unwrap(data.builder).name(data.builder).fmt(data.builder), }); @@ -4752,7 +4748,7 @@ pub const Function = struct { function: Function.Index, builder: *Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) { @@ -6944,7 +6940,7 @@ pub const MemoryAccessKind = enum(u1) { normal, @"volatile", - pub fn format(self: MemoryAccessKind, bw: *std.io.BufferedWriter, comptime prefix: []const u8) std.io.Writer.Error!void { + pub fn format(self: MemoryAccessKind, bw: *Writer, comptime prefix: []const u8) Writer.Error!void { if (self != .normal) try bw.print("{s}{s}", .{ prefix, @tagName(self) }); } }; @@ -6953,7 +6949,7 @@ pub const SyncScope = enum(u1) { singlethread, system, - pub fn format(self: SyncScope, bw: *std.io.BufferedWriter, comptime prefix: []const u8) std.io.Writer.Error!void { + pub fn format(self: SyncScope, bw: *Writer, comptime prefix: []const u8) Writer.Error!void { if (self != .system) try bw.print( \\{s}syncscope("{s}") , .{ prefix, @tagName(self) }); @@ -6969,7 +6965,7 @@ pub const AtomicOrdering = enum(u3) { acq_rel = 5, seq_cst = 6, - pub fn format(self: AtomicOrdering, bw: *std.io.BufferedWriter, comptime prefix: []const u8) std.io.Writer.Error!void { + pub fn format(self: AtomicOrdering, bw: *Writer, comptime prefix: []const u8) Writer.Error!void { if (self != .none) try bw.print("{s}{s}", .{ prefix, @tagName(self) }); } }; @@ -7385,7 +7381,7 @@ pub const Constant = enum(u32) { constant: Constant, builder: *Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) { @@ -7712,7 +7708,7 @@ pub const Value = enum(u32) { function: Function.Index, builder: *Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { switch (data.value.unwrap()) { .instruction => |instruction| try Function.Instruction.Index.format(.{ .instruction = instruction, @@ -7757,7 +7753,7 @@ pub const MetadataString = enum(u32) { metadata_string: MetadataString, builder: *const Builder, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime _: []const u8) Writer.Error!void { try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, bw); } fn fmt(self: MetadataString, builder: *const Builder) std.fmt.Formatter(format) { @@ -7922,7 +7918,7 @@ pub const Metadata = enum(u32) { AllCallsDescribed: bool = false, Unused: u2 = 0, - pub fn format(self: DIFlags, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: DIFlags, bw: *Writer, comptime _: []const u8) Writer.Error!void { var need_pipe = false; inline for (@typeInfo(DIFlags).@"struct".fields) |field| { switch (@typeInfo(field.type)) { @@ -7979,7 +7975,7 @@ pub const Metadata = enum(u32) { ObjCDirect: bool = false, Unused: u20 = 0, - pub fn format(self: DISPFlags, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: DISPFlags, bw: *Writer, comptime _: []const u8) Writer.Error!void { var need_pipe = false; inline for (@typeInfo(DISPFlags).@"struct".fields) |field| { switch (@typeInfo(field.type)) { @@ -8196,7 +8192,7 @@ pub const Metadata = enum(u32) { }; }; }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *Writer, comptime fmt_str: []const u8) Writer.Error!void { if (data.node == .none) return; const is_specialized = fmt_str.len > 0 and fmt_str[0] == 'S'; @@ -8370,7 +8366,7 @@ pub const Metadata = enum(u32) { DIGlobalVariableExpression, }, nodes: anytype, - bw: *std.io.BufferedWriter, + bw: *Writer, ) !void { comptime var fmt_str: []const u8 = ""; const names = comptime std.meta.fieldNames(@TypeOf(nodes)); @@ -8623,12 +8619,12 @@ pub fn deinit(self: *Builder) void { self.* = undefined; } -pub fn setModuleAsm(self: *Builder, aw: *std.io.AllocatingWriter) *std.io.BufferedWriter { +pub fn setModuleAsm(self: *Builder, aw: *std.io.AllocatingWriter) *Writer { self.module_asm.clearRetainingCapacity(); return self.appendModuleAsm(aw); } -pub fn appendModuleAsm(self: *Builder, aw: *std.io.AllocatingWriter) *std.io.BufferedWriter { +pub fn appendModuleAsm(self: *Builder, aw: *std.io.AllocatingWriter) *Writer { return aw.fromArrayList(self.gpa, &self.module_asm); } @@ -9379,14 +9375,14 @@ pub fn printToFile(self: *Builder, path: []const u8) bool { return true; } -pub fn printBuffered(self: *Builder, writer: std.io.Writer) std.io.Writer.Error!void { +pub fn printBuffered(self: *Builder, writer: Writer) Writer.Error!void { var buffer: [4096]u8 = undefined; var bw = writer.buffered(&buffer); try self.print(&bw); try bw.flush(); } -pub fn print(self: *Builder, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn print(self: *Builder, bw: *Writer) Writer.Error!void { var need_newline = false; var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined }; defer metadata_formatter.map.deinit(self.gpa); @@ -10458,7 +10454,7 @@ fn isValidIdentifier(id: []const u8) bool { } const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier }; -fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, bw: *Writer) Writer.Error!void { const need_quotes = switch (quotes) { .always_quote => true, .quote_unless_valid_identifier => !isValidIdentifier(slice), @@ -15097,6 +15093,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco return bitcode.toOwnedSlice(); } +const std = @import("../../std.zig"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; const bitcode_writer = @import("bitcode_writer.zig"); @@ -15105,4 +15102,4 @@ const builtin = @import("builtin"); const DW = std.dwarf; const ir = @import("ir.zig"); const log = std.log.scoped(.llvm); -const std = @import("../../std.zig"); +const Writer = std.io.Writer; diff --git a/lib/std/zig/string_literal.zig b/lib/std/zig/string_literal.zig index 592258d251..9add78b2b0 100644 --- a/lib/std/zig/string_literal.zig +++ b/lib/std/zig/string_literal.zig @@ -1,6 +1,7 @@ const std = @import("../std.zig"); const assert = std.debug.assert; const utf8Encode = std.unicode.utf8Encode; +const Writer = std.io.Writer; pub const ParseError = error{ OutOfMemory, @@ -44,7 +45,7 @@ pub const Error = union(enum) { raw_string: []const u8, }; - fn formatMessage(self: FormatMessage, bw: *std.io.BufferedWriter, comptime f: []const u8) !void { + fn formatMessage(self: FormatMessage, bw: *Writer, comptime f: []const u8) !void { _ = f; switch (self.err) { .invalid_escape_character => |bad_index| try bw.print( @@ -316,9 +317,9 @@ test parseCharLiteral { ); } -/// Parses `bytes` as a Zig string literal and writes the result to the `std.io.Writer` type. +/// Parses `bytes` as a Zig string literal and writes the result to the `Writer` type. /// Asserts `bytes` has '"' at beginning and end. -pub fn parseWrite(writer: *std.io.BufferedWriter, bytes: []const u8) std.io.Writer.Error!Result { +pub fn parseWrite(writer: *Writer, bytes: []const u8) Writer.Error!Result { assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"'); var index: usize = 1; diff --git a/lib/std/zip.zig b/lib/std/zip.zig index ff20f3847d..4f783956f6 100644 --- a/lib/std/zip.zig +++ b/lib/std/zip.zig @@ -7,6 +7,7 @@ const builtin = @import("builtin"); const std = @import("std"); const File = std.fs.File; const is_le = builtin.target.cpu.arch.endian() == .little; +const Writer = std.io.Writer; pub const CompressionMethod = enum(u16) { store = 0, @@ -200,7 +201,7 @@ pub const Decompress = union { fn readStore( context: ?*anyopaque, - writer: *std.io.BufferedWriter, + writer: *Writer, limit: std.io.Limit, ) std.io.Reader.StreamError!usize { const d: *Decompress = @ptrCast(@alignCast(context)); @@ -209,7 +210,7 @@ pub const Decompress = union { fn readDeflate( context: ?*anyopaque, - writer: *std.io.BufferedWriter, + writer: *Writer, limit: std.io.Limit, ) std.io.Reader.StreamError!usize { const d: *Decompress = @ptrCast(@alignCast(context)); diff --git a/lib/std/zip/test.zig b/lib/std/zip/test.zig index a02ee1ab2b..c88f42d36a 100644 --- a/lib/std/zip/test.zig +++ b/lib/std/zip/test.zig @@ -3,6 +3,7 @@ const testing = std.testing; const zip = @import("../zip.zig"); const maxInt = std.math.maxInt; const assert = std.debug.assert; +const Writer = std.io.Writer; const File = struct { name: []const u8, @@ -103,7 +104,7 @@ const Zip64Options = struct { }; fn writeZip( - writer: *std.io.BufferedWriter, + writer: *Writer, files: []const File, store: []FileStore, options: WriteZipOptions, @@ -129,13 +130,13 @@ fn writeZip( /// Provides methods to format and write the contents of a zip archive /// to the underlying Writer. const Zipper = struct { - writer: *std.io.BufferedWriter, + writer: *Writer, init_count: u64, central_count: u64 = 0, first_central_offset: ?u64 = null, last_central_limit: ?u64 = null, - fn init(writer: *std.io.BufferedWriter) Zipper { + fn init(writer: *Writer) Zipper { return .{ .writer = writer, .init_count = writer.count }; } @@ -198,8 +199,7 @@ const Zipper = struct { }, .deflate => { const offset = writer.count; - var br: std.io.Reader = undefined; - br.initFixed(@constCast(opt.content)); + var br: std.io.Reader = .fixed(opt.content); var compress: std.compress.flate.Compress = .init(&br, .{}); var compress_br = compress.readable(&.{}); const n = try compress_br.readRemaining(writer); diff --git a/lib/std/zon/stringify.zig b/lib/std/zon/stringify.zig index d0d9a8e74f..e5d964826b 100644 --- a/lib/std/zon/stringify.zig +++ b/lib/std/zon/stringify.zig @@ -22,7 +22,7 @@ const std = @import("std"); const assert = std.debug.assert; -const BufferedWriter = std.io.BufferedWriter; +const Writer = std.io.Writer; /// Options for `serialize`. pub const SerializeOptions = struct { @@ -41,7 +41,7 @@ pub const SerializeOptions = struct { /// Serialize the given value as ZON. /// /// It is asserted at comptime that `@TypeOf(val)` is not a recursive type. -pub fn serialize(val: anytype, options: SerializeOptions, writer: *BufferedWriter) std.io.Writer.Error!void { +pub fn serialize(val: anytype, options: SerializeOptions, writer: *Writer) Writer.Error!void { var s: Serializer = .{ .writer = writer, .options = .{ .whitespace = options.whitespace }, @@ -60,7 +60,7 @@ pub fn serialize(val: anytype, options: SerializeOptions, writer: *BufferedWrite pub fn serializeMaxDepth( val: anytype, options: SerializeOptions, - writer: *BufferedWriter, + writer: *Writer, depth: usize, ) Serializer.DepthError!void { var s: Serializer = .{ @@ -80,7 +80,7 @@ pub fn serializeMaxDepth( pub fn serializeArbitraryDepth( val: anytype, options: SerializeOptions, - writer: *BufferedWriter, + writer: *Writer, ) Serializer.Error!void { var s: Serializer = .{ .writer = writer, @@ -437,9 +437,9 @@ pub const SerializeContainerOptions = struct { pub const Serializer = struct { options: Options = .{}, indent_level: u8 = 0, - writer: *BufferedWriter, + writer: *Writer, - pub const Error = std.io.Writer.Error; + pub const Error = Writer.Error; pub const DepthError = Error || error{ExceededMaxDepth}; pub const Options = struct { @@ -1040,7 +1040,7 @@ pub const Serializer = struct { }; test Serializer { - var bw: std.io.BufferedWriter = .{ + var bw: Writer = .{ .unbuffered_writer = .discarding, .buffer = &.{}, }; diff --git a/lib/ubsan_rt.zig b/lib/ubsan_rt.zig index 6e1198f835..ab1727e745 100644 --- a/lib/ubsan_rt.zig +++ b/lib/ubsan_rt.zig @@ -119,7 +119,7 @@ const Value = extern struct { } } - pub fn format(value: Value, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { + pub fn format(value: Value, bw: *std.io.Writer, comptime fmt: []const u8) !void { comptime assert(fmt.len == 0); // Work around x86_64 backend limitation. diff --git a/src/Air.zig b/src/Air.zig index 7d4766125f..37dddb27f8 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -7,6 +7,7 @@ const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; +const Writer = std.io.Writer; const Air = @This(); const InternPool = @import("InternPool.zig"); @@ -957,7 +958,8 @@ pub const Inst = struct { return index.unwrap().target; } - pub fn format(index: Index, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(index: Index, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); try bw.writeByte('%'); switch (index.unwrap()) { .ref => {}, diff --git a/src/Air/Liveness.zig b/src/Air/Liveness.zig index 038254b5d0..9fab03c679 100644 --- a/src/Air/Liveness.zig +++ b/src/Air/Liveness.zig @@ -10,6 +10,7 @@ const log = std.log.scoped(.liveness); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const Log2Int = std.math.Log2Int; +const Writer = std.io.Writer; const Liveness = @This(); const trace = @import("../tracy.zig").trace; @@ -2036,7 +2037,7 @@ fn fmtInstSet(set: *const std.AutoHashMapUnmanaged(Air.Inst.Index, void)) FmtIns const FmtInstSet = struct { set: *const std.AutoHashMapUnmanaged(Air.Inst.Index, void), - pub fn format(val: FmtInstSet, bw: *std.io.BufferedWriter, comptime _: []const u8) !void { + pub fn format(val: FmtInstSet, bw: *Writer, comptime _: []const u8) !void { if (val.set.count() == 0) { try bw.writeAll("[no instructions]"); return; @@ -2056,7 +2057,8 @@ fn fmtInstList(list: []const Air.Inst.Index) FmtInstList { const FmtInstList = struct { list: []const Air.Inst.Index, - pub fn format(val: FmtInstList, bw: *std.io.BufferedWriter, comptime _: []const u8) !void { + pub fn format(val: FmtInstList, bw: *Writer, comptime fmt: []const u8) !void { + comptime assert(fmt.len == 0); if (val.list.len == 0) { try bw.writeAll("[no instructions]"); return; diff --git a/src/Air/print.zig b/src/Air/print.zig index 4133f76483..04d2f7933e 100644 --- a/src/Air/print.zig +++ b/src/Air/print.zig @@ -8,7 +8,7 @@ const Type = @import("../Type.zig"); const Air = @import("../Air.zig"); const InternPool = @import("../InternPool.zig"); -pub fn write(air: Air, stream: *std.io.BufferedWriter, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { +pub fn write(air: Air, stream: *std.io.Writer, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { comptime std.debug.assert(build_options.enable_debug_extensions); const instruction_bytes = air.instructions.len * // Here we don't use @sizeOf(Air.Inst.Data) because it would include @@ -54,7 +54,7 @@ pub fn write(air: Air, stream: *std.io.BufferedWriter, pt: Zcu.PerThread, livene pub fn writeInst( air: Air, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness, @@ -93,14 +93,14 @@ const Writer = struct { const Error = std.io.Writer.Error; - fn writeBody(w: *Writer, s: *std.io.BufferedWriter, body: []const Air.Inst.Index) Error!void { + fn writeBody(w: *Writer, s: *std.io.Writer, body: []const Air.Inst.Index) Error!void { for (body) |inst| { try w.writeInst(s, inst); try s.writeByte('\n'); } } - fn writeInst(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeInst(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)]; try s.splatByteAll(' ', w.indent); try s.print("{f}{c}= {s}(", .{ @@ -340,48 +340,48 @@ const Writer = struct { try s.writeByte(')'); } - fn writeBinOp(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeBinOp(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; try w.writeOperand(s, inst, 0, bin_op.lhs); try s.writeAll(", "); try w.writeOperand(s, inst, 1, bin_op.rhs); } - fn writeUnOp(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeUnOp(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const un_op = w.air.instructions.items(.data)[@intFromEnum(inst)].un_op; try w.writeOperand(s, inst, 0, un_op); } - fn writeNoOp(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeNoOp(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { _ = w; _ = s; _ = inst; // no-op, no argument to write } - fn writeType(w: *Writer, s: *std.io.BufferedWriter, ty: Type) !void { + fn writeType(w: *Writer, s: *std.io.Writer, ty: Type) !void { return ty.print(s, w.pt); } - fn writeTy(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeTy(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty = w.air.instructions.items(.data)[@intFromEnum(inst)].ty; try w.writeType(s, ty); } - fn writeArg(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeArg(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const arg = w.air.instructions.items(.data)[@intFromEnum(inst)].arg; try w.writeType(s, arg.ty.toType()); try s.print(", {d}", .{arg.zir_param_index}); } - fn writeTyOp(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeTyOp(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_op = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; try w.writeType(s, ty_op.ty.toType()); try s.writeAll(", "); try w.writeOperand(s, inst, 0, ty_op.operand); } - fn writeBlock(w: *Writer, s: *std.io.BufferedWriter, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void { + fn writeBlock(w: *Writer, s: *std.io.Writer, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; try w.writeType(s, ty_pl.ty.toType()); const body: []const Air.Inst.Index = @ptrCast(switch (tag) { @@ -422,7 +422,7 @@ const Writer = struct { } } - fn writeLoop(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeLoop(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.Block, ty_pl.payload); const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]); @@ -438,7 +438,7 @@ const Writer = struct { try s.writeAll("}"); } - fn writeAggregateInit(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeAggregateInit(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const zcu = w.pt.zcu; const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const vector_ty = ty_pl.ty.toType(); @@ -454,7 +454,7 @@ const Writer = struct { try s.writeAll("]"); } - fn writeUnionInit(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeUnionInit(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data; @@ -462,7 +462,7 @@ const Writer = struct { try w.writeOperand(s, inst, 0, extra.init); } - fn writeStructField(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeStructField(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.StructField, ty_pl.payload).data; @@ -470,7 +470,7 @@ const Writer = struct { try s.print(", {d}", .{extra.field_index}); } - fn writeTyPlBin(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeTyPlBin(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const data = w.air.instructions.items(.data); const ty_pl = data[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.Bin, ty_pl.payload).data; @@ -483,7 +483,7 @@ const Writer = struct { try w.writeOperand(s, inst, 1, extra.rhs); } - fn writeCmpxchg(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeCmpxchg(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data; @@ -497,7 +497,7 @@ const Writer = struct { }); } - fn writeMulAdd(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeMulAdd(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = w.air.extraData(Air.Bin, pl_op.payload).data; @@ -508,7 +508,7 @@ const Writer = struct { try w.writeOperand(s, inst, 2, pl_op.operand); } - fn writeShuffleOne(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeShuffleOne(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const unwrapped = w.air.unwrapShuffleOne(w.pt.zcu, inst); try w.writeType(s, unwrapped.result_ty); try s.writeAll(", "); @@ -543,7 +543,7 @@ const Writer = struct { try s.writeByte(']'); } - fn writeSelect(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeSelect(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const zcu = w.pt.zcu; const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = w.air.extraData(Air.Bin, pl_op.payload).data; @@ -558,14 +558,14 @@ const Writer = struct { try w.writeOperand(s, inst, 2, extra.rhs); } - fn writeReduce(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeReduce(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const reduce = w.air.instructions.items(.data)[@intFromEnum(inst)].reduce; try w.writeOperand(s, inst, 0, reduce.operand); try s.print(", {s}", .{@tagName(reduce.operation)}); } - fn writeCmpVector(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeCmpVector(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data; @@ -575,7 +575,7 @@ const Writer = struct { try w.writeOperand(s, inst, 1, extra.rhs); } - fn writeVectorStoreElem(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeVectorStoreElem(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const data = w.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem; const extra = w.air.extraData(Air.VectorCmp, data.payload).data; @@ -586,21 +586,21 @@ const Writer = struct { try w.writeOperand(s, inst, 2, extra.rhs); } - fn writeRuntimeNavPtr(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeRuntimeNavPtr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ip = &w.pt.zcu.intern_pool; const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; try w.writeType(s, .fromInterned(ty_nav.ty)); try s.print(", '{}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)}); } - fn writeAtomicLoad(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeAtomicLoad(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load; try w.writeOperand(s, inst, 0, atomic_load.ptr); try s.print(", {s}", .{@tagName(atomic_load.order)}); } - fn writePrefetch(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writePrefetch(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const prefetch = w.air.instructions.items(.data)[@intFromEnum(inst)].prefetch; try w.writeOperand(s, inst, 0, prefetch.ptr); @@ -611,7 +611,7 @@ const Writer = struct { fn writeAtomicStore( w: *Writer, - s: *std.io.BufferedWriter, + s: *std.io.Writer, inst: Air.Inst.Index, order: std.builtin.AtomicOrder, ) Error!void { @@ -622,7 +622,7 @@ const Writer = struct { try s.print(", {s}", .{@tagName(order)}); } - fn writeAtomicRmw(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeAtomicRmw(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data; @@ -632,7 +632,7 @@ const Writer = struct { try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) }); } - fn writeFieldParentPtr(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeFieldParentPtr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; @@ -640,7 +640,7 @@ const Writer = struct { try s.print(", {d}", .{extra.field_index}); } - fn writeAssembly(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeAssembly(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.Asm, ty_pl.payload); const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0; @@ -713,19 +713,19 @@ const Writer = struct { try s.print(", \"{f}\"", .{std.zig.fmtEscapes(asm_source)}); } - fn writeDbgStmt(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeDbgStmt(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const dbg_stmt = w.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); } - fn writeDbgVar(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeDbgVar(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; try w.writeOperand(s, inst, 0, pl_op.operand); const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); try s.print(", \"{f}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))}); } - fn writeCall(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeCall(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = w.air.extraData(Air.Call, pl_op.payload); const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len])); @@ -738,19 +738,19 @@ const Writer = struct { try s.writeAll("]"); } - fn writeBr(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeBr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const br = w.air.instructions.items(.data)[@intFromEnum(inst)].br; try w.writeInstIndex(s, br.block_inst, false); try s.writeAll(", "); try w.writeOperand(s, inst, 0, br.operand); } - fn writeRepeat(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeRepeat(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const repeat = w.air.instructions.items(.data)[@intFromEnum(inst)].repeat; try w.writeInstIndex(s, repeat.loop_inst, false); } - fn writeTry(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeTry(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = w.air.extraData(Air.Try, pl_op.payload); const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]); @@ -784,7 +784,7 @@ const Writer = struct { } } - fn writeTryPtr(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeTryPtr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = w.air.extraData(Air.TryPtr, ty_pl.payload); const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]); @@ -821,7 +821,7 @@ const Writer = struct { } } - fn writeCondBr(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeCondBr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = w.air.extraData(Air.CondBr, pl_op.payload); const then_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.then_body_len]); @@ -880,7 +880,7 @@ const Writer = struct { try s.writeAll("}"); } - fn writeSwitchBr(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeSwitchBr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const switch_br = w.air.unwrapSwitch(inst); const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness| @@ -966,25 +966,25 @@ const Writer = struct { try s.splatByteAll(' ', old_indent); } - fn writeWasmMemorySize(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeWasmMemorySize(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; try s.print("{d}", .{pl_op.payload}); } - fn writeWasmMemoryGrow(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeWasmMemoryGrow(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; try s.print("{d}, ", .{pl_op.payload}); try w.writeOperand(s, inst, 0, pl_op.operand); } - fn writeWorkDimension(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) Error!void { + fn writeWorkDimension(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; try s.print("{d}", .{pl_op.payload}); } fn writeOperand( w: *Writer, - s: *std.io.BufferedWriter, + s: *std.io.Writer, inst: Air.Inst.Index, op_index: usize, operand: Air.Inst.Ref, @@ -1030,7 +1030,7 @@ const Writer = struct { fn writeInstIndex( w: *Writer, - s: *std.io.BufferedWriter, + s: *std.io.Writer, inst: Air.Inst.Index, dies: bool, ) Error!void { diff --git a/src/Compilation.zig b/src/Compilation.zig index ea8d63e6d2..d1adbb6322 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -12,6 +12,7 @@ const ThreadPool = std.Thread.Pool; const WaitGroup = std.Thread.WaitGroup; const ErrorBundle = std.zig.ErrorBundle; const fatal = std.process.fatal; +const Writer = std.io.Writer; const Value = @import("Value.zig"); const Type = @import("Type.zig"); @@ -1000,15 +1001,12 @@ pub const CObject = struct { const file = std.fs.cwd().openFile(file_name, .{}) catch break :source_line 0; defer file.close(); - file.seekTo(diag.src_loc.offset + 1 - diag.src_loc.column) catch break :source_line 0; - var buffer: [1 << 10]u8 = undefined; - var fr = file.reader(); - var br = fr.interface().buffered(&buffer); - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buffer); + var fr = file.reader(&buffer); + fr.seekTo(diag.src_loc.offset + 1 - diag.src_loc.column) catch break :source_line 0; + var bw: Writer = .fixed(&buffer); break :source_line try eb.addString( - buffer[0 .. br.readDelimiterEnding(&bw, '\n') catch break :source_line 0], + buffer[0 .. fr.interface.readDelimiterEnding(&bw, '\n') catch break :source_line 0], ); }; @@ -6026,8 +6024,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // In .rc files, a " within a quoted string is escaped as "" const fmtRcEscape = struct { - fn formatRcEscape(bytes: []const u8, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { - _ = fmt; + fn formatRcEscape(bytes: []const u8, bw: *Writer, comptime fmt: []const u8) !void { + comptime assert(fmt.len == 0); for (bytes) |byte| switch (byte) { '"' => try bw.writeAll("\"\""), '\\' => try bw.writeAll("\\\\"), diff --git a/src/InternPool.zig b/src/InternPool.zig index 8016c66bde..99696f5403 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1888,7 +1888,7 @@ pub const NullTerminatedString = enum(u32) { string: NullTerminatedString, ip: *const InternPool, }; - fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime specifier: []const u8) std.io.Writer.Error!void { + fn format(data: FormatData, bw: *std.io.Writer, comptime specifier: []const u8) std.io.Writer.Error!void { const slice = data.string.toSlice(data.ip); if (comptime std.mem.eql(u8, specifier, "")) { try bw.writeAll(slice); diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index fbcc459443..9c0db8387a 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -1366,9 +1366,9 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U const index_prog_node = f.prog_node.start("Index pack", 0); defer index_prog_node.end(); var buffer: [4096]u8 = undefined; - var index_buffered_writer: std.io.BufferedWriter = index_file.writer().buffered(&buffer); - try git.indexPack(gpa, object_format, pack_file, &index_buffered_writer); - try index_buffered_writer.flush(); + var index_file_writer = index_file.writer(&buffer); + try git.indexPack(gpa, object_format, pack_file, &index_file_writer.interface); + try index_file_writer.flush(); try index_file.sync(); } @@ -1639,14 +1639,14 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute fn dumpHashInfo(all_files: []const *const HashedFile) !void { var buffer: [4096]u8 = undefined; - var bw: std.io.BufferedWriter = std.fs.File.stdout().writer().buffered(&buffer); + var file_writer = std.fs.File.stdout().writer(&buffer); + const w = &file_writer.interface; for (all_files) |hashed_file| { - try bw.print("{s}: {x}: {s}\n", .{ + try w.print("{s}: {x}: {s}\n", .{ @tagName(hashed_file.kind), &hashed_file.hash, hashed_file.normalized_path, }); } - - try bw.flush(); + try file_writer.flush(); } fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile) void { diff --git a/src/Package/Fetch/git.zig b/src/Package/Fetch/git.zig index c6cdf82774..f5a28a76c6 100644 --- a/src/Package/Fetch/git.zig +++ b/src/Package/Fetch/git.zig @@ -12,6 +12,7 @@ const Sha1 = std.crypto.hash.Sha1; const Sha256 = std.crypto.hash.sha2.Sha256; const assert = std.debug.assert; const zlib = std.compress.zlib; +const Writer = std.io.Writer; /// The ID of a Git object. pub const Oid = union(Format) { @@ -65,7 +66,7 @@ pub const Oid = union(Format) { }; } - pub fn writable(hasher: *Hasher, buffer: []u8) std.io.BufferedWriter { + pub fn writer(hasher: *Hasher, buffer: []u8) Writer { return switch (hasher.*) { inline else => |*inner| inner.writable(buffer), }; @@ -134,9 +135,9 @@ pub const Oid = union(Format) { } else error.InvalidOid; } - pub fn format(oid: Oid, bw: *std.io.BufferedWriter, comptime fmt: []const u8) std.io.Writer.Error!void { - _ = fmt; - try bw.print("{x}", .{oid.slice()}); + pub fn format(oid: Oid, w: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); + try w.print("{x}", .{oid.slice()}); } pub fn slice(oid: *const Oid) []const u8 { @@ -608,7 +609,7 @@ const Packet = union(enum) { } /// Writes a packet in pkt-line format. - fn write(packet: Packet, writer: *std.io.BufferedWriter) !void { + fn write(packet: Packet, writer: *Writer) !void { switch (packet) { .flush => try writer.writeAll("0000"), .delimiter => try writer.writeAll("0001"), @@ -1481,8 +1482,7 @@ fn resolveDeltaChain( const expanded_alloc_size = std.math.cast(usize, expanded_size) orelse return error.ObjectTooLarge; const expanded_data = try allocator.alloc(u8, expanded_alloc_size); errdefer allocator.free(expanded_data); - var expanded_delta_stream: std.io.BufferedWriter = undefined; - expanded_delta_stream.initFixed(expanded_data); + var expanded_delta_stream: Writer = .fixed(expanded_data); try expandDelta(base_data, &delta_reader, &expanded_delta_stream); if (expanded_delta_stream.end != expanded_size) return error.InvalidObject; @@ -1505,7 +1505,7 @@ fn readObjectRaw(gpa: Allocator, reader: *std.io.Reader, size: u64) ![]u8 { /// The format of the delta data is documented in /// [pack-format](https://git-scm.com/docs/pack-format). -fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *std.io.BufferedWriter) !void { +fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *Writer) !void { var base_offset: u32 = 0; while (true) { const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.takeByte() catch |e| switch (e) { diff --git a/src/Sema.zig b/src/Sema.zig index 8b5cdaee3e..df4dbeabbd 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9544,8 +9544,8 @@ fn callConvSupportsVarArgs(cc: std.builtin.CallingConvention.Tag) bool { fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: std.builtin.CallingConvention.Tag) CompileError!void { const CallingConventionsSupportingVarArgsList = struct { arch: std.Target.Cpu.Arch, - pub fn format(ctx: @This(), bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { - _ = fmt; + pub fn format(ctx: @This(), bw: *std.io.Writer, comptime fmt: []const u8) !void { + comptime assert(fmt.len == 0); var first = true; for (calling_conventions_supporting_var_args) |cc_inner| { for (std.Target.Cpu.Arch.fromCallingConvention(cc_inner)) |supported_arch| { @@ -9990,8 +9990,8 @@ fn finishFunc( .bad_arch => |allowed_archs| { const ArchListFormatter = struct { archs: []const std.Target.Cpu.Arch, - pub fn format(formatter: @This(), bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { - _ = fmt; + pub fn format(formatter: @This(), bw: *std.io.Writer, comptime fmt: []const u8) !void { + comptime assert(fmt.len == 0); for (formatter.archs, 0..) |arch, i| { if (i != 0) try bw.writeAll(", "); diff --git a/src/Type.zig b/src/Type.zig index 242c6582a2..d623e5c700 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -18,6 +18,7 @@ const Alignment = InternPool.Alignment; const Zir = std.zig.Zir; const Type = @This(); const SemaError = Zcu.SemaError; +const Writer = std.io.Writer; ip_index: InternPool.Index, @@ -121,7 +122,7 @@ pub fn eql(a: Type, b: Type, zcu: *const Zcu) bool { return a.toIntern() == b.toIntern(); } -pub fn format(ty: Type, bw: *std.io.BufferedWriter, comptime f: []const u8) !usize { +pub fn format(ty: Type, bw: *Writer, comptime f: []const u8) !usize { _ = ty; _ = f; _ = bw; @@ -142,7 +143,7 @@ const FormatContext = struct { pt: Zcu.PerThread, }; -fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime f: []const u8) !void { +fn format2(ctx: FormatContext, bw: *Writer, comptime f: []const u8) !void { comptime assert(f.len == 0); try print(ctx.ty, bw, ctx.pt); } @@ -153,14 +154,14 @@ pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) { /// This is a debug function. In order to print types in a meaningful way /// we also need access to the module. -pub fn dump(start_type: Type, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) !void { +pub fn dump(start_type: Type, bw: *Writer, comptime unused_format_string: []const u8) !void { comptime assert(unused_format_string.len == 0); return bw.print("{any}", .{start_type.ip_index}); } /// Prints a name suitable for `@typeName`. /// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels. -pub fn print(ty: Type, bw: *std.io.BufferedWriter, pt: Zcu.PerThread) std.io.Writer.Error!void { +pub fn print(ty: Type, bw: *Writer, pt: Zcu.PerThread) Writer.Error!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; switch (ip.indexToKey(ty.toIntern())) { diff --git a/src/Zcu.zig b/src/Zcu.zig index 5508d6533d..dba8aca19a 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -15,6 +15,7 @@ const BigIntConst = std.math.big.int.Const; const BigIntMutable = std.math.big.int.Mutable; const Target = std.Target; const Ast = std.zig.Ast; +const Writer = std.io.Writer; const Zcu = @This(); const Compilation = @import("Compilation.zig"); @@ -1101,8 +1102,7 @@ pub const File = struct { const gpa = pt.zcu.gpa; const ip = &pt.zcu.intern_pool; const strings = ip.getLocal(pt.tid).getMutableStrings(gpa); - var bw: std.io.BufferedWriter = undefined; - bw.initFixed((try strings.addManyAsSlice(file.fullyQualifiedNameLen()))[0]); + var bw: Writer = .fixed((try strings.addManyAsSlice(file.fullyQualifiedNameLen()))[0]); file.renderFullyQualifiedName(&bw) catch unreachable; assert(bw.end == bw.buffer.len); return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(bw.end), .no_embedded_nulls); @@ -4260,7 +4260,7 @@ pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Formatter(formatDe return .{ .data = .{ .dependee = d, .zcu = zcu } }; } -fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { +fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, bw: *Writer, comptime fmt: []const u8) !void { _ = fmt; const zcu = data.zcu; const ip = &zcu.intern_pool; @@ -4284,7 +4284,7 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, bw: *std.io.Buffer .memoized_state => return bw.writeAll("memoized_state"), } } -fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { +fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, bw: *Writer, comptime fmt: []const u8) !void { _ = fmt; const zcu = data.zcu; const ip = &zcu.intern_pool; diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 19ee60550c..6914e881a0 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -6,6 +6,7 @@ const mem = std.mem; const math = std.math; const assert = std.debug.assert; const Allocator = mem.Allocator; +const Writer = std.io.Writer; const Air = @import("../../Air.zig"); const Mir = @import("Mir.zig"); @@ -566,7 +567,8 @@ const InstTracking = struct { } } - pub fn format(inst_tracking: InstTracking, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(inst_tracking: InstTracking, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); if (!std.meta.eql(inst_tracking.long, inst_tracking.short)) try bw.print("|{}| ", .{inst_tracking.long}); try bw.print("{}", .{inst_tracking.short}); } @@ -932,7 +934,7 @@ const FormatWipMirData = struct { func: *Func, inst: Mir.Inst.Index, }; -fn formatWipMir(data: FormatWipMirData, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { +fn formatWipMir(data: FormatWipMirData, bw: *Writer, comptime _: []const u8) Writer.Error!void { const pt = data.func.pt; const comp = pt.zcu.comp; var lower: Lower = .{ @@ -980,7 +982,7 @@ const FormatNavData = struct { ip: *const InternPool, nav_index: InternPool.Nav.Index, }; -fn formatNav(data: FormatNavData, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { +fn formatNav(data: FormatNavData, bw: *Writer, comptime _: []const u8) Writer.Error!void { try bw.print("{f}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)}); } fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) { @@ -994,8 +996,13 @@ const FormatAirData = struct { func: *Func, inst: Air.Inst.Index, }; -fn formatAir(data: FormatAirData, _: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { - data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness); +fn formatAir(data: FormatAirData, w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); + // not acceptable implementation: + // data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness); + _ = data; + _ = w; + @panic("TODO: unimplemented"); } fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { return .{ .data = .{ .func = func, .inst = inst } }; @@ -1004,7 +1011,8 @@ fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { const FormatTrackingData = struct { func: *Func, }; -fn formatTracking(data: FormatTrackingData, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { +fn formatTracking(data: FormatTrackingData, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); var it = data.func.inst_tracking.iterator(); while (it.next()) |entry| try bw.print("\n%{d} = {f}", .{ entry.key_ptr.*, entry.value_ptr.* }); } diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig index aac134a80c..4653b6d73b 100644 --- a/src/arch/riscv64/Mir.zig +++ b/src/arch/riscv64/Mir.zig @@ -92,7 +92,7 @@ pub const Inst = struct { }, }; - pub fn format(inst: Inst, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { + pub fn format(inst: Inst, bw: *std.io.Writer, comptime fmt: []const u8) !void { assert(fmt.len == 0); try bw.print("Tag: {s}, Data: {s}", .{ @tagName(inst.tag), @tagName(inst.data) }); } diff --git a/src/arch/riscv64/bits.zig b/src/arch/riscv64/bits.zig index 86ff6473d7..9ca4808f89 100644 --- a/src/arch/riscv64/bits.zig +++ b/src/arch/riscv64/bits.zig @@ -2,6 +2,7 @@ const std = @import("std"); const assert = std.debug.assert; const testing = std.testing; const Target = std.Target; +const Writer = std.io.Writer; const Zcu = @import("../../Zcu.zig"); const Mir = @import("Mir.zig"); @@ -256,7 +257,8 @@ pub const FrameIndex = enum(u32) { return @intFromEnum(fi) < named_count; } - pub fn format(fi: FrameIndex, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(fi: FrameIndex, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); try bw.writeAll("FrameIndex"); if (fi.isNamed()) try bw.print(".{s}", .{@tagName(fi)}) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 027a709e2c..9df6255e52 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -5,6 +5,7 @@ const assert = std.debug.assert; const testing = std.testing; const mem = std.mem; const log = std.log.scoped(.codegen); +const Writer = std.io.Writer; const CodeGen = @This(); const codegen = @import("../../codegen.zig"); diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index e0795e746d..77d1057d56 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -4,6 +4,7 @@ const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const leb = std.leb; +const Writer = std.io.Writer; const Wasm = link.File.Wasm; const Mir = @import("Mir.zig"); @@ -15,7 +16,7 @@ const codegen = @import("../../codegen.zig"); mir: Mir, wasm: *Wasm, /// The binary representation of this module is written here. -bw: *std.io.BufferedWriter, +bw: *Writer, pub const Error = error{ OutOfMemory, @@ -893,12 +894,12 @@ pub fn lowerToCode(emit: *Emit) Error!void { } /// Asserts 20 unused capacity. -fn encodeMemArg(bw: *std.io.BufferedWriter, mem_arg: Mir.MemArg) std.io.Writer.Error!void { +fn encodeMemArg(bw: *Writer, mem_arg: Mir.MemArg) Writer.Error!void { try bw.writeLeb128(Wasm.Alignment.fromNonzeroByteUnits(mem_arg.alignment).toLog2Units()); try bw.writeLeb128(mem_arg.offset); } -fn uavRefObj(wasm: *Wasm, bw: *std.io.BufferedWriter, value: InternPool.Index, offset: i32, is_wasm32: bool) std.io.Writer.Error!void { +fn uavRefObj(wasm: *Wasm, bw: *Writer, value: InternPool.Index, offset: i32, is_wasm32: bool) Writer.Error!void { const comp = wasm.base.comp; const gpa = comp.gpa; const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; @@ -914,7 +915,7 @@ fn uavRefObj(wasm: *Wasm, bw: *std.io.BufferedWriter, value: InternPool.Index, o try bw.splatByteAll(0, if (is_wasm32) 5 else 10); } -fn uavRefExe(wasm: *Wasm, bw: *std.io.BufferedWriter, value: InternPool.Index, offset: i32, is_wasm32: bool) !void { +fn uavRefExe(wasm: *Wasm, bw: *Writer, value: InternPool.Index, offset: i32, is_wasm32: bool) !void { const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; try bw.writeByte(@intFromEnum(opcode)); @@ -922,7 +923,7 @@ fn uavRefExe(wasm: *Wasm, bw: *std.io.BufferedWriter, value: InternPool.Index, o try bw.writeLeb128(@as(u32, @intCast(@as(i64, addr) + offset))); } -fn navRefOff(wasm: *Wasm, bw: *std.io.BufferedWriter, data: Mir.NavRefOff, is_wasm32: bool) !void { +fn navRefOff(wasm: *Wasm, bw: *Writer, data: Mir.NavRefOff, is_wasm32: bool) !void { const comp = wasm.base.comp; const zcu = comp.zcu.?; const ip = &zcu.intern_pool; @@ -947,6 +948,6 @@ fn navRefOff(wasm: *Wasm, bw: *std.io.BufferedWriter, data: Mir.NavRefOff, is_wa } } -fn appendOutputFunctionIndex(bw: *std.io.BufferedWriter, i: Wasm.OutputFunctionIndex) std.io.Writer.Error!void { +fn appendOutputFunctionIndex(bw: *Writer, i: Wasm.OutputFunctionIndex) Writer.Error!void { return bw.writeLeb128(@intFromEnum(i)); } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 63e7436058..1f67306598 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -6,6 +6,7 @@ const log = std.log.scoped(.codegen); const tracking_log = std.log.scoped(.tracking); const verbose_tracking_log = std.log.scoped(.verbose_tracking); const wip_mir_log = std.log.scoped(.wip_mir); +const Writer = std.io.Writer; const Air = @import("../../Air.zig"); const Allocator = std.mem.Allocator; @@ -524,7 +525,7 @@ pub const MCValue = union(enum) { }; } - pub fn format(mcv: MCValue, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(mcv: MCValue, bw: *Writer, comptime _: []const u8) Writer.Error!void { switch (mcv) { .none, .unreach, .dead, .undef => try bw.print("({s})", .{@tagName(mcv)}), .immediate => |pl| try bw.print("0x{x}", .{pl}), @@ -811,7 +812,7 @@ const InstTracking = struct { } } - pub fn format(tracking: InstTracking, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(tracking: InstTracking, bw: *Writer, comptime _: []const u8) Writer.Error!void { if (!std.meta.eql(tracking.long, tracking.short)) try bw.print("|{f}| ", .{tracking.long}); try bw.print("{f}", .{tracking.short}); } @@ -1087,7 +1088,7 @@ const FormatNavData = struct { ip: *const InternPool, nav_index: InternPool.Nav.Index, }; -fn formatNav(data: FormatNavData, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { +fn formatNav(data: FormatNavData, bw: *Writer, comptime _: []const u8) Writer.Error!void { try bw.print("{f}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)}); } fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) { @@ -1101,8 +1102,13 @@ const FormatAirData = struct { self: *CodeGen, inst: Air.Inst.Index, }; -fn formatAir(data: FormatAirData, _: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { - data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness); +fn formatAir(data: FormatAirData, w: *std.io.Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); + // not acceptable implementation: + //data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness); + _ = data; + _ = w; + @panic("TODO: unimplemented"); } fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { return .{ .data = .{ .self = self, .inst = inst } }; @@ -1112,7 +1118,7 @@ const FormatWipMirData = struct { self: *CodeGen, inst: Mir.Inst.Index, }; -fn formatWipMir(data: FormatWipMirData, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { +fn formatWipMir(data: FormatWipMirData, bw: *Writer, comptime _: []const u8) Writer.Error!void { var lower: Lower = .{ .target = data.self.target, .allocator = data.self.gpa, @@ -1208,7 +1214,8 @@ fn fmtWipMir(self: *CodeGen, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMi const FormatTrackingData = struct { self: *CodeGen, }; -fn formatTracking(data: FormatTrackingData, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { +fn formatTracking(data: FormatTrackingData, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); var it = data.self.inst_tracking.iterator(); while (it.next()) |entry| try bw.print("\n{f} = {f}", .{ entry.key_ptr.*, entry.value_ptr.* }); } diff --git a/src/arch/x86_64/Disassembler.zig b/src/arch/x86_64/Disassembler.zig index 856e3e850d..04f4a3e8b9 100644 --- a/src/arch/x86_64/Disassembler.zig +++ b/src/arch/x86_64/Disassembler.zig @@ -372,8 +372,7 @@ fn parseGpRegister(low_enc: u3, is_extended: bool, rex: Rex, bit_size: u64) Regi } fn parseImm(dis: *Disassembler, kind: Encoding.Op) !Immediate { - var br: std.io.Reader = undefined; - br.initFixed(dis.code[dis.pos..]); + var br: std.io.Reader = .fixed(dis.code[dis.pos..]); defer dis.pos += br.seek; return switch (kind) { .imm8s, .rel8 => .s(try br.takeInt(i8, .little)), @@ -388,8 +387,7 @@ fn parseImm(dis: *Disassembler, kind: Encoding.Op) !Immediate { } fn parseOffset(dis: *Disassembler) !u64 { - var br: std.io.Reader = undefined; - br.initFixed(dis.code[dis.pos..]); + var br: std.io.Reader = .fixed(dis.code[dis.pos..]); defer dis.pos += br.seek; return br.takeInt(u64, .little); } diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index 07567f2fbd..9cb78972cc 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/src/arch/x86_64/Encoding.zig @@ -3,6 +3,7 @@ const Encoding = @This(); const std = @import("std"); const assert = std.debug.assert; const math = std.math; +const Writer = std.io.Writer; const bits = @import("bits.zig"); const encoder = @import("encoder.zig"); @@ -158,8 +159,8 @@ pub fn modRmExt(encoding: Encoding) u3 { }; } -pub fn format(encoding: Encoding, bw: *std.io.BufferedWriter, comptime fmt: []const u8) !void { - _ = fmt; +pub fn format(encoding: Encoding, bw: *Writer, comptime fmt: []const u8) !void { + comptime assert(fmt.len == 0); var opc = encoding.opcode(); if (encoding.data.mode.isVex()) { @@ -1016,8 +1017,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op @memcpy(inst.ops[0..ops.len], ops); var buf: [15]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buf); + var bw: Writer = .fixed(&buf); inst.encode(&bw, .{ .allow_frame_locs = true, .allow_symbols = true, diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 0c913836cd..d0063c13f2 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -6,6 +6,8 @@ const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; const InternPool = @import("../../InternPool.zig"); const link = @import("../../link.zig"); +const Writer = std.io.Writer; + const Mir = @import("Mir.zig"); /// EFLAGS condition codes @@ -728,7 +730,8 @@ pub const FrameIndex = enum(u32) { return @intFromEnum(fi) < named_count; } - pub fn format(fi: FrameIndex, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(fi: FrameIndex, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); try bw.writeAll("FrameIndex"); if (fi.isNamed()) try bw.print(".{s}", .{@tagName(fi)}) @@ -835,7 +838,8 @@ pub const Memory = struct { }; } - pub fn format(s: Size, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(s: Size, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); if (s == .none) return; try bw.writeAll(@tagName(s)); switch (s) { diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index 652e6867e4..06606bf302 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -3,6 +3,7 @@ const assert = std.debug.assert; const log = std.log.scoped(.x86_64_encoder); const math = std.math; const testing = std.testing; +const Writer = std.io.Writer; const bits = @import("bits.zig"); const Encoding = @import("Encoding.zig"); @@ -226,7 +227,7 @@ pub const Instruction = struct { }; } - fn format(op: Operand, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) !void { + fn format(op: Operand, bw: *Writer, comptime unused_format_string: []const u8) !void { _ = op; _ = bw; _ = unused_format_string; @@ -238,7 +239,7 @@ pub const Instruction = struct { enc_op: Encoding.Op, }; - fn fmtContext(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) std.io.Writer.Error!void { + fn fmtContext(ctx: FormatContext, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { _ = unused_format_string; const op = ctx.op; const enc_op = ctx.enc_op; @@ -360,7 +361,7 @@ pub const Instruction = struct { return inst; } - pub fn format(inst: Instruction, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) std.io.Writer.Error!void { + pub fn format(inst: Instruction, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { _ = unused_format_string; switch (inst.prefix) { .none, .directive => {}, @@ -374,7 +375,7 @@ pub const Instruction = struct { } } - pub fn encode(inst: Instruction, bw: *std.io.BufferedWriter, comptime opts: Options) !void { + pub fn encode(inst: Instruction, bw: *Writer, comptime opts: Options) !void { assert(inst.prefix != .directive); const encoder: Encoder(opts) = .{ .bw = bw }; const enc = inst.encoding; @@ -784,7 +785,7 @@ pub const Options = struct { allow_frame_locs: bool = false, allow_symbols: bool fn Encoder(comptime opts: Options) type { return struct { - bw: *std.io.BufferedWriter, + bw: *Writer, const Self = @This(); pub const options = opts; @@ -2198,7 +2199,7 @@ const Assembler = struct { }; } - pub fn assemble(as: *Assembler, bw: *std.io.BufferedWriter) !void { + pub fn assemble(as: *Assembler, bw: *Writer) !void { while (try as.next()) |parsed_inst| { const inst: Instruction = try .new(.none, parsed_inst.mnemonic, &parsed_inst.ops); try inst.encode(bw, .{}); diff --git a/src/codegen.zig b/src/codegen.zig index 937dd960a1..6618334d44 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -8,6 +8,7 @@ const mem = std.mem; const math = std.math; const target_util = @import("target.zig"); const trace = @import("tracy.zig").trace; +const Writer = std.io.Writer; const Air = @import("Air.zig"); const Allocator = mem.Allocator; @@ -326,7 +327,7 @@ pub fn generateSymbolInner( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, val: Value, - bw: *std.io.BufferedWriter, + bw: *Writer, reloc_parent: link.File.RelocInfo.Parent, ) GenerateSymbolError!void { const zcu = pt.zcu; @@ -707,7 +708,7 @@ fn lowerPtr( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, ptr_val: InternPool.Index, - bw: *std.io.BufferedWriter, + bw: *Writer, reloc_parent: link.File.RelocInfo.Parent, prev_offset: u64, ) GenerateSymbolError!void { @@ -760,7 +761,7 @@ fn lowerUavRef( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, uav: InternPool.Key.Ptr.BaseAddr.Uav, - bw: *std.io.BufferedWriter, + bw: *Writer, reloc_parent: link.File.RelocInfo.Parent, offset: u64, ) GenerateSymbolError!void { @@ -814,7 +815,7 @@ fn lowerNavRef( lf: *link.File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, - bw: *std.io.BufferedWriter, + bw: *Writer, reloc_parent: link.File.RelocInfo.Parent, offset: u64, ) GenerateSymbolError!void { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 019508aa85..b5511e0074 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -4,6 +4,7 @@ const assert = std.debug.assert; const mem = std.mem; const log = std.log.scoped(.c); const Allocator = mem.Allocator; +const Writer = std.io.Writer; const dev = @import("../dev.zig"); const link = @import("../link.zig"); @@ -69,7 +70,7 @@ pub const Mir = struct { } }; -pub const Error = std.io.Writer.Error || std.mem.Allocator.Error || error{AnalysisFail}; +pub const Error = Writer.Error || std.mem.Allocator.Error || error{AnalysisFail}; pub const CType = @import("c/Type.zig"); @@ -344,9 +345,9 @@ fn isReservedIdent(ident: []const u8) bool { fn formatIdent( ident: []const u8, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime fmt_str: []const u8, -) std.io.Writer.Error!void { +) Writer.Error!void { const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident. if (solo and isReservedIdent(ident)) { try bw.writeAll("zig_e_"); @@ -374,9 +375,9 @@ const CTypePoolStringFormatData = struct { }; fn formatCTypePoolString( data: CTypePoolStringFormatData, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime fmt_str: []const u8, -) std.io.Writer.Error!void { +) Writer.Error!void { if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice| try formatIdent(slice, bw, fmt_str) else @@ -504,7 +505,7 @@ pub const Function = struct { return result; } - fn writeCValue(f: *Function, bw: *std.io.BufferedWriter, c_value: CValue, location: ValueRenderLocation) !void { + fn writeCValue(f: *Function, bw: *Writer, c_value: CValue, location: ValueRenderLocation) !void { switch (c_value) { .none => unreachable, .new_local, .local => |i| try bw.print("t{d}", .{i}), @@ -517,7 +518,7 @@ pub const Function = struct { } } - fn writeCValueDeref(f: *Function, bw: *std.io.BufferedWriter, c_value: CValue) !void { + fn writeCValueDeref(f: *Function, bw: *Writer, c_value: CValue) !void { switch (c_value) { .none => unreachable, .new_local, .local, .constant => { @@ -538,7 +539,7 @@ pub const Function = struct { fn writeCValueMember( f: *Function, - bw: *std.io.BufferedWriter, + bw: *Writer, c_value: CValue, member: CValue, ) Error!void { @@ -552,7 +553,7 @@ pub const Function = struct { } } - fn writeCValueDerefMember(f: *Function, bw: *std.io.BufferedWriter, c_value: CValue, member: CValue) !void { + fn writeCValueDerefMember(f: *Function, bw: *Writer, c_value: CValue, member: CValue) !void { switch (c_value) { .new_local, .local, .arg, .arg_array => { try f.writeCValue(bw, c_value, .Other); @@ -584,15 +585,15 @@ pub const Function = struct { return f.object.dg.byteSize(ctype); } - fn renderType(f: *Function, bw: *std.io.BufferedWriter, ctype: Type) !void { + fn renderType(f: *Function, bw: *Writer, ctype: Type) !void { return f.object.dg.renderType(bw, ctype); } - fn renderCType(f: *Function, bw: *std.io.BufferedWriter, ctype: CType) !void { + fn renderCType(f: *Function, bw: *Writer, ctype: CType) !void { return f.object.dg.renderCType(bw, ctype); } - fn renderIntCast(f: *Function, bw: *std.io.BufferedWriter, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void { + fn renderIntCast(f: *Function, bw: *Writer, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void { return f.object.dg.renderIntCast(bw, dest_ty, .{ .c_value = .{ .f = f, .value = src, .v = v } }, src_ty, location); } @@ -757,7 +758,7 @@ pub const DeclGen = struct { fn renderUav( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, uav: InternPool.Key.Ptr.BaseAddr.Uav, location: ValueRenderLocation, ) Error!void { @@ -819,7 +820,7 @@ pub const DeclGen = struct { fn renderNav( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, nav_index: InternPool.Nav.Index, location: ValueRenderLocation, ) Error!void { @@ -868,7 +869,7 @@ pub const DeclGen = struct { fn renderPointer( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, derivation: Value.PointerDeriveStep, location: ValueRenderLocation, ) Error!void { @@ -972,13 +973,13 @@ pub const DeclGen = struct { } } - fn renderErrorName(dg: *DeclGen, bw: *std.io.BufferedWriter, err_name: InternPool.NullTerminatedString) !void { + fn renderErrorName(dg: *DeclGen, bw: *Writer, err_name: InternPool.NullTerminatedString) !void { try bw.print("zig_error_{f}", .{fmtIdent(err_name.toSlice(&dg.pt.zcu.intern_pool))}); } fn renderValue( dg: *DeclGen, - writer: *std.io.BufferedWriter, + writer: *Writer, val: Value, location: ValueRenderLocation, ) Error!void { @@ -1587,7 +1588,7 @@ pub const DeclGen = struct { fn renderUndefValue( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, ty: Type, location: ValueRenderLocation, ) Error!void { @@ -1890,7 +1891,7 @@ pub const DeclGen = struct { fn renderFunctionSignature( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, fn_val: Value, fn_align: InternPool.Alignment, kind: CType.Kind, @@ -2011,11 +2012,11 @@ pub const DeclGen = struct { /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | /// | `renderType` | "uint8_t *" | "uint8_t *[10]" | /// - fn renderType(dg: *DeclGen, bw: *std.io.BufferedWriter, t: Type) Error!void { + fn renderType(dg: *DeclGen, bw: *Writer, t: Type) Error!void { try dg.renderCType(bw, try dg.ctypeFromType(t, .complete)); } - fn renderCType(dg: *DeclGen, bw: *std.io.BufferedWriter, ctype: CType) Error!void { + fn renderCType(dg: *DeclGen, bw: *Writer, ctype: CType) Error!void { _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.pt.zcu, bw, ctype, .suffix, .{}); try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.pt.zcu, bw, ctype, .suffix, .{}); } @@ -2030,7 +2031,7 @@ pub const DeclGen = struct { value: Value, }, - pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, bw: *std.io.BufferedWriter, location: ValueRenderLocation) !void { + pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, bw: *Writer, location: ValueRenderLocation) !void { switch (self.*) { .c_value => |v| { try v.f.writeCValue(bw, v.value, location); @@ -2076,7 +2077,7 @@ pub const DeclGen = struct { /// | > 64 bit integer | > 64 bit integer | zig_make_(zig_hi_(src), zig_lo_(src)) fn renderIntCast( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, dest_ty: Type, context: IntCastContext, src_ty: Type, @@ -2160,7 +2161,7 @@ pub const DeclGen = struct { /// fn renderTypeAndName( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, ty: Type, name: CValue, qualifiers: CQualifiers, @@ -2181,7 +2182,7 @@ pub const DeclGen = struct { fn renderCTypeAndName( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, ctype: CType, name: CValue, qualifiers: CQualifiers, @@ -2201,7 +2202,7 @@ pub const DeclGen = struct { try renderTypeSuffix(dg.pass, &dg.ctype_pool, zcu, bw, ctype, .suffix, .{}); } - fn writeName(dg: *DeclGen, bw: *std.io.BufferedWriter, c_value: CValue) !void { + fn writeName(dg: *DeclGen, bw: *Writer, c_value: CValue) !void { switch (c_value) { .new_local, .local => |i| try bw.print("t{d}", .{i}), .constant => |uav| try renderUavName(bw, uav), @@ -2211,7 +2212,7 @@ pub const DeclGen = struct { } } - fn writeCValue(dg: *DeclGen, bw: *std.io.BufferedWriter, c_value: CValue) Error!void { + fn writeCValue(dg: *DeclGen, bw: *Writer, c_value: CValue) Error!void { switch (c_value) { .none, .new_local, .local, .local_ref => unreachable, .constant => |uav| try renderUavName(bw, uav), @@ -2234,7 +2235,7 @@ pub const DeclGen = struct { } } - fn writeCValueDeref(dg: *DeclGen, bw: *std.io.BufferedWriter, c_value: CValue) !void { + fn writeCValueDeref(dg: *DeclGen, bw: *Writer, c_value: CValue) !void { switch (c_value) { .none, .new_local, @@ -2263,7 +2264,7 @@ pub const DeclGen = struct { fn writeCValueMember( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, c_value: CValue, member: CValue, ) Error!void { @@ -2274,7 +2275,7 @@ pub const DeclGen = struct { fn writeCValueDerefMember( dg: *DeclGen, - bw: *std.io.BufferedWriter, + bw: *Writer, c_value: CValue, member: CValue, ) !void { @@ -2341,7 +2342,7 @@ pub const DeclGen = struct { try fwd.writeAll(";\n"); } - fn renderNavName(dg: *DeclGen, bw: *std.io.BufferedWriter, nav_index: InternPool.Nav.Index) !void { + fn renderNavName(dg: *DeclGen, bw: *Writer, nav_index: InternPool.Nav.Index) !void { const zcu = dg.pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); @@ -2360,15 +2361,15 @@ pub const DeclGen = struct { } } - fn renderUavName(bw: *std.io.BufferedWriter, uav: Value) !void { + fn renderUavName(bw: *Writer, uav: Value) !void { try bw.print("__anon_{d}", .{@intFromEnum(uav.toIntern())}); } - fn renderTypeForBuiltinFnName(dg: *DeclGen, bw: *std.io.BufferedWriter, ty: Type) !void { + fn renderTypeForBuiltinFnName(dg: *DeclGen, bw: *Writer, ty: Type) !void { try dg.renderCTypeForBuiltinFnName(bw, try dg.ctypeFromType(ty, .complete)); } - fn renderCTypeForBuiltinFnName(dg: *DeclGen, bw: *std.io.BufferedWriter, ctype: CType) !void { + fn renderCTypeForBuiltinFnName(dg: *DeclGen, bw: *Writer, ctype: CType) !void { switch (ctype.info(&dg.ctype_pool)) { else => |ctype_info| try bw.print("{c}{d}", .{ if (ctype.isBool()) @@ -2387,7 +2388,7 @@ pub const DeclGen = struct { } } - fn renderBuiltinInfo(dg: *DeclGen, bw: *std.io.BufferedWriter, ty: Type, info: BuiltinInfo) !void { + fn renderBuiltinInfo(dg: *DeclGen, bw: *Writer, ty: Type, info: BuiltinInfo) !void { const ctype = try dg.ctypeFromType(ty, .complete); const is_big = ctype.info(&dg.ctype_pool) == .array; switch (info) { @@ -2436,9 +2437,9 @@ const RenderCTypeTrailing = enum { pub fn format( self: @This(), - bw: *std.io.BufferedWriter, + bw: *Writer, comptime fmt: []const u8, - ) std.io.Writer.Error!void { + ) Writer.Error!void { if (fmt.len != 0) @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@This()) ++ "'"); switch (self) { @@ -2447,12 +2448,12 @@ const RenderCTypeTrailing = enum { } } }; -fn renderAlignedTypeName(bw: *std.io.BufferedWriter, ctype: CType) !void { +fn renderAlignedTypeName(bw: *Writer, ctype: CType) !void { try bw.print("anon__aligned_{d}", .{@intFromEnum(ctype.index)}); } fn renderFwdDeclTypeName( zcu: *Zcu, - bw: *std.io.BufferedWriter, + bw: *Writer, ctype: CType, fwd_decl: CType.Info.FwdDecl, attributes: []const u8, @@ -2471,11 +2472,11 @@ fn renderTypePrefix( pass: DeclGen.Pass, ctype_pool: *const CType.Pool, zcu: *Zcu, - bw: *std.io.BufferedWriter, + bw: *Writer, ctype: CType, parent_fix: CTypeFix, qualifiers: CQualifiers, -) std.io.Writer.Error!RenderCTypeTrailing { +) Writer.Error!RenderCTypeTrailing { var trailing = RenderCTypeTrailing.maybe_space; switch (ctype.info(ctype_pool)) { .basic => |basic_info| try bw.writeAll(@tagName(basic_info)), @@ -2588,11 +2589,11 @@ fn renderTypeSuffix( pass: DeclGen.Pass, ctype_pool: *const CType.Pool, zcu: *Zcu, - bw: *std.io.BufferedWriter, + bw: *Writer, ctype: CType, parent_fix: CTypeFix, qualifiers: CQualifiers, -) std.io.Writer.Error!void { +) Writer.Error!void { switch (ctype.info(ctype_pool)) { .basic, .aligned, .fwd_decl, .aggregate => {}, .pointer => |pointer_info| try renderTypeSuffix( @@ -2644,7 +2645,7 @@ fn renderTypeSuffix( } fn renderFields( zcu: *Zcu, - bw: *std.io.BufferedWriter, + bw: *Writer, ctype_pool: *const CType.Pool, aggregate_info: CType.Info.Aggregate, indent: usize, @@ -2686,7 +2687,7 @@ fn renderFields( pub fn genTypeDecl( zcu: *Zcu, - bw: *std.io.BufferedWriter, + bw: *Writer, global_ctype_pool: *const CType.Pool, global_ctype: CType, pass: DeclGen.Pass, @@ -2766,7 +2767,7 @@ pub fn genTypeDecl( } } -pub fn genGlobalAsm(zcu: *Zcu, bw: *std.io.BufferedWriter) !void { +pub fn genGlobalAsm(zcu: *Zcu, bw: *Writer) !void { for (zcu.global_assembly.values()) |asm_source| { try bw.print("__asm({fs});\n", .{fmtStringLiteral(asm_source, null)}); } @@ -5247,7 +5248,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal return local; } -fn airTrap(f: *Function, bw: *std.io.BufferedWriter) !void { +fn airTrap(f: *Function, bw: *Writer) !void { // Not even allowed to call trap in a naked function. if (f.object.dg.is_naked_fn) return; try bw.writeAll("zig_trap();\n"); @@ -7052,7 +7053,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa return .none; } -fn writeSliceOrPtr(f: *Function, bw: *std.io.BufferedWriter, ptr: CValue, ptr_ty: Type) !void { +fn writeSliceOrPtr(f: *Function, bw: *Writer, ptr: CValue, ptr_ty: Type) !void { const pt = f.object.dg.pt; const zcu = pt.zcu; if (ptr_ty.isSlice(zcu)) { @@ -7980,7 +7981,7 @@ fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { }; } -fn writeMemoryOrder(bw: *std.io.BufferedWriter, order: std.builtin.AtomicOrder) !void { +fn writeMemoryOrder(bw: *Writer, order: std.builtin.AtomicOrder) !void { return bw.writeAll(toMemoryOrder(order)); } @@ -8125,7 +8126,7 @@ const StringLiteral = struct { len: usize, cur_len: usize, start_count: usize, - bw: *std.io.BufferedWriter, + bw: *Writer, // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal, // regardless of the length of the string literal initializing it. Array initializer syntax is @@ -8138,7 +8139,7 @@ const StringLiteral = struct { const max_char_len = 4; const max_literal_len = @min(16380 - max_char_len, 4095); - fn init(bw: *std.io.BufferedWriter, len: usize) StringLiteral { + fn init(bw: *Writer, len: usize) StringLiteral { return .{ .cur_len = 0, .len = len, @@ -8147,7 +8148,7 @@ const StringLiteral = struct { }; } - pub fn start(sl: *StringLiteral) std.io.Writer.Error!void { + pub fn start(sl: *StringLiteral) Writer.Error!void { if (sl.len <= max_string_initializer_len) { try sl.bw.writeByte('\"'); } else { @@ -8155,7 +8156,7 @@ const StringLiteral = struct { } } - pub fn end(sl: *StringLiteral) std.io.Writer.Error!void { + pub fn end(sl: *StringLiteral) Writer.Error!void { if (sl.len <= max_string_initializer_len) { try sl.bw.writeByte('\"'); } else { @@ -8163,7 +8164,7 @@ const StringLiteral = struct { } } - fn writeStringLiteralChar(sl: *StringLiteral, c: u8) std.io.Writer.Error!void { + fn writeStringLiteralChar(sl: *StringLiteral, c: u8) Writer.Error!void { switch (c) { 7 => try sl.bw.writeAll("\\a"), 8 => try sl.bw.writeAll("\\b"), @@ -8180,7 +8181,7 @@ const StringLiteral = struct { } } - pub fn writeChar(sl: *StringLiteral, c: u8) std.io.Writer.Error!void { + pub fn writeChar(sl: *StringLiteral, c: u8) Writer.Error!void { if (sl.len <= max_string_initializer_len) { if (sl.cur_len == 0 and sl.bw.count - sl.start_count > 1) try sl.bw.writeAll("\"\""); @@ -8202,9 +8203,9 @@ const StringLiteral = struct { const FormatStringContext = struct { str: []const u8, sentinel: ?u8 }; fn formatStringLiteral( data: FormatStringContext, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime fmt: []const u8, -) std.io.Writer.Error!void { +) Writer.Error!void { if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt); var literal: StringLiteral = .init(bw, data.str.len + @intFromBool(data.sentinel != null)); @@ -8233,9 +8234,9 @@ const FormatIntLiteralContext = struct { }; fn formatIntLiteral( data: FormatIntLiteralContext, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime fmt: []const u8, -) std.io.Writer.Error!void { +) Writer.Error!void { const pt = data.dg.pt; const zcu = pt.zcu; const target = &data.dg.mod.resolved_target.result; @@ -8423,7 +8424,7 @@ const Materialize = struct { } }; } - pub fn mat(self: Materialize, f: *Function, bw: *std.io.BufferedWriter) !void { + pub fn mat(self: Materialize, f: *Function, bw: *Writer) !void { try f.writeCValue(bw, self.local, .Other); } @@ -8435,27 +8436,27 @@ const Materialize = struct { const Assignment = struct { ctype: CType, - pub fn start(f: *Function, bw: *std.io.BufferedWriter, ctype: CType) !Assignment { + pub fn start(f: *Function, bw: *Writer, ctype: CType) !Assignment { const self: Assignment = .{ .ctype = ctype }; try self.restart(f, bw); return self; } - pub fn restart(self: Assignment, f: *Function, bw: *std.io.BufferedWriter) !void { + pub fn restart(self: Assignment, f: *Function, bw: *Writer) !void { switch (self.strategy(f)) { .assign => {}, .memcpy => try bw.writeAll("memcpy("), } } - pub fn assign(self: Assignment, f: *Function, bw: *std.io.BufferedWriter) !void { + pub fn assign(self: Assignment, f: *Function, bw: *Writer) !void { switch (self.strategy(f)) { .assign => try bw.writeAll(" = "), .memcpy => try bw.writeAll(", "), } } - pub fn end(self: Assignment, f: *Function, bw: *std.io.BufferedWriter) !void { + pub fn end(self: Assignment, f: *Function, bw: *Writer) !void { switch (self.strategy(f)) { .assign => {}, .memcpy => { @@ -8479,7 +8480,7 @@ const Assignment = struct { const Vectorize = struct { index: CValue = .none, - pub fn start(f: *Function, inst: Air.Inst.Index, writer: *std.io.BufferedWriter, ty: Type) !Vectorize { + pub fn start(f: *Function, inst: Air.Inst.Index, writer: *Writer, ty: Type) !Vectorize { const pt = f.object.dg.pt; const zcu = pt.zcu; return if (ty.zigTypeTag(zcu) == .vector) index: { @@ -8499,7 +8500,7 @@ const Vectorize = struct { } else .{}; } - pub fn elem(self: Vectorize, f: *Function, bw: *std.io.BufferedWriter) !void { + pub fn elem(self: Vectorize, f: *Function, bw: *Writer) !void { if (self.index != .none) { try bw.writeByte('['); try f.writeCValue(bw, self.index, .Other); @@ -8507,7 +8508,7 @@ const Vectorize = struct { } } - pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, bw: *std.io.BufferedWriter) !void { + pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, bw: *Writer) !void { if (self.index != .none) { try f.object.outdent(); try bw.writeByte('}'); diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig index 556ba07fad..594912bd30 100644 --- a/src/codegen/c/Type.zig +++ b/src/codegen/c/Type.zig @@ -209,7 +209,7 @@ pub fn getStandardDefineAbbrev(ctype: CType) ?[]const u8 { }; } -pub fn renderLiteralPrefix(ctype: CType, bw: *std.io.BufferedWriter, kind: Kind, pool: *const Pool) std.io.Writer.Error!void { +pub fn renderLiteralPrefix(ctype: CType, bw: *Writer, kind: Kind, pool: *const Pool) Writer.Error!void { switch (ctype.info(pool)) { .basic => |basic_info| switch (basic_info) { .void => unreachable, @@ -270,7 +270,7 @@ pub fn renderLiteralPrefix(ctype: CType, bw: *std.io.BufferedWriter, kind: Kind, } } -pub fn renderLiteralSuffix(ctype: CType, bw: *std.io.BufferedWriter, pool: *const Pool) std.io.Writer.Error!void { +pub fn renderLiteralSuffix(ctype: CType, bw: *Writer, pool: *const Pool) Writer.Error!void { switch (ctype.info(pool)) { .basic => |basic_info| switch (basic_info) { .void => unreachable, @@ -940,10 +940,10 @@ pub const Pool = struct { const FormatData = struct { string: String, pool: *const Pool }; fn format( data: FormatData, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime fmt_str: []const u8, - ) std.io.Writer.Error!void { - if (fmt_str.len > 0) @compileError("invalid format string '" ++ fmt_str ++ "'"); + ) Writer.Error!void { + comptime assert(fmt_str.len == 0); if (data.string.toSlice(data.pool)) |slice| try bw.writeAll(slice) else @@ -3280,10 +3280,12 @@ pub const AlignAs = packed struct { } }; +const std = @import("std"); const assert = std.debug.assert; +const Writer = std.io.Writer; + const CType = @This(); const InternPool = @import("../../InternPool.zig"); const Module = @import("../../Package/Module.zig"); -const std = @import("std"); const Type = @import("../../Type.zig"); const Zcu = @import("../../Zcu.zig"); diff --git a/src/codegen/spirv/spec.zig b/src/codegen/spirv/spec.zig index 344e6cd312..857d5bb03a 100644 --- a/src/codegen/spirv/spec.zig +++ b/src/codegen/spirv/spec.zig @@ -18,7 +18,8 @@ pub const IdResult = enum(Word) { none, _, - pub fn format(self: IdResult, bw: *std.io.BufferedWriter, comptime _: []const u8) std.io.Writer.Error!void { + pub fn format(self: IdResult, bw: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime std.debug.assert(fmt.len == 0); switch (self) { .none => try bw.writeAll("(none)"), else => try bw.print("%{}", .{@intFromEnum(self)}), diff --git a/src/fmt.zig b/src/fmt.zig index d582a8df3b..661397aebd 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -1,3 +1,12 @@ +const std = @import("std"); +const mem = std.mem; +const fs = std.fs; +const process = std.process; +const Allocator = std.mem.Allocator; +const Color = std.zig.Color; +const fatal = std.process.fatal; +const File = std.fs.File; + const usage_fmt = \\Usage: zig fmt [file]... \\ @@ -27,7 +36,7 @@ const Fmt = struct { gpa: Allocator, arena: Allocator, out_buffer: std.ArrayListUnmanaged(u8), - stdout: *std.io.BufferedWriter, + stdout_writer: *File.Writer, const SeenMap = std.AutoHashMap(fs.File.INode, void); }; @@ -49,7 +58,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - try std.fs.File.stdout().writeAll(usage_fmt); + try File.stdout().writeAll(usage_fmt); return process.cleanExit(); } else if (mem.eql(u8, arg, "--color")) { if (i + 1 >= args.len) { @@ -133,10 +142,9 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { try std.zig.printAstErrorsToStderr(gpa, tree, "", color); process.exit(2); } - var aw: std.io.AllocatingWriter = undefined; - aw.init(gpa); + var aw: std.io.AllocatingWriter = .init(gpa); defer aw.deinit(); - try tree.render(gpa, &aw.buffered_writer, .{}); + try tree.render(gpa, &aw.interface, .{}); const formatted = aw.getWritten(); if (check_flag) { @@ -144,7 +152,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { process.exit(code); } - return std.fs.File.stdout().writeAll(formatted); + return File.stdout().writeAll(formatted); } if (input_files.items.len == 0) { @@ -152,7 +160,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { } var stdout_buffer: [4096]u8 = undefined; - var stdout: std.io.BufferedWriter = std.fs.File.stdout().writer().buffered(&stdout_buffer); + var stdout_writer = File.stdout().writer(&stdout_buffer); var fmt: Fmt = .{ .gpa = gpa, @@ -163,7 +171,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { .force_zon = force_zon, .color = color, .out_buffer = .empty, - .stdout = &stdout, + .stdout_writer = &stdout_writer, }; defer fmt.seen.deinit(); defer fmt.out_buffer.deinit(gpa); @@ -190,6 +198,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { if (fmt.any_error) { process.exit(1); } + try fmt.stdout_writer.flush(); } fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) anyerror!void { @@ -336,7 +345,7 @@ fn fmtPathFile( return; if (check_mode) { - try fmt.stdout.print("{s}\n", .{file_path}); + try fmt.stdout_writer.interface.print("{s}\n", .{file_path}); fmt.any_error = true; } else { var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode }); @@ -344,18 +353,10 @@ fn fmtPathFile( try af.file.writeAll(fmt.out_buffer.items); try af.finish(); - try fmt.stdout.print("{s}\n", .{file_path}); + try fmt.stdout_writer.interface.print("{s}\n", .{file_path}); } } -const std = @import("std"); -const mem = std.mem; -const fs = std.fs; -const process = std.process; -const Allocator = std.mem.Allocator; -const Color = std.zig.Color; -const fatal = std.process.fatal; - /// Provided for debugging/testing purposes; unused by the compiler. pub fn main() !void { const gpa = std.heap.smp_allocator; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 4512ff91d2..88195a9391 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1,5 +1,41 @@ //! The main driver of the self-hosted COFF linker. +const Coff = @This(); + +const std = @import("std"); +const build_options = @import("build_options"); +const builtin = @import("builtin"); +const assert = std.debug.assert; +const coff_util = std.coff; +const fmt = std.fmt; +const fs = std.fs; +const log = std.log.scoped(.link); +const math = std.math; +const mem = std.mem; + +const Allocator = std.mem.Allocator; +const Path = std.Build.Cache.Path; +const Directory = std.Build.Cache.Directory; +const Cache = std.Build.Cache; +const Writer = std.io.Writer; + +const aarch64_util = @import("../arch/aarch64/bits.zig"); +const allocPrint = std.fmt.allocPrint; +const codegen = @import("../codegen.zig"); +const link = @import("../link.zig"); +const target_util = @import("../target.zig"); +const trace = @import("../tracy.zig").trace; + +const Compilation = @import("../Compilation.zig"); +const Zcu = @import("../Zcu.zig"); +const InternPool = @import("../InternPool.zig"); +const TableSection = @import("table_section.zig").TableSection; +const StringTable = @import("StringTable.zig"); +const Type = @import("../Type.zig"); +const Value = @import("../Value.zig"); +const AnalUnit = InternPool.AnalUnit; +const dev = @import("../dev.zig"); + base: link.File, image_base: u64, /// TODO this and minor_subsystem_version should be combined into one property and left as @@ -2175,8 +2211,7 @@ fn writeDataDirectoriesHeaders(coff: *Coff) !void { fn writeHeader(coff: *Coff) !void { const target = &coff.base.comp.root_mod.resolved_target.result; const gpa = coff.base.comp.gpa; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, coff.getSizeOfHeaders())); + var bw: Writer = .fixed(try gpa.alloc(u8, coff.getSizeOfHeaders())); defer gpa.free(bw.buffer); bw.writeAll(&msdos_stub) catch unreachable; @@ -3066,14 +3101,14 @@ const ImportTable = struct { ctx: Context, }; - fn format(itab: ImportTable, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) std.io.Writer.Error!void { + fn format(itab: ImportTable, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { _ = itab; _ = bw; _ = unused_format_string; @compileError("do not format ImportTable directly; use itab.fmtDebug()"); } - fn format2(fmt_ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) std.io.Writer.Error!void { + fn format2(fmt_ctx: FormatContext, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { comptime assert(unused_format_string.len == 0); const lib_name = fmt_ctx.ctx.coff.temp_strtab.getAssumeExists(fmt_ctx.ctx.name_off); const base_vaddr = getBaseAddress(fmt_ctx.ctx); @@ -3105,41 +3140,6 @@ fn pwriteAll(coff: *Coff, bytes: []const u8, offset: u64) error{LinkFailure}!voi }; } -const Coff = @This(); - -const std = @import("std"); -const build_options = @import("build_options"); -const builtin = @import("builtin"); -const assert = std.debug.assert; -const coff_util = std.coff; -const fmt = std.fmt; -const fs = std.fs; -const log = std.log.scoped(.link); -const math = std.math; -const mem = std.mem; - -const Allocator = std.mem.Allocator; -const Path = std.Build.Cache.Path; -const Directory = std.Build.Cache.Directory; -const Cache = std.Build.Cache; - -const aarch64_util = @import("../arch/aarch64/bits.zig"); -const allocPrint = std.fmt.allocPrint; -const codegen = @import("../codegen.zig"); -const link = @import("../link.zig"); -const target_util = @import("../target.zig"); -const trace = @import("../tracy.zig").trace; - -const Compilation = @import("../Compilation.zig"); -const Zcu = @import("../Zcu.zig"); -const InternPool = @import("../InternPool.zig"); -const TableSection = @import("table_section.zig").TableSection; -const StringTable = @import("StringTable.zig"); -const Type = @import("../Type.zig"); -const Value = @import("../Value.zig"); -const AnalUnit = InternPool.AnalUnit; -const dev = @import("../dev.zig"); - /// This is the start of a Portable Executable (PE) file. /// It starts with a MS-DOS header followed by a MS-DOS stub program. /// This data does not change so we include it as follows in all binaries. diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index cb45cd59c0..a81c13cfed 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -648,8 +648,7 @@ const Unit = struct { assert(len >= unit.trailer_len); if (sec == &dwarf.debug_line.section) { var buf: [1 + uleb128Bytes(std.math.maxInt(u32)) + 1]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buf); + var bw: Writer = .fixed(&buf); bw.writeByte(DW.LNS.extended_op) catch unreachable; const extended_op_bytes = bw.end; var op_len_bytes: u5 = 1; @@ -668,8 +667,7 @@ const Unit = struct { assert(bw.end >= unit.trailer_len and bw.end <= len); return dwarf.getFile().?.pwriteAll(bw.getWritten(), sec.off(dwarf) + start); } - var trailer_bw: std.io.BufferedWriter = undefined; - trailer_bw.initFixed(try dwarf.gpa.alloc(u8, len)); + var trailer_bw: Writer = .fixed(try dwarf.gpa.alloc(u8, len)); defer dwarf.gpa.free(trailer_bw.buffer); const fill_byte: u8 = if (sec == &dwarf.debug_abbrev.section) fill: { assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1); @@ -833,8 +831,7 @@ const Entry = struct { 1 + uleb128Bytes(std.math.maxInt(u32)) + 1, ) ]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buf); + var bw: Writer = .fixed(&buf); if (sec == &dwarf.debug_info.section) switch (len) { 0 => {}, 1 => bw.writeLeb128(try dwarf.refAbbrevCode(.pad_1)) catch unreachable, @@ -1134,7 +1131,7 @@ pub const Loc = union(enum) { }; } - fn writeReg(bw: *std.io.BufferedWriter, reg: u32, op0: u8, opx: u8) std.io.Writer.Error!void { + fn writeReg(bw: *Writer, reg: u32, op0: u8, opx: u8) Writer.Error!void { if (std.math.cast(u5, reg)) |small_reg| { try bw.writeByte(op0 + small_reg); } else { @@ -1143,7 +1140,7 @@ pub const Loc = union(enum) { } } - fn write(loc: Loc, bw: *std.io.BufferedWriter, adapter: anytype) UpdateError!void { + fn write(loc: Loc, bw: *Writer, adapter: anytype) UpdateError!void { switch (loc) { .empty => {}, .addr_reloc => |sym_index| { @@ -1795,10 +1792,10 @@ pub const WipNav = struct { fn endian(_: ExprLocCounter) std.builtin.Endian { return @import("builtin").cpu.arch.endian(); } - fn addrSym(counter: ExprLocCounter, bw: *std.io.BufferedWriter, _: u32) error{}!void { + fn addrSym(counter: ExprLocCounter, bw: *Writer, _: u32) error{}!void { bw.count += @intFromEnum(counter.address_size); } - fn infoEntry(counter: ExprLocCounter, bw: *std.io.BufferedWriter, _: Unit.Index, _: Entry.Index) error{}!void { + fn infoEntry(counter: ExprLocCounter, bw: *Writer, _: Unit.Index, _: Entry.Index) error{}!void { bw.count += counter.section_offset_bytes; } }; @@ -1817,10 +1814,10 @@ pub const WipNav = struct { fn endian(ctx: @This()) std.builtin.Endian { return ctx.wip_nav.dwarf.endian; } - fn addrSym(ctx: @This(), _: *std.io.BufferedWriter, sym_index: u32) UpdateError!void { + fn addrSym(ctx: @This(), _: *Writer, sym_index: u32) UpdateError!void { try ctx.wip_nav.infoAddrSym(sym_index, 0); } - fn infoEntry(ctx: @This(), _: *std.io.BufferedWriter, unit: Unit.Index, entry: Entry.Index) UpdateError!void { + fn infoEntry(ctx: @This(), _: *Writer, unit: Unit.Index, entry: Entry.Index) UpdateError!void { try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); } } = .{ .wip_nav = wip_nav }; @@ -1852,10 +1849,10 @@ pub const WipNav = struct { fn endian(ctx: @This()) std.builtin.Endian { return ctx.wip_nav.dwarf.endian; } - fn addrSym(ctx: @This(), _: *std.io.BufferedWriter, sym_index: u32) UpdateError!void { + fn addrSym(ctx: @This(), _: *Writer, sym_index: u32) UpdateError!void { try ctx.wip_nav.frameAddrSym(sym_index, 0); } - fn infoEntry(ctx: @This(), _: *std.io.BufferedWriter, unit: Unit.Index, entry: Entry.Index) UpdateError!void { + fn infoEntry(ctx: @This(), _: *Writer, unit: Unit.Index, entry: Entry.Index) UpdateError!void { try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0); } } = .{ .wip_nav = wip_nav }; @@ -2756,8 +2753,7 @@ fn finishWipNavFuncInner( try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } else { const abbrev_code_buf = wip_nav.debug_info.getWritten()[0..AbbrevCode.decl_bytes]; - var abbrev_code_br: std.io.Reader = undefined; - abbrev_code_br.initFixed(abbrev_code_buf); + var abbrev_code_br: std.io.Reader = .fixed(abbrev_code_buf); const abbrev_code: AbbrevCode = @enumFromInt(abbrev_code_br.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable); std.leb.writeUnsignedFixed( AbbrevCode.decl_bytes, @@ -4565,14 +4561,14 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { var header: std.ArrayListUnmanaged(u8) = .empty; defer header.deinit(gpa); - var header_bw: std.io.BufferedWriter = undefined; + var header_bw: Writer = undefined; if (dwarf.debug_aranges.section.dirty) { for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| { const unit: Unit.Index = @enumFromInt(unit_index); unit_ptr.clear(); try unit_ptr.cross_section_relocs.ensureTotalCapacity(gpa, 1); try header.resize(gpa, unit_ptr.header_len); - header_bw.initFixed(header.items); + header_bw = .fixed(header.items); const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| dwarf.debug_aranges.section.getUnit(next_unit).off else @@ -4610,7 +4606,7 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { const Register = @import("../arch/x86_64/bits.zig").Register; for (dwarf.debug_frame.section.units.items) |*unit| { try header.resize(gpa, unit.header_len); - header_bw.initFixed(header.items); + header_bw = .fixed(header.items); const unit_len = unit.header_len - dwarf.unitLengthBytes(); switch (dwarf.format) { .@"32" => header_bw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, @@ -4651,7 +4647,7 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { try unit_ptr.cross_unit_relocs.ensureTotalCapacity(gpa, 1); try unit_ptr.cross_section_relocs.ensureTotalCapacity(gpa, 7); try header.resize(gpa, unit_ptr.header_len); - header_bw.initFixed(header.items); + header_bw = .fixed(header.items); const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| dwarf.debug_info.section.getUnit(next_unit).off else @@ -4751,7 +4747,7 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { unit.clear(); try unit.cross_section_relocs.ensureTotalCapacity(gpa, mod_info.dirs.count() + 2 * (mod_info.files.count())); try header.resize(gpa, unit.header_len); - header_bw.initFixed(header.items); + header_bw = .fixed(header.items); const unit_len = (if (unit.next.unwrap()) |next_unit| dwarf.debug_line.section.getUnit(next_unit).off else @@ -4859,7 +4855,7 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { if (dwarf.debug_rnglists.section.dirty) { for (dwarf.debug_rnglists.section.units.items) |*unit| { try header.resize(gpa, unit.header_len); - header_bw.initFixed(header.items); + header_bw = .fixed(header.items); const unit_len = (if (unit.next.unwrap()) |next_unit| dwarf.debug_rnglists.section.getUnit(next_unit).off else @@ -6078,7 +6074,7 @@ fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void { } } -fn writeIntTo(dwarf: *Dwarf, bw: *std.io.BufferedWriter, len: usize, int: u64) !void { +fn writeIntTo(dwarf: *Dwarf, bw: *Writer, len: usize, int: u64) !void { dwarf.writeInt(try bw.writableSlice(len), int); } @@ -6127,8 +6123,7 @@ fn leb128Bytes(value: anytype) u32 { var buffer: [ std.math.divCeil(u16, @intFromBool(value_info.signedness == .signed) + value_info.bits, 7) catch unreachable ]u8 = undefined; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(&buffer); + var bw: Writer = .fixed(&buffer); bw.writeLeb128(value) catch unreachable; return @intCast(bw.end); } @@ -6155,3 +6150,4 @@ const log = std.log.scoped(.dwarf); const std = @import("std"); const target_info = @import("../target.zig"); const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 329aa268cf..388036b146 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3029,8 +3029,7 @@ fn writeAtoms(self: *Elf) !void { if (self.requiresThunks()) { for (self.thunks.items) |th| { try buffer.resize(th.size(self)); - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(buffer.items); + var bw: Writer = .fixed(buffer.items); const shdr = slice.items(.shdr)[th.output_section_index]; const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset; try th.write(self, &bw); @@ -3136,7 +3135,7 @@ fn writeSyntheticSections(self: *Elf) !void { var buffer: std.ArrayListUnmanaged(u8) = .empty; defer buffer.deinit(gpa); - var bw: std.io.BufferedWriter = undefined; + var bw: Writer = undefined; if (self.section_indexes.interp) |shndx| { const shdr = slice.items(.shdr)[shndx]; @@ -3156,7 +3155,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.gnu_hash) |shndx| { const shdr = slice.items(.shdr)[shndx]; try buffer.resize(gpa, self.gnu_hash.size()); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try self.gnu_hash.write(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3170,7 +3169,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.verneed) |shndx| { const shdr = slice.items(.shdr)[shndx]; try buffer.resize(gpa, self.verneed.size()); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try self.verneed.write(&bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3179,7 +3178,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.dynamic) |shndx| { const shdr = slice.items(.shdr)[shndx]; try buffer.resize(gpa, self.dynamic.size(self)); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try self.dynamic.write(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3188,7 +3187,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.dynsymtab) |shndx| { const shdr = slice.items(.shdr)[shndx]; try buffer.resize(gpa, self.dynsym.size()); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try self.dynsym.write(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3208,7 +3207,7 @@ fn writeSyntheticSections(self: *Elf) !void { const shdr = slice.items(.shdr)[shndx]; const sh_size = try self.cast(usize, shdr.sh_size); try buffer.resize(gpa, @intCast(sh_size - existing_size)); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try eh_frame.writeEhFrame(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset + existing_size); @@ -3218,7 +3217,7 @@ fn writeSyntheticSections(self: *Elf) !void { const shdr = slice.items(.shdr)[shndx]; const sh_size = try self.cast(usize, shdr.sh_size); try buffer.resize(gpa, sh_size); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try eh_frame.writeEhFrameHdr(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3227,7 +3226,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.got) |index| { const shdr = slice.items(.shdr)[index]; try buffer.resize(gpa, self.got.size(self)); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try self.got.write(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3244,7 +3243,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.plt) |shndx| { const shdr = slice.items(.shdr)[shndx]; try buffer.resize(gpa, self.plt.size(self)); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try self.plt.write(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3253,7 +3252,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.got_plt) |shndx| { const shdr = slice.items(.shdr)[shndx]; try buffer.resize(gpa, self.got_plt.size(self)); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try self.got_plt.write(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3262,7 +3261,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.plt_got) |shndx| { const shdr = slice.items(.shdr)[shndx]; try buffer.resize(gpa, self.plt_got.size(self)); - bw.initFixed(buffer.items); + bw = .fixed(buffer.items); try self.plt_got.write(self, &bw); assert(bw.end == bw.buffer.len); try self.pwriteAll(bw.buffer, shdr.sh_offset); @@ -3883,7 +3882,7 @@ fn fmtShdr(self: *Elf, shdr: elf.Elf64_Shdr) std.fmt.Formatter(formatShdr) { } }; } -fn formatShdr(ctx: FormatShdrCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatShdr(ctx: FormatShdrCtx, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const shdr = ctx.shdr; try bw.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({f})", .{ @@ -3898,7 +3897,7 @@ pub fn fmtShdrFlags(sh_flags: u64) std.fmt.Formatter(formatShdrFlags) { return .{ .data = sh_flags }; } -fn formatShdrFlags(sh_flags: u64, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) !void { +fn formatShdrFlags(sh_flags: u64, bw: *Writer, comptime unused_fmt_string: []const u8) !void { _ = unused_fmt_string; if (elf.SHF_WRITE & sh_flags != 0) { try bw.writeByte('W'); @@ -3958,7 +3957,7 @@ fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Formatter(formatPhdr) { fn formatPhdr( ctx: FormatPhdrCtx, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -3994,7 +3993,7 @@ pub fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { fn fmtDumpState( self: *Elf, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -4216,7 +4215,7 @@ pub const Ref = struct { return ref.index == other.index and ref.file == other.file; } - pub fn format(ref: Ref, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format(ref: Ref, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; try bw.print("ref({},{})", .{ ref.index, ref.file }); } @@ -4493,6 +4492,7 @@ const Allocator = std.mem.Allocator; const Hash = std.hash.Wyhash; const Path = std.Build.Cache.Path; const Stat = std.Build.Cache.File.Stat; +const Writer = std.io.Writer; const codegen = @import("../codegen.zig"); const dev = @import("../dev.zig"); diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index 6e0c8ca8aa..405a3a64e6 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -184,7 +184,7 @@ pub const ArSymtab = struct { } } - pub fn format(ar: ArSymtab, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format(ar: ArSymtab, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = ar; _ = bw; _ = unused_fmt_string; @@ -203,7 +203,7 @@ pub const ArSymtab = struct { } }; } - fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const ar = ctx.ar; const elf_file = ctx.elf_file; @@ -251,8 +251,8 @@ pub const ArStrtab = struct { try writer.writeAll(ar.buffer.items); } - pub fn format(ar: ArStrtab, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; + pub fn format(ar: ArStrtab, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); try bw.print("{f}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)}); } }; @@ -277,6 +277,7 @@ const log = std.log.scoped(.link); const mem = std.mem; const Path = std.Build.Cache.Path; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; const Diags = @import("../../link.zig").Diags; const Archive = @This(); diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 3f8b0ee62a..3ec05eb942 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -622,8 +622,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi const cpu_arch = elf_file.getTarget().cpu.arch; const file_ptr = self.file(elf_file).?; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(code); + var bw: Writer = .fixed(code); const rels = self.relocs(elf_file); var it = RelocsIterator{ .relocs = rels }; @@ -807,8 +806,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any const cpu_arch = elf_file.getTarget().cpu.arch; const file_ptr = self.file(elf_file).?; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(code); + var bw: Writer = .fixed(code); const rels = self.relocs(elf_file); var has_reloc_errors = false; @@ -908,7 +906,7 @@ pub fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void { atom.file(elf_file).?.setAtomExtra(atom.extra_index, extras); } -pub fn format(atom: Atom, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(atom: Atom, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = atom; _ = bw; _ = unused_fmt_string; @@ -927,7 +925,7 @@ const FormatContext = struct { elf_file: *Elf, }; -fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const atom = ctx.atom; const elf_file = ctx.elf_file; @@ -1079,8 +1077,8 @@ const x86_64 = struct { target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, - bw: *std.io.BufferedWriter, - ) std.io.Writer.Error!void { + bw: *Writer, + ) Writer.Error!void { dev.check(.x86_64_backend); const t = &elf_file.base.comp.root_mod.resolved_target.result; const diags = &elf_file.base.comp.link_diags; @@ -1211,8 +1209,8 @@ const x86_64 = struct { rel: elf.Elf64_Rela, target: *const Symbol, args: ResolveArgs, - bw: *std.io.BufferedWriter, - ) std.io.Writer.Error!void { + bw: *Writer, + ) Writer.Error!void { dev.check(.x86_64_backend); const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); @@ -1287,7 +1285,7 @@ const x86_64 = struct { rels: []const elf.Elf64_Rela, value: i32, elf_file: *Elf, - bw: *std.io.BufferedWriter, + bw: *Writer, ) !void { dev.check(.x86_64_backend); assert(rels.len == 2); @@ -1327,7 +1325,7 @@ const x86_64 = struct { rels: []const elf.Elf64_Rela, value: i32, elf_file: *Elf, - bw: *std.io.BufferedWriter, + bw: *Writer, ) !void { dev.check(.x86_64_backend); assert(rels.len == 2); @@ -1388,7 +1386,7 @@ const x86_64 = struct { .{ .imm = .s(-129) }, }, t) catch return false; var buf: [std.atomic.cache_line]u8 = undefined; - var bw = std.io.Writer.null.buffered(&buf); + var bw = Writer.null.buffered(&buf); inst.encode(&bw, .{}) catch return false; return true; }, @@ -1435,7 +1433,7 @@ const x86_64 = struct { rels: []const elf.Elf64_Rela, value: i32, elf_file: *Elf, - bw: *std.io.BufferedWriter, + bw: *Writer, ) !void { dev.check(.x86_64_backend); assert(rels.len == 2); @@ -1483,8 +1481,7 @@ const x86_64 = struct { } fn encode(insts: []const Instruction, code: []u8) !void { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(code); + var bw: Writer = .fixed(code); for (insts) |inst| try inst.encode(&bw, .{}); } @@ -1589,8 +1586,8 @@ const aarch64 = struct { target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, - bw: *std.io.BufferedWriter, - ) std.io.Writer.Error!void { + bw: *Writer, + ) Writer.Error!void { _ = it; const diags = &elf_file.base.comp.link_diags; @@ -1792,7 +1789,7 @@ const aarch64 = struct { rel: elf.Elf64_Rela, target: *const Symbol, args: ResolveArgs, - bw: *std.io.BufferedWriter, + bw: *Writer, ) !void { const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); _, const A, const S, _, _, _, _ = args; @@ -1865,7 +1862,7 @@ const riscv = struct { target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, - bw: *std.io.BufferedWriter, + bw: *Writer, ) !void { const diags = &elf_file.base.comp.link_diags; const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); @@ -2000,8 +1997,8 @@ const riscv = struct { rel: elf.Elf64_Rela, target: *const Symbol, args: ResolveArgs, - bw: *std.io.BufferedWriter, - ) std.io.Writer.Error!void { + bw: *Writer, + ) Writer.Error!void { const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); _, const A, const S, const GOT, _, _, const DTP = args; @@ -2105,14 +2102,15 @@ pub const Extra = struct { const std = @import("std"); const assert = std.debug.assert; const elf = std.elf; -const eh_frame = @import("eh_frame.zig"); const log = std.log.scoped(.link); const math = std.math; const mem = std.mem; const relocs_log = std.log.scoped(.link_relocs); -const relocation = @import("relocation.zig"); - const Allocator = mem.Allocator; +const Writer = std.io.Writer; + +const eh_frame = @import("eh_frame.zig"); +const relocation = @import("relocation.zig"); const Atom = @This(); const Elf = @import("../Elf.zig"); const Fde = eh_frame.Fde; diff --git a/src/link/Elf/AtomList.zig b/src/link/Elf/AtomList.zig index 0271cd6c4a..500105673d 100644 --- a/src/link/Elf/AtomList.zig +++ b/src/link/Elf/AtomList.zig @@ -167,7 +167,7 @@ pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom { return elf_file.atom(list.atoms.keys()[list.atoms.keys().len - 1]).?; } -pub fn format(list: AtomList, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(list: AtomList, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = list; _ = bw; _ = unused_fmt_string; @@ -180,8 +180,8 @@ pub fn fmt(list: AtomList, elf_file: *Elf) std.fmt.Formatter(format2) { return .{ .data = .{ list, elf_file } }; } -fn format2(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn format2(ctx: FormatCtx, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const list, const elf_file = ctx; try bw.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{ list.address(elf_file), list.output_section_index, @@ -195,13 +195,14 @@ fn format2(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_strin try bw.writeAll(" }"); } +const std = @import("std"); const assert = std.debug.assert; const elf = std.elf; const log = std.log.scoped(.link); const math = std.math; -const std = @import("std"); - const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; + const Atom = @import("Atom.zig"); const AtomList = @This(); const Elf = @import("../Elf.zig"); diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index 871150a945..58310a9272 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -449,8 +449,8 @@ const FormatContext = struct { elf_file: *Elf, }; -fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn formatSymtab(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const self = ctx.self; const elf_file = ctx.elf_file; try bw.writeAll(" globals\n"); @@ -464,12 +464,13 @@ fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_ } } +const std = @import("std"); +const Allocator = mem.Allocator; const assert = std.debug.assert; const elf = std.elf; const mem = std.mem; -const std = @import("std"); +const Writer = std.io.Writer; -const Allocator = mem.Allocator; const Atom = @import("Atom.zig"); const Elf = @import("../Elf.zig"); const File = @import("file.zig").File; diff --git a/src/link/Elf/Merge.zig b/src/link/Elf/Merge.zig index 27a4f26a2a..ec2a61579b 100644 --- a/src/link/Elf/Merge.zig +++ b/src/link/Elf/Merge.zig @@ -157,7 +157,7 @@ pub const Section = struct { } }; - pub fn format(msec: Section, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format(msec: Section, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = msec; _ = bw; _ = unused_fmt_string; @@ -176,7 +176,7 @@ pub const Section = struct { elf_file: *Elf, }; - pub fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const msec = ctx.msec; const elf_file = ctx.elf_file; @@ -219,7 +219,7 @@ pub const Subsection = struct { return msec.bytes.items[msub.string_index..][0..msub.size]; } - pub fn format(msub: Subsection, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format(msub: Subsection, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = msub; _ = bw; _ = unused_fmt_string; @@ -238,7 +238,7 @@ pub const Subsection = struct { elf_file: *Elf, }; - pub fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const msub = ctx.msub; const elf_file = ctx.elf_file; @@ -307,11 +307,12 @@ pub const InputSection = struct { const String = struct { pos: u32, len: u32 }; +const std = @import("std"); const assert = std.debug.assert; const mem = std.mem; -const std = @import("std"); - const Allocator = mem.Allocator; +const Writer = std.io.Writer; + const Atom = @import("Atom.zig"); const Elf = @import("../Elf.zig"); const Merge = @This(); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index c5b77723d6..be5b48c546 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -448,8 +448,7 @@ fn parseEhFrame( const fdes_start = self.fdes.items.len; const cies_start = self.cies.items.len; - var it: eh_frame.Iterator = undefined; - it.br.initFixed(raw); + var it: eh_frame.Iterator = .{ .br = .fixed(raw) }; while (try it.next()) |rec| { const rel_range = filterRelocs(self.relocs.items[rel_start..][0..relocs.len], rec.offset, rec.size + 4); switch (rec.tag) { @@ -1199,8 +1198,7 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index const chdr = (try r.takeStruct(elf.Elf64_Chdr)).*; switch (chdr.ch_type) { .ZLIB => { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, std.math.cast(usize, chdr.ch_size) orelse return error.Overflow)); + var bw: Writer = .fixed(try gpa.alloc(u8, std.math.cast(usize, chdr.ch_size) orelse return error.Overflow)); errdefer gpa.free(bw.buffer); try std.compress.zlib.decompress(&r, &bw); if (bw.end != bw.buffer.len) return error.InputOutput; @@ -1430,7 +1428,7 @@ pub fn group(self: *Object, index: Elf.Group.Index) *Elf.Group { return &self.groups.items[index]; } -pub fn format(self: *Object, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(self: *Object, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = self; _ = bw; _ = unused_fmt_string; @@ -1449,7 +1447,7 @@ const FormatContext = struct { elf_file: *Elf, }; -fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatSymtab(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; const elf_file = ctx.elf_file; @@ -1476,7 +1474,7 @@ pub fn fmtAtoms(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatAtoms) { } }; } -fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatAtoms(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; try bw.writeAll(" atoms\n"); @@ -1493,7 +1491,7 @@ pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) { } }; } -fn formatCies(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatCies(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; try bw.writeAll(" cies\n"); @@ -1509,7 +1507,7 @@ pub fn fmtFdes(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatFdes) { } }; } -fn formatFdes(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatFdes(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; try bw.writeAll(" fdes\n"); @@ -1525,7 +1523,7 @@ pub fn fmtGroups(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatGroups) } }; } -fn formatGroups(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatGroups(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { comptime assert(unused_fmt_string.len == 0); const object = ctx.object; const elf_file = ctx.elf_file; @@ -1547,8 +1545,8 @@ pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) { return .{ .data = self }; } -fn formatPath(object: Object, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn formatPath(object: Object, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); if (object.archive) |ar| { try bw.print("{f}({f})", .{ ar.path, object.path }); } else { @@ -1574,6 +1572,7 @@ const math = std.math; const mem = std.mem; const Path = std.Build.Cache.Path; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; const Diags = @import("../../link.zig").Diags; const Archive = @import("Archive.zig"); diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index d2baaf11d6..941bd374ed 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -509,7 +509,7 @@ pub fn setSymbolExtra(self: *SharedObject, index: u32, extra: Symbol.Extra) void } } -pub fn format(self: SharedObject, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(self: SharedObject, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = self; _ = bw; _ = unused_fmt_string; @@ -528,8 +528,8 @@ const FormatContext = struct { elf_file: *Elf, }; -fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn formatSymtab(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const shared = ctx.shared; const elf_file = ctx.elf_file; try bw.writeAll(" globals\n"); @@ -553,6 +553,7 @@ const mem = std.mem; const Path = std.Build.Cache.Path; const Stat = std.Build.Cache.File.Stat; const Allocator = mem.Allocator; +const Writer = std.io.Writer; const Elf = @import("../Elf.zig"); const File = @import("file.zig").File; diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 1bb70a5c05..2790afdd12 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -316,7 +316,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { out.st_size = esym.st_size; } -pub fn format(symbol: Symbol, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(symbol: Symbol, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = symbol; _ = bw; _ = unused_fmt_string; @@ -335,7 +335,7 @@ pub fn fmtName(symbol: Symbol, elf_file: *Elf) std.fmt.Formatter(formatName) { } }; } -fn formatName(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatName(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const elf_file = ctx.elf_file; const symbol = ctx.symbol; @@ -358,8 +358,8 @@ pub fn fmt(symbol: Symbol, elf_file: *Elf) std.fmt.Formatter(format2) { } }; } -fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const symbol = ctx.symbol; const elf_file = ctx.elf_file; try bw.print("%{d} : {f} : @{x}", .{ @@ -461,12 +461,13 @@ pub const Extra = struct { pub const Index = u32; +const std = @import("std"); const assert = std.debug.assert; const elf = std.elf; const mem = std.mem; -const std = @import("std"); -const synthetic_sections = @import("synthetic_sections.zig"); +const Writer = std.io.Writer; +const synthetic_sections = @import("synthetic_sections.zig"); const Atom = @import("Atom.zig"); const Elf = @import("../Elf.zig"); const File = @import("file.zig").File; diff --git a/src/link/Elf/Thunk.zig b/src/link/Elf/Thunk.zig index b8b19164e7..8c3a1448bd 100644 --- a/src/link/Elf/Thunk.zig +++ b/src/link/Elf/Thunk.zig @@ -65,7 +65,7 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize { }; } -pub fn format(thunk: Thunk, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(thunk: Thunk, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = thunk; _ = bw; _ = unused_fmt_string; @@ -84,8 +84,8 @@ const FormatContext = struct { elf_file: *Elf, }; -fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const thunk = ctx.thunk; const elf_file = ctx.elf_file; try bw.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) }); @@ -117,14 +117,15 @@ const aarch64 = struct { const Instruction = util.Instruction; }; +const std = @import("std"); const assert = std.debug.assert; const elf = std.elf; const log = std.log.scoped(.link); const math = std.math; const mem = std.mem; -const std = @import("std"); - const Allocator = mem.Allocator; +const Writer = std.io.Writer; + const Atom = @import("Atom.zig"); const Elf = @import("../Elf.zig"); const Symbol = @import("Symbol.zig"); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 0881d4696c..c969b6a3b0 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -2198,7 +2198,7 @@ const FormatContext = struct { elf_file: *Elf, }; -fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatSymtab(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const self = ctx.self; const elf_file = ctx.elf_file; @@ -2221,8 +2221,8 @@ pub fn fmtAtoms(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatAtoms) } }; } -fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn formatAtoms(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); try bw.writeAll(" atoms\n"); for (ctx.self.atoms_indexes.items) |atom_index| { const atom_ptr = ctx.self.atom(atom_index) orelse continue; @@ -2326,6 +2326,7 @@ const target_util = @import("../../target.zig"); const trace = @import("../../tracy.zig").trace; const std = @import("std"); const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 5d46b54d39..1586a0675d 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -49,7 +49,7 @@ pub const Fde = struct { pub fn format( fde: Fde, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = fde; @@ -72,7 +72,7 @@ pub const Fde = struct { fn format2( ctx: FdeFormatContext, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -148,7 +148,7 @@ pub const Cie = struct { pub fn format( cie: Cie, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = cie; @@ -171,7 +171,7 @@ pub const Cie = struct { fn format2( ctx: CieFormatContext, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -319,7 +319,7 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: } } -pub fn writeEhFrame(elf_file: *Elf, bw: *std.io.BufferedWriter) !void { +pub fn writeEhFrame(elf_file: *Elf, bw: *Writer) !void { relocs_log.debug("{x}: .eh_frame", .{ elf_file.sections.items(.shdr)[elf_file.section_indexes.eh_frame.?].sh_addr, }); @@ -380,7 +380,7 @@ pub fn writeEhFrame(elf_file: *Elf, bw: *std.io.BufferedWriter) !void { if (has_reloc_errors) return error.RelocFailure; } -pub fn writeEhFrameRelocatable(elf_file: *Elf, bw: *std.io.BufferedWriter) !void { +pub fn writeEhFrameRelocatable(elf_file: *Elf, bw: *Writer) !void { for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; @@ -482,7 +482,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.ArrayList(elf.Elf64_Rela) } } -pub fn writeEhFrameHdr(elf_file: *Elf, bw: *std.io.BufferedWriter) !void { +pub fn writeEhFrameHdr(elf_file: *Elf, bw: *Writer) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; @@ -607,9 +607,10 @@ const assert = std.debug.assert; const elf = std.elf; const math = std.math; const relocs_log = std.log.scoped(.link_relocs); -const relocation = @import("relocation.zig"); - +const Writer = std.io.Writer; const Allocator = std.mem.Allocator; + +const relocation = @import("relocation.zig"); const Atom = @import("Atom.zig"); const DW_EH_PE = std.dwarf.EH.PE; const Elf = @import("../Elf.zig"); diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index d007942dd1..68bd303407 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -14,8 +14,8 @@ pub const File = union(enum) { return .{ .data = file }; } - fn formatPath(file: File, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; + fn formatPath(file: File, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); switch (file) { .zig_object => |zo| try bw.writeAll(zo.basename), .linker_defined => try bw.writeAll("(linker defined)"), @@ -289,6 +289,8 @@ const elf = std.elf; const log = std.log.scoped(.link); const Path = std.Build.Cache.Path; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; +const assert = std.debug.assert; const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); diff --git a/src/link/Elf/gc.zig b/src/link/Elf/gc.zig index 69c2d9753c..44b2ced73d 100644 --- a/src/link/Elf/gc.zig +++ b/src/link/Elf/gc.zig @@ -185,8 +185,8 @@ const Level = struct { self.value += 1; } - pub fn format(self: *const @This(), bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; + pub fn format(self: *const @This(), bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); try bw.splatByteAll(' ', self.value); } }; @@ -198,8 +198,9 @@ const assert = std.debug.assert; const elf = std.elf; const gc_track_live_log = std.log.scoped(.gc_track_live); const mem = std.mem; - const Allocator = mem.Allocator; +const Writer = std.io.Writer; + const Atom = @import("Atom.zig"); const Elf = @import("../Elf.zig"); const File = @import("file.zig").File; diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index bd35b51dbf..71d0d42c2b 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -100,8 +100,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { state_log.debug("ar_strtab\n{f}\n", .{ar_strtab}); } - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, total_size)); + var bw: Writer = .fixed(try gpa.alloc(u8, total_size)); defer gpa.free(bw.buffer); // Write magic @@ -406,8 +405,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void { }; const shdr = slice.items(.shdr)[shndx]; const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, sh_size - existing_size)); + var bw: Writer = .fixed(try gpa.alloc(u8, sh_size - existing_size)); defer gpa.free(bw.buffer); try eh_frame.writeEhFrameRelocatable(elf_file, &bw); log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ @@ -458,18 +456,19 @@ fn writeGroups(elf_file: *Elf) !void { } } +const std = @import("std"); const assert = std.debug.assert; -const build_options = @import("build_options"); -const eh_frame = @import("eh_frame.zig"); const elf = std.elf; -const link = @import("../../link.zig"); const log = std.log.scoped(.link); const math = std.math; const mem = std.mem; const state_log = std.log.scoped(.link_state); const Path = std.Build.Cache.Path; -const std = @import("std"); +const Writer = std.io.Writer; +const link = @import("../../link.zig"); +const build_options = @import("build_options"); +const eh_frame = @import("eh_frame.zig"); const Archive = @import("Archive.zig"); const Compilation = @import("../../Compilation.zig"); const Elf = @import("../Elf.zig"); diff --git a/src/link/Elf/relocation.zig b/src/link/Elf/relocation.zig index 48e74ae2fe..6b73b041fa 100644 --- a/src/link/Elf/relocation.zig +++ b/src/link/Elf/relocation.zig @@ -148,8 +148,8 @@ pub fn fmtRelocType(r_type: u32, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatte } }; } -fn formatRelocType(ctx: FormatRelocTypeCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn formatRelocType(ctx: FormatRelocTypeCtx, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const r_type = ctx.r_type; switch (ctx.cpu_arch) { .x86_64 => try bw.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}), @@ -159,9 +159,10 @@ fn formatRelocType(ctx: FormatRelocTypeCtx, bw: *std.io.BufferedWriter, comptime } } +const std = @import("std"); const assert = std.debug.assert; const elf = std.elf; -const std = @import("std"); +const Writer = std.io.Writer; const Dwarf = @import("../Dwarf.zig"); const Elf = @import("../Elf.zig"); diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 2b8a37f5b0..c7436534ea 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -94,7 +94,7 @@ pub const DynamicSection = struct { return nentries * @sizeOf(elf.Elf64_Dyn); } - pub fn write(dt: DynamicSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(dt: DynamicSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { const shdrs = elf_file.sections.items(.shdr); // NEEDED @@ -360,7 +360,7 @@ pub const GotSection = struct { return s; } - pub fn write(got: GotSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(got: GotSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { const comp = elf_file.base.comp; const is_dyn_lib = elf_file.isEffectivelyDynLib(); const apply_relocs = true; // TODO add user option for this @@ -615,7 +615,7 @@ pub const GotSection = struct { return .{ .data = .{ .got = got, .elf_file = elf_file } }; } - pub fn format2(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format2(ctx: FormatCtx, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const got = ctx.got; const elf_file = ctx.elf_file; @@ -672,7 +672,7 @@ pub const PltSection = struct { }; } - pub fn write(plt: PltSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(plt: PltSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { const cpu_arch = elf_file.getTarget().cpu.arch; switch (cpu_arch) { .x86_64 => try x86_64.write(plt, elf_file, bw), @@ -752,7 +752,7 @@ pub const PltSection = struct { return .{ .data = .{ .plt = plt, .elf_file = elf_file } }; } - pub fn format2(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format2(ctx: FormatCtx, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const plt = ctx.plt; const elf_file = ctx.elf_file; @@ -770,7 +770,7 @@ pub const PltSection = struct { } const x86_64 = struct { - fn write(plt: PltSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + fn write(plt: PltSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { const shdrs = elf_file.sections.items(.shdr); const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr; const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr; @@ -805,7 +805,7 @@ pub const PltSection = struct { }; const aarch64 = struct { - fn write(plt: PltSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + fn write(plt: PltSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { { const shdrs = elf_file.sections.items(.shdr); const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr); @@ -871,7 +871,7 @@ pub const GotPltSection = struct { return preamble_size + elf_file.plt.symbols.items.len * 8; } - pub fn write(got_plt: GotPltSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(got_plt: GotPltSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { _ = got_plt; { // [0]: _DYNAMIC @@ -922,7 +922,7 @@ pub const PltGotSection = struct { }; } - pub fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { const cpu_arch = elf_file.getTarget().cpu.arch; switch (cpu_arch) { .x86_64 => try x86_64.write(plt_got, elf_file, bw), @@ -958,7 +958,7 @@ pub const PltGotSection = struct { } const x86_64 = struct { - pub fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { for (plt_got.symbols.items) |ref| { const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); @@ -976,7 +976,7 @@ pub const PltGotSection = struct { }; const aarch64 = struct { - fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { for (plt_got.symbols.items) |ref| { const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); @@ -1155,7 +1155,7 @@ pub const DynsymSection = struct { return @as(u32, @intCast(dynsym.entries.items.len + 1)); } - pub fn write(dynsym: DynsymSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(dynsym: DynsymSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { try bw.writeStruct(Elf.null_sym); for (dynsym.entries.items) |entry| { const sym = elf_file.symbol(entry.ref).?; @@ -1249,7 +1249,7 @@ pub const GnuHashSection = struct { return header_size + hash.num_bloom * 8 + hash.num_buckets * 4 + hash.num_exports * 4; } - pub fn write(hash: GnuHashSection, elf_file: *Elf, br: *std.io.BufferedWriter) !void { + pub fn write(hash: GnuHashSection, elf_file: *Elf, br: *Writer) !void { const exports = getExports(elf_file); const export_off = elf_file.dynsym.count() - hash.num_exports; @@ -1458,7 +1458,7 @@ pub const VerneedSection = struct { return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Vernaux); } - pub fn write(vern: VerneedSection, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(vern: VerneedSection, bw: *Writer) Writer.Error!void { try bw.writeAll(mem.sliceAsBytes(vern.verneed.items)); try bw.writeAll(mem.sliceAsBytes(vern.vernaux.items)); } @@ -1486,7 +1486,7 @@ pub const GroupSection = struct { return (members.len + 1) * @sizeOf(u32); } - pub fn write(cgs: GroupSection, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(cgs: GroupSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { const cg = cgs.comdatGroup(elf_file); const object = cg.file(elf_file).object; const members = cg.members(elf_file); @@ -1514,7 +1514,7 @@ pub const GroupSection = struct { } }; -fn writeInt(value: anytype, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn writeInt(value: anytype, elf_file: *Elf, bw: *Writer) Writer.Error!void { const entry_size = elf_file.archPtrWidthBytes(); const target = elf_file.getTarget(); const endian = target.cpu.arch.endian(); @@ -1526,17 +1526,19 @@ fn writeInt(value: anytype, elf_file: *Elf, bw: *std.io.BufferedWriter) std.io.W } } -const assert = std.debug.assert; const builtin = @import("builtin"); + +const std = @import("std"); +const assert = std.debug.assert; const elf = std.elf; const math = std.math; const mem = std.mem; const log = std.log.scoped(.link); const relocs_log = std.log.scoped(.link_relocs); -const relocation = @import("relocation.zig"); -const std = @import("std"); - const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; + +const relocation = @import("relocation.zig"); const Elf = @import("../Elf.zig"); const File = @import("file.zig").File; const SharedObject = @import("SharedObject.zig"); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 38554dcbda..b319df1652 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2527,8 +2527,7 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void { const doWork = struct { fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(buffer[try macho_file.cast(usize, th.value)..][0..th.size()]); + var bw: Writer = .fixed(buffer[try macho_file.cast(usize, th.value)..][0..th.size()]); try th.write(macho_file, &bw); } }.doWork; @@ -2556,8 +2555,7 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void { const doWork = struct { fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(buffer); + var bw: Writer = .fixed(buffer); switch (tag) { .eh_frame => eh_frame.write(macho_file, buffer), .unwind_info => try macho_file.unwind_info.write(macho_file, &bw), @@ -2606,8 +2604,7 @@ fn updateLazyBindSizeWorker(self: *MachO) void { try macho_file.lazy_bind_section.updateSize(macho_file); const sect_id = macho_file.stubs_helper_sect_index.?; const out = &macho_file.sections.items(.out)[sect_id]; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(out.items); + var bw: Writer = .fixed(out.items); try macho_file.stubs_helper.write(macho_file, &bw); } }.doWork; @@ -2667,8 +2664,7 @@ fn writeDyldInfo(self: *MachO) !void { needed_size += cmd.lazy_bind_size; needed_size += cmd.export_size; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, needed_size)); + var bw: Writer = .fixed(try gpa.alloc(u8, needed_size)); defer gpa.free(bw.buffer); @memset(bw.buffer, 0); @@ -2690,8 +2686,7 @@ pub fn writeDataInCode(self: *MachO) !void { const gpa = self.base.comp.gpa; const cmd = self.data_in_code_cmd; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, self.data_in_code.size())); + var bw: Writer = .fixed(try gpa.alloc(u8, self.data_in_code.size())); defer gpa.free(bw.buffer); try self.data_in_code.write(self, &bw); @@ -2706,8 +2701,7 @@ fn writeIndsymtab(self: *MachO) !void { const gpa = self.base.comp.gpa; const cmd = self.dysymtab_cmd; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, @sizeOf(u32) * cmd.nindirectsyms)); + var bw: Writer = .fixed(try gpa.alloc(u8, @sizeOf(u32) * cmd.nindirectsyms)); defer gpa.free(bw.buffer); try self.indsymtab.write(self, &bw); @@ -2822,12 +2816,11 @@ fn calcSymtabSize(self: *MachO) !void { } } -fn writeLoadCommands(self: *MachO) std.io.Writer.Error!struct { usize, usize, u64 } { +fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } { const comp = self.base.comp; const gpa = comp.gpa; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, try load_commands.calcLoadCommandsSize(self, false))); + var bw: Writer = .fixed(try gpa.alloc(u8, try load_commands.calcLoadCommandsSize(self, false))); defer gpa.free(bw.buffer); var ncmds: usize = 0; @@ -3021,8 +3014,7 @@ pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void { const seg = self.getTextSegment(); const offset = self.codesig_cmd.dataoff; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, code_sig.size())); + var bw: Writer = .fixed(try gpa.alloc(u8, code_sig.size())); defer gpa.free(bw.buffer); try code_sig.writeAdhocSignature(self, .{ .file = self.base.file.?, @@ -3910,7 +3902,7 @@ pub fn dumpState(self: *MachO) std.fmt.Formatter(fmtDumpState) { return .{ .data = self }; } -fn fmtDumpState(self: *MachO, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn fmtDumpState(self: *MachO, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; if (self.getZigObject()) |zo| { try bw.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename }); @@ -3969,7 +3961,7 @@ fn fmtSections(self: *MachO) std.fmt.Formatter(formatSections) { return .{ .data = self }; } -fn formatSections(self: *MachO, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatSections(self: *MachO, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const slice = self.sections.slice(); for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| { @@ -3987,7 +3979,7 @@ fn fmtSegments(self: *MachO) std.fmt.Formatter(formatSegments) { return .{ .data = self }; } -fn formatSegments(self: *MachO, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatSegments(self: *MachO, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; for (self.segments.items, 0..) |seg, i| { try bw.print("seg({d}) : {s} : @{x}-{x} ({x}-{x})\n", .{ @@ -4001,7 +3993,7 @@ pub fn fmtSectType(tt: u8) std.fmt.Formatter(formatSectType) { return .{ .data = tt }; } -fn formatSectType(tt: u8, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatSectType(tt: u8, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const name = switch (tt) { macho.S_REGULAR => "REGULAR", @@ -4270,7 +4262,7 @@ pub const Platform = struct { cpu_arch: std.Target.Cpu.Arch, }; - pub fn formatTarget(ctx: FmtCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn formatTarget(ctx: FmtCtx, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; try bw.print("{s}-{s}", .{ @tagName(ctx.cpu_arch), @tagName(ctx.platform.os_tag) }); if (ctx.platform.abi != .none) { @@ -4483,8 +4475,8 @@ pub const Ref = struct { }; } - pub fn format(ref: Ref, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; + pub fn format(ref: Ref, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); try bw.print("%{d} in file({d})", .{ ref.index, ref.file }); } }; @@ -5387,6 +5379,7 @@ const macho = std.macho; const math = std.math; const mem = std.mem; const meta = std.meta; +const Writer = std.io.Writer; const aarch64 = @import("../arch/aarch64/bits.zig"); const bind = @import("MachO/dyld_info/bind.zig"); diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index e09c3a680c..d625b8ead8 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -78,11 +78,11 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File } pub fn writeHeader( - bw: *std.io.BufferedWriter, + bw: *Writer, object_name: []const u8, object_size: usize, format: Format, -) std.io.Writer.Error!void { +) Writer.Error!void { var hdr: ar_hdr = undefined; @memset(mem.asBytes(&hdr), ' '); inline for (@typeInfo(ar_hdr).@"struct".fields) |field| @field(hdr, field.name)[0] = '0'; @@ -177,7 +177,7 @@ pub const ArSymtab = struct { return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width); } - pub fn write(ar: ArSymtab, bw: *std.io.BufferedWriter, format: Format, macho_file: *MachO) std.io.Writer.Error!void { + pub fn write(ar: ArSymtab, bw: *Writer, format: Format, macho_file: *MachO) Writer.Error!void { const ptr_width = ptrWidth(format); // Header try writeHeader(bw, SYMDEF, ar.size(format), format); @@ -212,7 +212,7 @@ pub const ArSymtab = struct { return .{ .data = .{ .ar = ar, .macho_file = macho_file } }; } - fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const ar = ctx.ar; const macho_file = ctx.macho_file; @@ -249,7 +249,7 @@ pub fn ptrWidth(format: Format) usize { }; } -pub fn writeInt(bw: *std.io.BufferedWriter, format: Format, value: u64) std.io.Writer.Error!void { +pub fn writeInt(bw: *Writer, format: Format, value: u64) Writer.Error!void { switch (format) { .p32 => try bw.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little), .p64 => try bw.writeInt(u64, value, .little), @@ -271,8 +271,9 @@ const log = std.log.scoped(.link); const macho = std.macho; const mem = std.mem; const std = @import("std"); -const Allocator = mem.Allocator; +const Allocator = std.mem.Allocator; const Path = std.Build.Cache.Path; +const Writer = std.io.Writer; const Archive = @This(); const File = @import("file.zig").File; diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index dfae468483..7e100c059d 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -580,8 +580,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { relocs_log.debug("{x}: {s}", .{ self.value, name }); - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(buffer); + var bw: Writer = .fixed(buffer); var has_error = false; var i: usize = 0; @@ -638,8 +637,8 @@ fn resolveRelocInner( subtractor: ?Relocation, code: []u8, macho_file: *MachO, - bw: *std.io.BufferedWriter, -) std.io.Writer.Error!void { + bw: *Writer, +) Writer.Error!void { const t = &macho_file.base.comp.root_mod.resolved_target.result; const cpu_arch = t.cpu.arch; const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; @@ -938,8 +937,7 @@ const x86_64 = struct { } fn encode(insts: []const Instruction, code: []u8) !void { - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(code); + var bw: Writer = .fixed(code); for (insts) |inst| try inst.encode(&bw, .{}); } @@ -1140,8 +1138,8 @@ const FormatContext = struct { macho_file: *MachO, }; -fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const atom = ctx.atom; const macho_file = ctx.macho_file; const file = atom.getFile(macho_file); @@ -1197,19 +1195,20 @@ pub const Extra = struct { pub const Alignment = @import("../../InternPool.zig").Alignment; -const aarch64 = @import("../aarch64.zig"); +const std = @import("std"); const assert = std.debug.assert; const macho = std.macho; const math = std.math; const mem = std.mem; const log = std.log.scoped(.link); const relocs_log = std.log.scoped(.link_relocs); -const std = @import("std"); -const trace = @import("../../tracy.zig").trace; - +const Writer = std.io.Writer; const Allocator = mem.Allocator; -const Atom = @This(); const AtomicBool = std.atomic.Value(bool); + +const aarch64 = @import("../aarch64.zig"); +const trace = @import("../../tracy.zig").trace; +const Atom = @This(); const File = @import("file.zig").File; const MachO = @import("../MachO.zig"); const Object = @import("Object.zig"); diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 76cd8e42aa..7e4389e09f 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -269,8 +269,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void { fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } { const gpa = self.allocator; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self))); + var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self))); defer gpa.free(bw.buffer); var ncmds: usize = 0; @@ -456,6 +455,7 @@ const math = std.math; const mem = std.mem; const padToIdeal = MachO.padToIdeal; const trace = @import("../../tracy.zig").trace; +const Writer = std.io.Writer; const Allocator = mem.Allocator; const MachO = @import("../MachO.zig"); diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig index 5a0191bda6..f7af39aa93 100644 --- a/src/link/MachO/Dylib.zig +++ b/src/link/MachO/Dylib.zig @@ -675,7 +675,7 @@ const FormatContext = struct { macho_file: *MachO, }; -fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatSymtab(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const dylib = ctx.dylib; const macho_file = ctx.macho_file; @@ -901,19 +901,17 @@ const Export = struct { }; }; +const std = @import("std"); const assert = std.debug.assert; -const fat = @import("fat.zig"); const fs = std.fs; const fmt = std.fmt; const log = std.log.scoped(.link); const macho = std.macho; const math = std.math; const mem = std.mem; -const tapi = @import("../tapi.zig"); -const trace = @import("../../tracy.zig").trace; -const std = @import("std"); const Allocator = mem.Allocator; const Path = std.Build.Cache.Path; +const Writer = std.io.Writer; const Dylib = @This(); const File = @import("file.zig").File; @@ -922,3 +920,6 @@ const LoadCommandIterator = macho.LoadCommandIterator; const MachO = @import("../MachO.zig"); const Symbol = @import("Symbol.zig"); const Tbd = tapi.Tbd; +const fat = @import("fat.zig"); +const tapi = @import("../tapi.zig"); +const trace = @import("../../tracy.zig").trace; diff --git a/src/link/MachO/InternalObject.zig b/src/link/MachO/InternalObject.zig index 9a4d38c0b3..19eb04b712 100644 --- a/src/link/MachO/InternalObject.zig +++ b/src/link/MachO/InternalObject.zig @@ -848,7 +848,7 @@ pub fn fmtAtoms(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(for } }; } -fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatAtoms(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; try bw.writeAll(" atoms\n"); for (ctx.self.getAtoms()) |atom_index| { @@ -864,8 +864,8 @@ pub fn fmtSymtab(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(fo } }; } -fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn formatSymtab(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const macho_file = ctx.macho_file; const self = ctx.self; try bw.writeAll(" symbols\n"); @@ -896,6 +896,7 @@ const macho = std.macho; const mem = std.mem; const std = @import("std"); const trace = @import("../../tracy.zig").trace; +const Writer = std.io.Writer; const Allocator = std.mem.Allocator; const Atom = @import("Atom.zig"); diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index f4073743be..4f344f536d 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -1065,8 +1065,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi } } - var it: eh_frame.Iterator = undefined; - it.br.initFixed(self.eh_frame_data.items); + var it: eh_frame.Iterator = .{ .br = .fixed(self.eh_frame_data.items) }; while (try it.next()) |rec| { switch (rec.tag) { .cie => try self.cies.append(allocator, .{ @@ -1695,7 +1694,7 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { }; } -pub fn writeAr(self: Object, bw: *std.io.BufferedWriter, ar_format: Archive.Format, macho_file: *MachO) !void { +pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) !void { // Header const size = try macho_file.cast(usize, self.output_ar_state.size); const basename = std.fs.path.basename(self.path.sub_path); @@ -2513,7 +2512,7 @@ pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_ return data; } -pub fn format(self: *Object, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(self: *Object, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = self; _ = bw; _ = unused_fmt_string; @@ -2532,7 +2531,7 @@ pub fn fmtAtoms(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatAtoms } }; } -fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatAtoms(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; const macho_file = ctx.macho_file; @@ -2550,7 +2549,7 @@ pub fn fmtCies(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatCies) } }; } -fn formatCies(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatCies(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; try bw.writeAll(" cies\n"); @@ -2566,7 +2565,7 @@ pub fn fmtFdes(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatFdes) } }; } -fn formatFdes(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatFdes(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; try bw.writeAll(" fdes\n"); @@ -2582,7 +2581,7 @@ pub fn fmtUnwindRecords(self: *Object, macho_file: *MachO) std.fmt.Formatter(for } }; } -fn formatUnwindRecords(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatUnwindRecords(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; const macho_file = ctx.macho_file; @@ -2599,7 +2598,7 @@ pub fn fmtSymtab(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatSymt } }; } -fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatSymtab(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const object = ctx.object; const macho_file = ctx.macho_file; @@ -2629,7 +2628,7 @@ pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) { return .{ .data = self }; } -fn formatPath(object: Object, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatPath(object: Object, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; if (object.in_archive) |ar| { try bw.print("{f}({s})", .{ @@ -2690,7 +2689,7 @@ const StabFile = struct { return object.symbols.items[index]; } - pub fn format(stab: Stab, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format(stab: Stab, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = stab; _ = bw; _ = unused_fmt_string; @@ -2703,7 +2702,7 @@ const StabFile = struct { return .{ .data = .{ stab, object } }; } - fn format2(ctx: StabFormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + fn format2(ctx: StabFormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const stab, const object = ctx; const sym = stab.getSymbol(object).?; @@ -3104,17 +3103,18 @@ const aarch64 = struct { } }; +const std = @import("std"); const assert = std.debug.assert; -const eh_frame = @import("eh_frame.zig"); const log = std.log.scoped(.link); const macho = std.macho; const math = std.math; const mem = std.mem; -const trace = @import("../../tracy.zig").trace; -const std = @import("std"); const Path = std.Build.Cache.Path; +const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; -const Allocator = mem.Allocator; +const eh_frame = @import("eh_frame.zig"); +const trace = @import("../../tracy.zig").trace; const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); const Cie = eh_frame.Cie; diff --git a/src/link/MachO/Relocation.zig b/src/link/MachO/Relocation.zig index baa953c941..30eef438ae 100644 --- a/src/link/MachO/Relocation.zig +++ b/src/link/MachO/Relocation.zig @@ -76,7 +76,7 @@ pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatt return .{ .data = .{ rel, cpu_arch } }; } -fn formatPretty(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatPretty(ctx: FormatCtx, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const rel, const cpu_arch = ctx; try bw.writeAll(switch (rel.type) { @@ -157,10 +157,11 @@ pub const Type = enum { const Tag = enum { local, @"extern" }; +const std = @import("std"); const assert = std.debug.assert; const macho = std.macho; const math = std.math; -const std = @import("std"); +const Writer = std.io.Writer; const Atom = @import("Atom.zig"); const MachO = @import("../MachO.zig"); diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 1ef01259e6..9e8660d8cf 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -286,7 +286,7 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo } } -pub fn format(symbol: Symbol, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(symbol: Symbol, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = symbol; _ = bw; _ = unused_fmt_string; @@ -305,8 +305,8 @@ pub fn fmt(symbol: Symbol, macho_file: *MachO) std.fmt.Formatter(format2) { } }; } -fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { - _ = unused_fmt_string; +fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { + comptime assert(unused_fmt_string.len == 0); const symbol = ctx.symbol; try bw.print("%{d} : {s} : @{x}", .{ symbol.nlist_idx, @@ -425,6 +425,7 @@ pub const Index = u32; const assert = std.debug.assert; const macho = std.macho; const std = @import("std"); +const Writer = std.io.Writer; const Atom = @import("Atom.zig"); const File = @import("file.zig").File; diff --git a/src/link/MachO/Thunk.zig b/src/link/MachO/Thunk.zig index f8b18084cf..b84cc4c8f2 100644 --- a/src/link/MachO/Thunk.zig +++ b/src/link/MachO/Thunk.zig @@ -20,7 +20,7 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size; } -pub fn write(thunk: Thunk, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { +pub fn write(thunk: Thunk, macho_file: *MachO, bw: *Writer) !void { for (thunk.symbols.keys(), 0..) |ref, i| { const sym = ref.getSymbol(macho_file).?; const saddr = thunk.getAddress(macho_file) + i * trampoline_size; @@ -61,7 +61,7 @@ pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void { } } -pub fn format(thunk: Thunk, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +pub fn format(thunk: Thunk, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = thunk; _ = bw; _ = unused_fmt_string; @@ -80,7 +80,7 @@ const FormatContext = struct { macho_file: *MachO, }; -fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const thunk = ctx.thunk; const macho_file = ctx.macho_file; @@ -103,6 +103,7 @@ const math = std.math; const mem = std.mem; const std = @import("std"); const trace = @import("../../tracy.zig").trace; +const Writer = std.io.Writer; const Allocator = mem.Allocator; const Atom = @import("Atom.zig"); diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig index a6d90ebc39..a8afef13b0 100644 --- a/src/link/MachO/UnwindInfo.zig +++ b/src/link/MachO/UnwindInfo.zig @@ -289,7 +289,7 @@ pub fn calcSize(info: UnwindInfo) usize { return total_size; } -pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!void { const seg = macho_file.getTextSegment(); const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?]; @@ -449,7 +449,7 @@ pub const Encoding = extern struct { return enc.enc == other.enc; } - pub fn format(enc: Encoding, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format(enc: Encoding, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; try bw.print("0x{x:0>8}", .{enc.enc}); } @@ -505,7 +505,7 @@ pub const Record = struct { return lsda.getAddress(macho_file) + rec.lsda_offset; } - pub fn format(rec: Record, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format(rec: Record, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = rec; _ = bw; _ = unused_fmt_string; @@ -524,7 +524,7 @@ pub const Record = struct { macho_file: *MachO, }; - fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const rec = ctx.rec; const macho_file = ctx.macho_file; @@ -589,7 +589,7 @@ const Page = struct { return null; } - fn format(page: *const Page, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) std.io.Writer.Error!void { + fn format(page: *const Page, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { _ = page; _ = bw; _ = unused_format_string; @@ -601,7 +601,7 @@ const Page = struct { info: UnwindInfo, }; - fn format2(ctx: FormatPageContext, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) std.io.Writer.Error!void { + fn format2(ctx: FormatPageContext, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { _ = unused_format_string; try bw.writeAll("Page:\n"); try bw.print(" kind: {s}\n", .{@tagName(ctx.page.kind)}); @@ -684,6 +684,7 @@ const macho = std.macho; const math = std.math; const mem = std.mem; const trace = @import("../../tracy.zig").trace; +const Writer = std.io.Writer; const Allocator = mem.Allocator; const Atom = @import("Atom.zig"); diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 7d8b6857d4..54d25fe6e3 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -317,7 +317,7 @@ pub fn updateArSize(self: *ZigObject) void { self.output_ar_state.size = self.data.items.len; } -pub fn writeAr(self: ZigObject, bw: *std.io.BufferedWriter, ar_format: Archive.Format) std.io.Writer.Error!void { +pub fn writeAr(self: ZigObject, bw: *Writer, ar_format: Archive.Format) Writer.Error!void { // Header const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; try Archive.writeHeader(bw, self.basename, size, ar_format); @@ -1688,7 +1688,7 @@ const FormatContext = struct { macho_file: *MachO, }; -fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatSymtab(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; try bw.writeAll(" symbols\n"); const self = ctx.self; @@ -1711,7 +1711,7 @@ pub fn fmtAtoms(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatAt } }; } -fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { +fn formatAtoms(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const self = ctx.self; const macho_file = ctx.macho_file; @@ -1783,6 +1783,7 @@ const mem = std.mem; const target_util = @import("../../target.zig"); const trace = @import("../../tracy.zig").trace; const std = @import("std"); +const Writer = std.io.Writer; const Allocator = std.mem.Allocator; const Archive = @import("Archive.zig"); diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index 0bd8213414..17bd302d82 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -196,7 +196,7 @@ const Level = struct { self.value += 1; } - pub fn format(self: *const @This(), bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + pub fn format(self: *const @This(), bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; try bw.splatByteAll(' ', self.value); } @@ -213,6 +213,7 @@ const mem = std.mem; const trace = @import("../../tracy.zig").trace; const track_live_log = std.log.scoped(.dead_strip_track_live); const std = @import("std"); +const Writer = std.io.Writer; const Allocator = mem.Allocator; const Atom = @import("Atom.zig"); diff --git a/src/link/MachO/dyld_info/Rebase.zig b/src/link/MachO/dyld_info/Rebase.zig index ed337a72d8..445fc076a7 100644 --- a/src/link/MachO/dyld_info/Rebase.zig +++ b/src/link/MachO/dyld_info/Rebase.zig @@ -133,7 +133,7 @@ fn finalize(rebase: *Rebase, gpa: Allocator) !void { try done(bw); } -fn finalizeSegment(entries: []const Entry, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void { if (entries.len == 0) return; const segment_id = entries[0].segment_id; @@ -220,24 +220,24 @@ fn finalizeSegment(entries: []const Entry, bw: *std.io.BufferedWriter) std.io.Wr } } -fn setTypePointer(bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn setTypePointer(bw: *Writer) Writer.Error!void { log.debug(">>> set type: {d}", .{macho.REBASE_TYPE_POINTER}); try bw.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.REBASE_TYPE_POINTER))); } -fn setSegmentOffset(segment_id: u4, offset: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void { log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset }); try bw.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id))); try bw.writeLeb128(offset); } -fn rebaseAddAddr(addr: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn rebaseAddAddr(addr: u64, bw: *Writer) Writer.Error!void { log.debug(">>> rebase with add: {x}", .{addr}); try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB); try bw.writeLeb128(addr); } -fn rebaseTimes(count: usize, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn rebaseTimes(count: usize, bw: *Writer) Writer.Error!void { log.debug(">>> rebase with count: {d}", .{count}); if (count <= 0xf) { try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count))); @@ -247,14 +247,14 @@ fn rebaseTimes(count: usize, bw: *std.io.BufferedWriter) std.io.Writer.Error!voi } } -fn rebaseTimesSkip(count: usize, skip: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn rebaseTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void { log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip }); try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB); try bw.writeLeb128(count); try bw.writeLeb128(skip); } -fn addAddr(addr: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn addAddr(addr: u64, bw: *Writer) Writer.Error!void { log.debug(">>> add: {x}", .{addr}); if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| { if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte( @@ -265,12 +265,12 @@ fn addAddr(addr: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { try bw.writeLeb128(addr); } -fn done(bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn done(bw: *Writer) Writer.Error!void { log.debug(">>> done", .{}); try bw.writeByte(macho.REBASE_OPCODE_DONE); } -pub fn write(rebase: Rebase, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn write(rebase: Rebase, bw: *Writer) Writer.Error!void { try bw.writeAll(rebase.buffer.items); } @@ -654,9 +654,10 @@ const log = std.log.scoped(.link_dyld_info); const macho = std.macho; const mem = std.mem; const testing = std.testing; -const trace = @import("../../../tracy.zig").trace; - const Allocator = mem.Allocator; +const Writer = std.io.Writer; + +const trace = @import("../../../tracy.zig").trace; const File = @import("../file.zig").File; const MachO = @import("../../MachO.zig"); const Rebase = @This(); diff --git a/src/link/MachO/dyld_info/Trie.zig b/src/link/MachO/dyld_info/Trie.zig index 53e73c334d..c4a5548f7e 100644 --- a/src/link/MachO/dyld_info/Trie.zig +++ b/src/link/MachO/dyld_info/Trie.zig @@ -166,8 +166,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void { assert(self.buffer.len == 0); self.buffer = try allocator.alloc(u8, size); - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(self.buffer); + var bw: Writer = .fixed(self.buffer); for (ordered_nodes.items) |node_index| { try self.writeNode(node_index, &bw); } @@ -185,7 +184,7 @@ const FinalizeNodeResult = struct { /// Updates offset of this node in the output byte stream. fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult { var buf: [1024]u8 = undefined; - var bw = std.io.Writer.null.buffered(&buf); + var bw = Writer.null.buffered(&buf); const slice = self.nodes.slice(); var node_size: u32 = 0; @@ -229,7 +228,7 @@ pub fn deinit(self: *Trie, allocator: Allocator) void { allocator.free(self.buffer); } -pub fn write(self: Trie, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn write(self: Trie, bw: *Writer) Writer.Error!void { try bw.writeAll(self.buffer); } @@ -239,7 +238,7 @@ pub fn write(self: Trie, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { /// iterate over `Trie.ordered_nodes` and call this method on each node. /// This is one of the requirements of the MachO. /// Panics if `finalize` was not called before calling this method. -fn writeNode(self: *Trie, node_index: Node.Index, bw: *std.io.BufferedWriter) !void { +fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void { const slice = self.nodes.slice(); const edges = slice.items(.edges)[node_index]; const is_terminal = slice.items(.is_terminal)[node_index]; @@ -408,9 +407,10 @@ const macho = std.macho; const mem = std.mem; const std = @import("std"); const testing = std.testing; +const Writer = std.io.Writer; + const trace = @import("../../../tracy.zig").trace; const DeprecatedLinearFifo = @import("../../../deprecated.zig").LinearFifo; - const Allocator = mem.Allocator; const MachO = @import("../../MachO.zig"); const Trie = @This(); diff --git a/src/link/MachO/dyld_info/bind.zig b/src/link/MachO/dyld_info/bind.zig index bdb330b18c..82680e3bf1 100644 --- a/src/link/MachO/dyld_info/bind.zig +++ b/src/link/MachO/dyld_info/bind.zig @@ -139,7 +139,7 @@ pub const Bind = struct { try done(bw); } - fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void { if (entries.len == 0) return; const seg_id = entries[0].segment_id; @@ -251,7 +251,7 @@ pub const Bind = struct { } } - pub fn write(bind: Bind, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(bind: Bind, bw: *Writer) Writer.Error!void { try bw.writeAll(bind.buffer.items); } }; @@ -380,7 +380,7 @@ pub const WeakBind = struct { try done(bw); } - fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void { if (entries.len == 0) return; const seg_id = entries[0].segment_id; @@ -481,7 +481,7 @@ pub const WeakBind = struct { } } - pub fn write(bind: WeakBind, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(bind: WeakBind, bw: *Writer) Writer.Error!void { try bw.writeAll(bind.buffer.items); } }; @@ -565,30 +565,30 @@ pub const LazyBind = struct { } } - pub fn write(bind: LazyBind, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { + pub fn write(bind: LazyBind, bw: *Writer) Writer.Error!void { try bw.writeAll(bind.buffer.items); } }; -fn setSegmentOffset(segment_id: u4, offset: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void { log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset }); try bw.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segment_id); try bw.writeLeb128(offset); } -fn setSymbol(name: []const u8, flags: u4, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn setSymbol(name: []const u8, flags: u4, bw: *Writer) Writer.Error!void { log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags }); try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags); try bw.writeAll(name); try bw.writeByte(0); } -fn setTypePointer(bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn setTypePointer(bw: *Writer) Writer.Error!void { log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER}); try bw.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.BIND_TYPE_POINTER))); } -fn setDylibOrdinal(ordinal: i16, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn setDylibOrdinal(ordinal: i16, bw: *Writer) Writer.Error!void { switch (ordinal) { else => unreachable, // Invalid dylib special binding macho.BIND_SPECIAL_DYLIB_SELF, @@ -610,18 +610,18 @@ fn setDylibOrdinal(ordinal: i16, bw: *std.io.BufferedWriter) std.io.Writer.Error } } -fn setAddend(addend: i64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn setAddend(addend: i64, bw: *Writer) Writer.Error!void { log.debug(">>> set addend: {x}", .{addend}); try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB); try bw.writeLeb128(addend); } -fn doBind(bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn doBind(bw: *Writer) Writer.Error!void { log.debug(">>> bind", .{}); try bw.writeByte(macho.BIND_OPCODE_DO_BIND); } -fn doBindAddAddr(addr: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn doBindAddAddr(addr: u64, bw: *Writer) Writer.Error!void { log.debug(">>> bind with add: {x}", .{addr}); if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| { if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte( @@ -632,34 +632,35 @@ fn doBindAddAddr(addr: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void try bw.writeLeb128(addr); } -fn doBindTimesSkip(count: usize, skip: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn doBindTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void { log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip }); try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB); try bw.writeLeb128(count); try bw.writeLeb128(skip); } -fn addAddr(addr: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn addAddr(addr: u64, bw: *Writer) Writer.Error!void { log.debug(">>> add: {x}", .{addr}); try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB); try bw.writeLeb128(addr); } -fn done(bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn done(bw: *Writer) Writer.Error!void { log.debug(">>> done", .{}); try bw.writeByte(macho.BIND_OPCODE_DONE); } +const std = @import("std"); const assert = std.debug.assert; const leb = std.leb; const log = std.log.scoped(.link_dyld_info); const macho = std.macho; const mem = std.mem; const testing = std.testing; -const trace = @import("../../../tracy.zig").trace; -const std = @import("std"); +const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; -const Allocator = mem.Allocator; +const trace = @import("../../../tracy.zig").trace; const File = @import("../file.zig").File; const MachO = @import("../../MachO.zig"); const Symbol = @import("../Symbol.zig"); diff --git a/src/link/MachO/eh_frame.zig b/src/link/MachO/eh_frame.zig index 2a452604b0..3d77115604 100644 --- a/src/link/MachO/eh_frame.zig +++ b/src/link/MachO/eh_frame.zig @@ -103,7 +103,7 @@ pub const Cie = struct { macho_file: *MachO, }; - fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const cie = ctx.cie; try bw.print("@{x} : size({x})", .{ @@ -142,8 +142,7 @@ pub const Fde = struct { const object = fde.getObject(macho_file); const sect = object.sections.items(.header)[object.eh_frame_sect_index.?]; - var br: std.io.Reader = undefined; - br.initFixed(fde.getData(macho_file)); + var br: std.io.Reader = .fixed(fde.getData(macho_file)); try br.discard(4); const cie_ptr = try br.takeInt(u32, .little); @@ -249,7 +248,7 @@ pub const Fde = struct { macho_file: *MachO, }; - fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + fn format2(ctx: FormatContext, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; const fde = ctx.fde; const macho_file = ctx.macho_file; @@ -528,6 +527,7 @@ const math = std.math; const mem = std.mem; const std = @import("std"); const trace = @import("../../tracy.zig").trace; +const Writer = std.io.Writer; const Allocator = std.mem.Allocator; const Atom = @import("Atom.zig"); diff --git a/src/link/MachO/file.zig b/src/link/MachO/file.zig index ed43e2e50b..b40b770959 100644 --- a/src/link/MachO/file.zig +++ b/src/link/MachO/file.zig @@ -14,7 +14,7 @@ pub const File = union(enum) { return .{ .data = file }; } - fn formatPath(file: File, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) std.io.Writer.Error!void { + fn formatPath(file: File, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void { _ = unused_fmt_string; switch (file) { .zig_object => |zo| try bw.writeAll(zo.basename), @@ -322,7 +322,7 @@ pub const File = union(enum) { }; } - pub fn writeAr(file: File, bw: *std.io.BufferedWriter, ar_format: Archive.Format, macho_file: *MachO) std.io.Writer.Error!void { + pub fn writeAr(file: File, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) Writer.Error!void { return switch (file) { .dylib, .internal => unreachable, .zig_object => |x| x.writeAr(bw, ar_format), @@ -365,6 +365,7 @@ const log = std.log.scoped(.link); const macho = std.macho; const Allocator = std.mem.Allocator; const Path = std.Build.Cache.Path; +const Writer = std.io.Writer; const trace = @import("../../tracy.zig").trace; const Archive = @import("Archive.zig"); diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index c0cb1ca33d..2d3f0bb231 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -3,6 +3,7 @@ const assert = std.debug.assert; const log = std.log.scoped(.link); const macho = std.macho; const mem = std.mem; +const Writer = std.io.Writer; const Allocator = mem.Allocator; const DebugSymbols = @import("DebugSymbols.zig"); @@ -180,7 +181,7 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 { return offset; } -pub fn writeDylinkerLC(bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn writeDylinkerLC(bw: *Writer) Writer.Error!void { const name_len = mem.sliceTo(default_dyld_path, 0).len; const cmdsize = @as(u32, @intCast(mem.alignForward( u64, @@ -204,7 +205,7 @@ const WriteDylibLCCtx = struct { compatibility_version: u32 = 0x10000, }; -pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *std.io.BufferedWriter) !void { +pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void { const name_len = ctx.name.len + 1; const cmdsize: u32 = @intCast(mem.alignForward( u64, @@ -252,7 +253,7 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void { }, writer); } -pub fn writeRpathLC(bw: *std.io.BufferedWriter, rpath: []const u8) !void { +pub fn writeRpathLC(bw: *Writer, rpath: []const u8) !void { const rpath_len = rpath.len + 1; const cmdsize = @as(u32, @intCast(mem.alignForward( u64, @@ -268,7 +269,7 @@ pub fn writeRpathLC(bw: *std.io.BufferedWriter, rpath: []const u8) !void { try bw.splatByteAll(0, cmdsize - @sizeOf(macho.rpath_command) - rpath_len); } -pub fn writeVersionMinLC(bw: *std.io.BufferedWriter, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) std.io.Writer.Error!void { +pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void { const cmd: macho.LC = switch (platform.os_tag) { .macos => .VERSION_MIN_MACOSX, .ios => .VERSION_MIN_IPHONEOS, @@ -286,7 +287,7 @@ pub fn writeVersionMinLC(bw: *std.io.BufferedWriter, platform: MachO.Platform, s })); } -pub fn writeBuildVersionLC(bw: *std.io.BufferedWriter, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) std.io.Writer.Error!void { +pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void { const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); try bw.writeStruct(macho.build_version_command{ .cmdsize = cmdsize, diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index 491c586003..0458ccef8b 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -205,8 +205,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)}); } - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, total_size)); + var bw: Writer = .fixed(try gpa.alloc(u8, total_size)); defer gpa.free(bw.buffer); // Write magic @@ -683,8 +682,7 @@ fn writeSectionsToFile(macho_file: *MachO) !void { fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } { const gpa = macho_file.base.comp.gpa; - var bw: std.io.BufferedWriter = undefined; - bw.initFixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file))); + var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file))); defer gpa.free(bw.buffer); var ncmds: usize = 0; @@ -759,6 +757,7 @@ const macho = std.macho; const math = std.math; const mem = std.mem; const state_log = std.log.scoped(.link_state); +const Writer = std.io.Writer; const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); diff --git a/src/link/MachO/synthetic.zig b/src/link/MachO/synthetic.zig index 387225ae71..09e3ea1368 100644 --- a/src/link/MachO/synthetic.zig +++ b/src/link/MachO/synthetic.zig @@ -27,7 +27,7 @@ pub const GotSection = struct { return got.symbols.items.len * @sizeOf(u64); } - pub fn write(got: GotSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + pub fn write(got: GotSection, macho_file: *MachO, bw: *Writer) !void { const tracy = trace(@src()); defer tracy.end(); for (got.symbols.items) |ref| { @@ -48,7 +48,7 @@ pub const GotSection = struct { pub fn format2( ctx: FormatCtx, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -94,7 +94,7 @@ pub const StubsSection = struct { return stubs.symbols.items.len * header.reserved2; } - pub fn write(stubs: StubsSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + pub fn write(stubs: StubsSection, macho_file: *MachO, bw: *Writer) !void { const tracy = trace(@src()); defer tracy.end(); const cpu_arch = macho_file.getTarget().cpu.arch; @@ -137,7 +137,7 @@ pub const StubsSection = struct { pub fn format2( ctx: FormatCtx, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -185,7 +185,7 @@ pub const StubsHelperSection = struct { return s; } - pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void { const tracy = trace(@src()); defer tracy.end(); @@ -230,7 +230,7 @@ pub const StubsHelperSection = struct { } } - fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void { _ = stubs_helper; const obj = macho_file.getInternalObject().?; const cpu_arch = macho_file.getTarget().cpu.arch; @@ -289,7 +289,7 @@ pub const LaSymbolPtrSection = struct { return macho_file.stubs.symbols.items.len * @sizeOf(u64); } - pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, bw: *Writer) !void { const tracy = trace(@src()); defer tracy.end(); _ = laptr; @@ -339,7 +339,7 @@ pub const TlvPtrSection = struct { return tlv.symbols.items.len * @sizeOf(u64); } - pub fn write(tlv: TlvPtrSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + pub fn write(tlv: TlvPtrSection, macho_file: *MachO, bw: *Writer) !void { const tracy = trace(@src()); defer tracy.end(); @@ -364,7 +364,7 @@ pub const TlvPtrSection = struct { pub fn format2( ctx: FormatCtx, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -415,7 +415,7 @@ pub const ObjcStubsSection = struct { return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch); } - pub fn write(objc: ObjcStubsSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + pub fn write(objc: ObjcStubsSection, macho_file: *MachO, bw: *Writer) !void { const tracy = trace(@src()); defer tracy.end(); @@ -487,7 +487,7 @@ pub const ObjcStubsSection = struct { pub fn format2( ctx: FormatCtx, - bw: *std.io.BufferedWriter, + bw: *Writer, comptime unused_fmt_string: []const u8, ) !void { _ = unused_fmt_string; @@ -516,7 +516,7 @@ pub const Indsymtab = struct { macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file); } - pub fn write(ind: Indsymtab, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + pub fn write(ind: Indsymtab, macho_file: *MachO, bw: *Writer) !void { const tracy = trace(@src()); defer tracy.end(); @@ -593,7 +593,7 @@ pub const DataInCode = struct { macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow; } - pub fn write(dice: DataInCode, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { + pub fn write(dice: DataInCode, macho_file: *MachO, bw: *Writer) !void { const base_address = if (!macho_file.base.isRelocatable()) macho_file.getTextSegment().vmaddr else @@ -617,13 +617,14 @@ pub const DataInCode = struct { }; }; +const std = @import("std"); const aarch64 = @import("../aarch64.zig"); const assert = std.debug.assert; const macho = std.macho; const math = std.math; -const std = @import("std"); -const trace = @import("../../tracy.zig").trace; - const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; + +const trace = @import("../../tracy.zig").trace; const MachO = @import("../MachO.zig"); const Symbol = @import("Symbol.zig"); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index cb19d2044f..ae0225ebdb 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -23,6 +23,7 @@ const Allocator = std.mem.Allocator; const log = std.log.scoped(.link); const assert = std.debug.assert; const Path = std.Build.Cache.Path; +const Writer = std.io.Writer; base: link.File, sixtyfour_bit: bool, @@ -336,25 +337,24 @@ fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void }; try fn_map_res.value_ptr.functions.put(gpa, nav_index, out); - var aw: std.io.AllocatingWriter = undefined; - aw.init(arena); + var aw: std.io.AllocatingWriter = .init(arena); defer aw.deinit(); - const bw = &aw.buffered_writer; + const w = &aw.interface; // every 'z' starts with 0 - try bw.writeByte(0); + try w.writeByte(0); // path component value of '/' - try bw.writeInt(u16, 1, .big); + try w.writeInt(u16, 1, .big); // getting the full file path { const full_path = try file.path.toAbsolute(comp.dirs, gpa); defer gpa.free(full_path); - try self.addPathComponents(full_path, bw); + try self.addPathComponents(full_path, w); } // null terminate - try bw.writeByte(0); + try w.writeByte(0); const final = try aw.toOwnedSlice(); self.syms.items[fn_map_res.value_ptr.sym_index - 1] = .{ .type = .z, @@ -370,17 +370,17 @@ fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void } } -fn addPathComponents(self: *Plan9, path: []const u8, bw: *std.io.BufferedWriter) !void { +fn addPathComponents(self: *Plan9, path: []const u8, w: *Writer) !void { const gpa = self.base.comp.gpa; const sep = std.fs.path.sep; var it = std.mem.tokenizeScalar(u8, path, sep); while (it.next()) |component| { if (self.file_segments.get(component)) |num| { - try bw.writeInt(u16, num, .big); + try w.writeInt(u16, num, .big); } else { self.file_segments_i += 1; try self.file_segments.put(gpa, component, self.file_segments_i); - try bw.writeInt(u16, self.file_segments_i, .big); + try w.writeInt(u16, self.file_segments_i, .big); } } } @@ -527,14 +527,14 @@ fn allocateGotIndex(self: *Plan9) usize { } } -pub fn changeLine(bw: *std.io.Writer, delta_line: i32) !void { +pub fn changeLine(w: *std.io.Writer, delta_line: i32) !void { if (delta_line > 0 and delta_line < 65) { - try bw.writeByte(@intCast(delta_line)); + try w.writeByte(@intCast(delta_line)); } else if (delta_line < 0 and delta_line > -65) { - try bw.writeByte(@intCast(-delta_line + 64)); + try w.writeByte(@intCast(-delta_line + 64)); } else if (delta_line != 0) { - try bw.writeByte(0); - try bw.writeInt(i32, delta_line, .big); + try w.writeByte(0); + try w.writeInt(i32, delta_line, .big); } } @@ -1205,16 +1205,16 @@ pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void { try w.writeByte(0); } -pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { +pub fn writeSyms(self: *Plan9, w: *Writer) !void { const zcu = self.base.comp.zcu.?; const ip = &zcu.intern_pool; // write __GOT - try self.writeSym(bw, self.syms.items[0]); + try self.writeSym(w, self.syms.items[0]); // write the f symbols { var it = self.file_segments.iterator(); while (it.next()) |entry| { - try self.writeSym(bw, .{ + try self.writeSym(w, .{ .type = .f, .value = entry.value_ptr.*, .name = entry.key_ptr.*, @@ -1230,12 +1230,12 @@ pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { const nav_metadata = self.navs.get(nav_index).?; const atom = self.getAtom(nav_metadata.index); const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(bw, sym); + try self.writeSym(w, sym); if (self.nav_exports.get(nav_index)) |export_indices| { for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); if (nav_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| { - try self.writeSym(bw, self.syms.items[exp_i]); + try self.writeSym(w, self.syms.items[exp_i]); } } } @@ -1248,7 +1248,7 @@ pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { const meta = kv.value_ptr; const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue; const sym = self.syms.items[data_atom.sym_index.?]; - try self.writeSym(bw, sym); + try self.writeSym(w, sym); } } // text symbols are the hardest: @@ -1259,8 +1259,8 @@ pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { while (it_file.next()) |fentry| { var symidx_and_submap = fentry.value_ptr; // write the z symbols - try self.writeSym(bw, self.syms.items[symidx_and_submap.sym_index - 1]); - try self.writeSym(bw, self.syms.items[symidx_and_submap.sym_index]); + try self.writeSym(w, self.syms.items[symidx_and_submap.sym_index - 1]); + try self.writeSym(w, self.syms.items[symidx_and_submap.sym_index]); // write all the decls come from the file of the z symbol var submap_it = symidx_and_submap.functions.iterator(); @@ -1269,7 +1269,7 @@ pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { const nav_metadata = self.navs.get(nav_index).?; const atom = self.getAtom(nav_metadata.index); const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(bw, sym); + try self.writeSym(w, sym); if (self.nav_exports.get(nav_index)) |export_indices| { for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); @@ -1277,7 +1277,7 @@ pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { const s = self.syms.items[exp_i]; if (mem.eql(u8, s.name, "_start")) self.entry_val = s.value; - try self.writeSym(bw, s); + try self.writeSym(w, s); } } } @@ -1290,7 +1290,7 @@ pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { const meta = kv.value_ptr; const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue; const sym = self.syms.items[text_atom.sym_index.?]; - try self.writeSym(bw, sym); + try self.writeSym(w, sym); } } } @@ -1299,7 +1299,7 @@ pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { if (idx) |atom_idx| { const atom = self.getAtom(atom_idx); const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(bw, sym); + try self.writeSym(w, sym); } } } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 0a8c3b6c6f..084146acea 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -28,6 +28,7 @@ const fs = std.fs; const leb = std.leb; const log = std.log.scoped(.link); const mem = std.mem; +const Writer = std.io.Writer; const Mir = @import("../arch/wasm/Mir.zig"); const CodeGen = @import("../arch/wasm/CodeGen.zig"); @@ -2124,8 +2125,8 @@ pub const FunctionType = extern struct { wasm: *const Wasm, ft: FunctionType, - pub fn format(self: Formatter, bw: *std.io.BufferedWriter, comptime format_string: []const u8) std.io.Writer.Error!void { - if (format_string.len != 0) std.fmt.invalidFmtError(format_string, self); + pub fn format(self: Formatter, bw: *Writer, comptime format_string: []const u8) Writer.Error!void { + comptime assert(format_string.len == 0); const params = self.ft.params.slice(self.wasm); const returns = self.ft.returns.slice(self.wasm); @@ -2904,7 +2905,7 @@ pub const Feature = packed struct(u8) { @"=", }; - pub fn format(feature: Feature, bw: *std.io.BufferedWriter, comptime fmt: []const u8) std.io.Writer.Error!void { + pub fn format(feature: Feature, bw: *Writer, comptime fmt: []const u8) Writer.Error!void { _ = fmt; try bw.print("{s} {s}", .{ @tagName(feature.prefix), @tagName(feature.tag) }); } @@ -3037,8 +3038,7 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void { const stat = try obj.file.stat(); const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig; - var br: std.io.Reader = undefined; - br.initFixed(try gpa.alloc(u8, size)); + var br: std.io.Reader = .fixed(try gpa.alloc(u8, size)); defer gpa.free(br.storageBuffer()); const n = try obj.file.preadAll(br.storageBuffer(), 0); diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 237abd6911..1e9cdc513f 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -18,6 +18,7 @@ const Allocator = std.mem.Allocator; const mem = std.mem; const log = std.log.scoped(.link); const assert = std.debug.assert; +const Writer = std.io.Writer; /// Ordered list of data segments that will appear in the final binary. /// When sorted, to-be-merged segments will be made adjacent. @@ -557,11 +558,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { var data_section_index: ?u32 = null; assert(f.binary_bytes.items.len == 0); - var aw: std.io.AllocatingWriter = undefined; - const bw = aw.fromArrayList(gpa, &f.binary_bytes); + var aw: std.io.AllocatingWriter = .fromArrayList(gpa, &f.binary_bytes); defer f.binary_bytes = aw.toArrayList(); + const w = &aw.interface; - try bw.writeAll(&std.wasm.magic ++ &std.wasm.version); + try w.writeAll(&std.wasm.magic ++ &std.wasm.version); // Type section. for (f.function_imports.values()) |id| { @@ -571,16 +572,16 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { try f.func_types.put(gpa, function.typeIndex(wasm), {}); } if (f.func_types.entries.len != 0) { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); for (f.func_types.keys()) |func_type_index| { const func_type = func_type_index.ptr(wasm); - try bw.writeLeb128(std.wasm.function_type); + try w.writeLeb128(std.wasm.function_type); const params = func_type.params.slice(wasm); - try bw.writeLeb128(params.len); - for (params) |param_ty| try bw.writeLeb128(@intFromEnum(param_ty)); + try w.writeLeb128(params.len); + for (params) |param_ty| try w.writeLeb128(@intFromEnum(param_ty)); const returns = func_type.returns.slice(wasm); - try bw.writeLeb128(returns.len); - for (returns) |ret_ty| try bw.writeLeb128(@intFromEnum(ret_ty)); + try w.writeLeb128(returns.len); + for (returns) |ret_ty| try w.writeLeb128(@intFromEnum(ret_ty)); } replaceVecSectionHeader(&aw, header_offset, .type, @intCast(f.func_types.entries.len)); section_index += 1; @@ -595,42 +596,42 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Import section { var total_imports: usize = 0; - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); for (f.function_imports.values()) |id| { const module_name = id.moduleName(wasm).slice(wasm).?; - try bw.writeLeb128(module_name.len); - try bw.writeAll(module_name); + try w.writeLeb128(module_name.len); + try w.writeAll(module_name); const name = id.importName(wasm).slice(wasm); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(name.len); + try w.writeAll(name); - try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); + try w.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); const type_index: FuncTypeIndex = .fromTypeIndex(id.functionType(wasm), f); - try bw.writeLeb128(@intFromEnum(type_index)); + try w.writeLeb128(@intFromEnum(type_index)); } total_imports += f.function_imports.entries.len; for (wasm.table_imports.values()) |id| { const table_import = id.value(wasm); const module_name = table_import.module_name.slice(wasm); - try bw.writeLeb128(module_name.len); - try bw.writeAll(module_name); + try w.writeLeb128(module_name.len); + try w.writeAll(module_name); const name = table_import.name.slice(wasm); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(name.len); + try w.writeAll(name); - try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); - try bw.writeLeb128(@intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to()))); - try emitLimits(bw, table_import.limits()); + try w.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); + try w.writeLeb128(@intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to()))); + try emitLimits(w, table_import.limits()); } total_imports += wasm.table_imports.entries.len; if (import_memory) { const name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory; - try emitMemoryImport(wasm, bw, name, &.{ + try emitMemoryImport(wasm, w, name, &.{ // TODO the import_memory option needs to specify from which module .module_name = wasm.object_host_name.unwrap().?, .limits_min = wasm.memories.limits.min, @@ -644,17 +645,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { for (f.global_imports.values()) |id| { const module_name = id.moduleName(wasm).slice(wasm).?; - try bw.writeLeb128(module_name.len); - try bw.writeAll(module_name); + try w.writeLeb128(module_name.len); + try w.writeAll(module_name); const name = id.importName(wasm).slice(wasm); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(name.len); + try w.writeAll(name); - try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); + try w.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); const global_type = id.globalType(wasm); - try bw.writeLeb128(@intFromEnum(global_type.valtype)); - try bw.writeByte(@intFromBool(global_type.mutable)); + try w.writeLeb128(@intFromEnum(global_type.valtype)); + try w.writeByte(@intFromBool(global_type.mutable)); } total_imports += f.global_imports.entries.len; @@ -668,10 +669,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Function section if (wasm.functions.count() != 0) { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); for (wasm.functions.keys()) |function| { const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f); - try bw.writeLeb128(@intFromEnum(index)); + try w.writeLeb128(@intFromEnum(index)); } replaceVecSectionHeader(&aw, header_offset, .function, @intCast(wasm.functions.count())); @@ -680,11 +681,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Table section if (wasm.tables.entries.len > 0) { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); for (wasm.tables.keys()) |table| { - try bw.writeLeb128(@intFromEnum(table.refType(wasm))); - try emitLimits(bw, table.limits(wasm)); + try w.writeLeb128(@intFromEnum(table.refType(wasm))); + try emitLimits(w, table.limits(wasm)); } replaceVecSectionHeader(&aw, header_offset, .table, @intCast(wasm.tables.entries.len)); @@ -693,8 +694,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Memory section. wasm currently only supports 1 linear memory segment. if (!import_memory) { - const header_offset = try reserveVecSectionHeader(bw); - try emitLimits(bw, wasm.memories.limits); + const header_offset = try reserveVecSectionHeader(w); + try emitLimits(w, wasm.memories.limits); replaceVecSectionHeader(&aw, header_offset, .memory, 1); section_index += 1; } @@ -702,24 +703,24 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Global section. const globals_len: u32 = @intCast(wasm.globals.entries.len); if (globals_len > 0) { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); for (wasm.globals.keys()) |global_resolution| { switch (global_resolution.unpack(wasm)) { .unresolved => unreachable, - .__heap_base => try appendGlobal(bw, false, virtual_addrs.heap_base), - .__heap_end => try appendGlobal(bw, false, virtual_addrs.heap_end), - .__stack_pointer => try appendGlobal(bw, true, virtual_addrs.stack_pointer), - .__tls_align => try appendGlobal(bw, false, @intCast(virtual_addrs.tls_align.toByteUnits().?)), - .__tls_base => try appendGlobal(bw, true, virtual_addrs.tls_base.?), - .__tls_size => try appendGlobal(bw, false, virtual_addrs.tls_size.?), + .__heap_base => try appendGlobal(w, false, virtual_addrs.heap_base), + .__heap_end => try appendGlobal(w, false, virtual_addrs.heap_end), + .__stack_pointer => try appendGlobal(w, true, virtual_addrs.stack_pointer), + .__tls_align => try appendGlobal(w, false, @intCast(virtual_addrs.tls_align.toByteUnits().?)), + .__tls_base => try appendGlobal(w, true, virtual_addrs.tls_base.?), + .__tls_size => try appendGlobal(w, false, virtual_addrs.tls_size.?), .object_global => |i| { const global = i.ptr(wasm); - try bw.writeAll(&.{ + try w.writeAll(&.{ @intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to())), @intFromBool(global.flags.global_type.mutable), }); - try emitExpr(wasm, bw, global.expr); + try emitExpr(wasm, w, global.expr); }, .nav_exe => unreachable, // Zig source code currently cannot represent this. .nav_obj => unreachable, // Zig source code currently cannot represent this. @@ -732,44 +733,44 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Export section { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); var exports_len: usize = 0; for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| { const name = exp_name.slice(wasm); - try bw.writeLeb128(name.len); - try bw.writeAll(name); - try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); + try w.writeLeb128(name.len); + try w.writeAll(name); + try w.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index); - try bw.writeLeb128(@intFromEnum(func_index)); + try w.writeLeb128(@intFromEnum(func_index)); } exports_len += wasm.function_exports.entries.len; if (wasm.export_table and f.indirect_function_table.entries.len > 0) { const name = "__indirect_function_table"; const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); - try bw.writeLeb128(name.len); - try bw.writeAll(name); - try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); - try bw.writeLeb128(index); + try w.writeLeb128(name.len); + try w.writeAll(name); + try w.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); + try w.writeLeb128(index); exports_len += 1; } if (export_memory) { const name = "memory"; - try bw.writeLeb128(name.len); - try bw.writeAll(name); - try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); - try bw.writeUleb128(0); + try w.writeLeb128(name.len); + try w.writeAll(name); + try w.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); + try w.writeUleb128(0); exports_len += 1; } for (wasm.global_exports.items) |exp| { const name = exp.name.slice(wasm); - try bw.writeLeb128(name.len); - try bw.writeAll(name); - try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); - try bw.writeLeb128(@intFromEnum(exp.global_index)); + try w.writeLeb128(name.len); + try w.writeAll(name); + try w.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); + try w.writeLeb128(@intFromEnum(exp.global_index)); } exports_len += wasm.global_exports.items.len; @@ -790,19 +791,19 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // element section if (f.indirect_function_table.entries.len > 0) { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); // indirect function table elements const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); // passive with implicit 0-index table or set table index manually const flags: u32 = if (table_index == 0) 0x0 else 0x02; - try bw.writeLeb128(flags); - if (flags == 0x02) try bw.writeLeb128(table_index); + try w.writeLeb128(flags); + if (flags == 0x02) try w.writeLeb128(table_index); // We start at index 1, so unresolved function pointers are invalid - try emitInit(bw, .{ .i32_const = 1 }); - if (flags == 0x02) try bw.writeUleb128(0); // represents funcref - try bw.writeLeb128(f.indirect_function_table.entries.len); - for (f.indirect_function_table.keys()) |func_index| try bw.writeLeb128(@intFromEnum(func_index)); + try emitInit(w, .{ .i32_const = 1 }); + if (flags == 0x02) try w.writeUleb128(0); // represents funcref + try w.writeLeb128(f.indirect_function_table.entries.len); + for (f.indirect_function_table.keys()) |func_index| try w.writeLeb128(@intFromEnum(func_index)); replaceVecSectionHeader(&aw, header_offset, .element, 1); section_index += 1; @@ -810,42 +811,42 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // When the shared-memory option is enabled, we *must* emit the 'data count' section. if (f.data_segment_groups.items.len > 0) { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); replaceVecSectionHeader(&aw, header_offset, .data_count, @intCast(f.data_segment_groups.items.len)); } // Code section. if (wasm.functions.count() != 0) { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); for (wasm.functions.keys()) |resolution| switch (resolution.unpack(wasm)) { .unresolved => unreachable, .__wasm_apply_global_tls_relocs => @panic("TODO lower __wasm_apply_global_tls_relocs"), .__wasm_call_ctors => { - const code_start = try reserveSizeHeader(bw); + const code_start = try reserveSizeHeader(w); defer replaceSizeHeader(&aw, code_start); - try emitCallCtorsFunction(wasm, bw); + try emitCallCtorsFunction(wasm, w); }, .__wasm_init_memory => { - const code_start = try reserveSizeHeader(bw); + const code_start = try reserveSizeHeader(w); defer replaceSizeHeader(&aw, code_start); - try emitInitMemoryFunction(wasm, bw, &virtual_addrs); + try emitInitMemoryFunction(wasm, w, &virtual_addrs); }, .__wasm_init_tls => { - const code_start = try reserveSizeHeader(bw); + const code_start = try reserveSizeHeader(w); defer replaceSizeHeader(&aw, code_start); - try emitInitTlsFunction(wasm, bw); + try emitInitTlsFunction(wasm, w); }, .object_function => |i| { const ptr = i.ptr(wasm); const code = ptr.code.slice(wasm); - try bw.writeLeb128(code.len); - const code_start = bw.count; - try bw.writeAll(code); + try w.writeLeb128(code.len); + const code_start = w.count; + try w.writeAll(code); if (!is_obj) applyRelocs(aw.getWritten()[code_start..], ptr.offset, ptr.relocations(wasm), wasm); }, .zcu_func => |i| { - const code_start = try reserveSizeHeader(bw); + const code_start = try reserveSizeHeader(w); defer replaceSizeHeader(&aw, code_start); log.debug("lowering function code for '{s}'", .{resolution.name(wasm).?}); @@ -855,7 +856,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { const ip_index = i.key(wasm).*; switch (ip.indexToKey(ip_index)) { .enum_type => { - try emitTagNameFunction(wasm, bw, f.data_segments.get(.__zig_tag_name_table).?, i.value(wasm).tag_name.table_index, ip_index); + try emitTagNameFunction(wasm, w, f.data_segments.get(.__zig_tag_name_table).?, i.value(wasm).tag_name.table_index, ip_index); }, else => { const func = i.value(wasm).function; @@ -870,7 +871,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .func_tys = undefined, .error_name_table_ref_count = undefined, }; - try mir.lower(wasm, bw); + try mir.lower(wasm, w); }, } }, @@ -912,7 +913,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Data section. if (f.data_segment_groups.items.len != 0) { - const header_offset = try reserveVecSectionHeader(bw); + const header_offset = try reserveVecSectionHeader(w); var group_index: u32 = 0; var segment_offset: u32 = 0; @@ -920,7 +921,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { var group_end_addr = f.data_segment_groups.items[group_index].end_addr; for (segment_ids, segment_vaddrs) |segment_id, segment_vaddr| { if (segment_vaddr >= group_end_addr) { - try bw.splatByteAll(0, group_end_addr - group_start_addr - segment_offset); + try w.splatByteAll(0, group_end_addr - group_start_addr - segment_offset); group_index += 1; if (group_index >= f.data_segment_groups.items.len) { // All remaining segments are zero. @@ -934,10 +935,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { const group_size = group_end_addr - group_start_addr; log.debug("emit data section group, {d} bytes", .{group_size}); const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active; - try bw.writeLeb128(@intFromEnum(flags)); + try w.writeLeb128(@intFromEnum(flags)); // Passive segments are initialized at runtime. - if (flags != .passive) try emitInit(bw, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) }); - try bw.writeLeb128(group_size); + if (flags != .passive) try emitInit(w, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) }); + try w.writeLeb128(group_size); } if (segment_id.isEmpty(wasm)) { // It counted for virtual memory but it does not go into the binary. @@ -946,59 +947,59 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Padding for alignment. const needed_offset = segment_vaddr - group_start_addr; - try bw.splatByteAll(0, needed_offset - segment_offset); + try w.splatByteAll(0, needed_offset - segment_offset); segment_offset = needed_offset; - const code_start = bw.count; + const code_start = w.count; append: { const code = switch (segment_id.unpack(wasm)) { .__heap_base => { - try bw.writeInt(u32, virtual_addrs.heap_base, .little); + try w.writeInt(u32, virtual_addrs.heap_base, .little); break :append; }, .__heap_end => { - try bw.writeInt(u32, virtual_addrs.heap_end, .little); + try w.writeInt(u32, virtual_addrs.heap_end, .little); break :append; }, .__zig_error_names => { - try bw.writeAll(wasm.error_name_bytes.items); + try w.writeAll(wasm.error_name_bytes.items); break :append; }, .__zig_error_name_table => { if (is_obj) @panic("TODO error name table reloc"); const base = f.data_segments.get(.__zig_error_names).?; if (!is64) { - try emitTagNameTable(bw, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32); + try emitTagNameTable(w, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32); } else { - try emitTagNameTable(bw, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64); + try emitTagNameTable(w, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64); } break :append; }, .__zig_tag_names => { - try bw.writeAll(wasm.tag_name_bytes.items); + try w.writeAll(wasm.tag_name_bytes.items); break :append; }, .__zig_tag_name_table => { if (is_obj) @panic("TODO tag name table reloc"); const base = f.data_segments.get(.__zig_tag_names).?; if (!is64) { - try emitTagNameTable(bw, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32); + try emitTagNameTable(w, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32); } else { - try emitTagNameTable(bw, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u64); + try emitTagNameTable(w, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u64); } break :append; }, .object => |i| { const ptr = i.ptr(wasm); - try bw.writeAll(ptr.payload.slice(wasm)); + try w.writeAll(ptr.payload.slice(wasm)); if (!is_obj) applyRelocs(aw.getWritten()[code_start..], ptr.offset, ptr.relocations(wasm), wasm); break :append; }, inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code, }; - try bw.writeAll(code.slice(wasm)); + try w.writeAll(code.slice(wasm)); } - segment_offset += @intCast(bw.count - code_start); + segment_offset += @intCast(w.count - code_start); } replaceVecSectionHeader(&aw, header_offset, .data, @intCast(f.data_segment_groups.items.len)); @@ -1019,7 +1020,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .none => {}, .fast => { var id: [16]u8 = undefined; - std.crypto.hash.sha3.TurboShake128(null).hash(bw.getWritten(), &id, .{}); + std.crypto.hash.sha3.TurboShake128(null).hash(w.getWritten(), &id, .{}); var uuid: [36]u8 = undefined; _ = try std.fmt.bufPrint(&uuid, "{x}-{x}-{x}-{x}-{x}", .{ id[0..4], id[4..6], id[6..8], id[8..10], id[10..], @@ -1067,62 +1068,62 @@ fn emitNameSection( data_segment_groups: []const DataSegmentGroup, ) !void { const f = &wasm.flush_buffer; - const bw = &aw.buffered_writer; - const header_offset = try reserveSectionHeader(bw); + const w = &aw.interface; + const header_offset = try reserveSectionHeader(w); defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); const section_name = "name"; - try bw.writeLeb128(section_name.len); - try bw.writeAll(section_name); + try w.writeLeb128(section_name.len); + try w.writeAll(section_name); { - const sub_header_offset = try reserveSectionHeader(bw); + const sub_header_offset = try reserveSectionHeader(w); defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.function)); - try bw.writeLeb128(f.function_imports.entries.len + wasm.functions.entries.len); + try w.writeLeb128(f.function_imports.entries.len + wasm.functions.entries.len); for (f.function_imports.keys(), 0..) |name_index, function_index| { const name = name_index.slice(wasm); - try bw.writeLeb128(function_index); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(function_index); + try w.writeLeb128(name.len); + try w.writeAll(name); } for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| { const name = resolution.name(wasm).?; - try bw.writeLeb128(function_index); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(function_index); + try w.writeLeb128(name.len); + try w.writeAll(name); } } { - const sub_header_offset = try reserveSectionHeader(bw); + const sub_header_offset = try reserveSectionHeader(w); defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.global)); - try bw.writeLeb128(f.global_imports.entries.len + wasm.globals.entries.len); + try w.writeLeb128(f.global_imports.entries.len + wasm.globals.entries.len); for (f.global_imports.keys(), 0..) |name_index, global_index| { const name = name_index.slice(wasm); - try bw.writeLeb128(global_index); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(global_index); + try w.writeLeb128(name.len); + try w.writeAll(name); } for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| { const name = resolution.name(wasm).?; - try bw.writeLeb128(global_index); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(global_index); + try w.writeLeb128(name.len); + try w.writeAll(name); } } { - const sub_header_offset = try reserveSectionHeader(bw); + const sub_header_offset = try reserveSectionHeader(w); defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.data_segment)); - try bw.writeLeb128(data_segment_groups.len); + try w.writeLeb128(data_segment_groups.len); for (data_segment_groups, 0..) |group, group_index| { const name, _ = splitSegmentName(group.first_segment.name(wasm)); - try bw.writeLeb128(group_index); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(group_index); + try w.writeLeb128(name.len); + try w.writeAll(name); } } } @@ -1131,87 +1132,87 @@ fn emitFeaturesSection(aw: *std.io.AllocatingWriter, target: *const std.Target) const feature_count = target.cpu.features.count(); if (feature_count == 0) return; - const bw = &aw.buffered_writer; - const header_offset = try reserveSectionHeader(bw); + const w = &aw.interface; + const header_offset = try reserveSectionHeader(w); defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); const section_name = "target_features"; - try bw.writeLeb128(section_name.len); - try bw.writeAll(section_name); + try w.writeLeb128(section_name.len); + try w.writeAll(section_name); - try bw.writeLeb128(feature_count); + try w.writeLeb128(feature_count); var safety_count = feature_count; for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| { if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue; safety_count -= 1; - try bw.writeUleb128('+'); + try w.writeUleb128('+'); // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions. const name = feature.llvm_name.?; - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(name.len); + try w.writeAll(name); } assert(safety_count == 0); } fn emitBuildIdSection(aw: *std.io.AllocatingWriter, build_id: []const u8) !void { - const bw = &aw.buffered_writer; - const header_offset = try reserveSectionHeader(bw); + const w = &aw.interface; + const header_offset = try reserveSectionHeader(w); defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); const section_name = "build_id"; - try bw.writeLeb128(section_name.len); - try bw.writeAll(section_name); + try w.writeLeb128(section_name.len); + try w.writeAll(section_name); - try bw.writeUleb128(1); - try bw.writeLeb128(build_id.len); - try bw.writeAll(build_id); + try w.writeUleb128(1); + try w.writeLeb128(build_id.len); + try w.writeAll(build_id); } fn emitProducerSection(aw: *std.io.AllocatingWriter) !void { - const bw = &aw.buffered_writer; - const header_offset = try reserveSectionHeader(bw); + const w = &aw.interface; + const header_offset = try reserveSectionHeader(w); defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); const section_name = "producers"; - try bw.writeLeb128(section_name.len); - try bw.writeAll(section_name); + try w.writeLeb128(section_name.len); + try w.writeAll(section_name); - try bw.writeUleb128(2); // 2 fields: language + processed-by + try w.writeUleb128(2); // 2 fields: language + processed-by { const field_name = "language"; - try bw.writeLeb128(field_name.len); - try bw.writeAll(field_name); + try w.writeLeb128(field_name.len); + try w.writeAll(field_name); // field_value_count (TODO: Parse object files for producer sections to detect their language) - try bw.writeUleb128(1); + try w.writeUleb128(1); // versioned name { const field_value = "Zig"; - try bw.writeLeb128(field_value.len); - try bw.writeAll(field_value); + try w.writeLeb128(field_value.len); + try w.writeAll(field_value); - try bw.writeLeb128(build_options.version.len); - try bw.writeAll(build_options.version); + try w.writeLeb128(build_options.version.len); + try w.writeAll(build_options.version); } } { const field_name = "processed-by"; - try bw.writeLeb128(field_name.len); - try bw.writeAll(field_name); + try w.writeLeb128(field_name.len); + try w.writeAll(field_name); // field_value_count (TODO: Parse object files for producer sections to detect other used tools) - try bw.writeUleb128(1); + try w.writeUleb128(1); // versioned name { const field_value = "Zig"; - try bw.writeLeb128(field_value.len); - try bw.writeAll(field_value); + try w.writeLeb128(field_value.len); + try w.writeAll(field_value); - try bw.writeLeb128(build_options.version.len); - try bw.writeAll(build_options.version); + try w.writeLeb128(build_options.version.len); + try w.writeAll(build_options.version); } } } @@ -1251,9 +1252,9 @@ fn wantSegmentMerge( /// section id + fixed leb contents size + fixed leb vector length const vec_section_header_size = section_header_size + size_header_size; -fn reserveVecSectionHeader(bw: *std.io.BufferedWriter) std.io.Writer.Error!u32 { - const offset = bw.count; - _ = try bw.writableSlice(vec_section_header_size); +fn reserveVecSectionHeader(w: *Writer) Writer.Error!u32 { + const offset = w.count; + _ = try w.writableSlice(vec_section_header_size); return @intCast(offset); } @@ -1265,68 +1266,68 @@ fn replaceVecSectionHeader( ) void { const header = aw.getWritten()[offset..][0..vec_section_header_size]; header[0] = @intFromEnum(section); - std.leb.writeUnsignedFixed(5, header[1..6], @intCast(aw.buffered_writer.count - offset - section_header_size)); + std.leb.writeUnsignedFixed(5, header[1..6], @intCast(aw.interface.count - offset - section_header_size)); std.leb.writeUnsignedFixed(5, header[6..], n_items); } const section_header_size = 1 + size_header_size; -fn reserveSectionHeader(bw: *std.io.BufferedWriter) std.io.Writer.Error!u32 { - const offset = bw.count; - _ = try bw.writableSlice(section_header_size); +fn reserveSectionHeader(w: *Writer) Writer.Error!u32 { + const offset = w.count; + _ = try w.writableSlice(section_header_size); return @intCast(offset); } fn replaceSectionHeader(aw: *std.io.AllocatingWriter, offset: u32, section: u8) void { const header = aw.getWritten()[offset..][0..section_header_size]; header[0] = section; - std.leb.writeUnsignedFixed(5, header[1..6], @intCast(aw.buffered_writer.count - offset - section_header_size)); + std.leb.writeUnsignedFixed(5, header[1..6], @intCast(aw.interface.count - offset - section_header_size)); } const size_header_size = 5; -fn reserveSizeHeader(bw: *std.io.BufferedWriter) std.io.Writer.Error!u32 { - const offset = bw.count; - _ = try bw.writableSlice(size_header_size); +fn reserveSizeHeader(w: *Writer) Writer.Error!u32 { + const offset = w.count; + _ = try w.writableSlice(size_header_size); return @intCast(offset); } fn replaceSizeHeader(aw: *std.io.AllocatingWriter, offset: u32) void { const header = aw.getWritten()[offset..][0..size_header_size]; - std.leb.writeUnsignedFixed(5, header[0..5], @intCast(aw.buffered_writer.count - offset - size_header_size)); + std.leb.writeUnsignedFixed(5, header[0..5], @intCast(aw.interface.count - offset - size_header_size)); } -fn emitLimits(bw: *std.io.BufferedWriter, limits: std.wasm.Limits) std.io.Writer.Error!void { - try bw.writeByte(@bitCast(limits.flags)); - try bw.writeLeb128(limits.min); - if (limits.flags.has_max) try bw.writeLeb128(limits.max); +fn emitLimits(w: *Writer, limits: std.wasm.Limits) Writer.Error!void { + try w.writeByte(@bitCast(limits.flags)); + try w.writeLeb128(limits.min); + if (limits.flags.has_max) try w.writeLeb128(limits.max); } fn emitMemoryImport( wasm: *Wasm, - bw: *std.io.BufferedWriter, + w: *Writer, name_index: String, memory_import: *const Wasm.MemoryImport, -) std.io.Writer.Error!void { +) Writer.Error!void { const module_name = memory_import.module_name.slice(wasm); - try bw.writeLeb128(module_name.len); - try bw.writeAll(module_name); + try w.writeLeb128(module_name.len); + try w.writeAll(module_name); const name = name_index.slice(wasm); - try bw.writeLeb128(name.len); - try bw.writeAll(name); + try w.writeLeb128(name.len); + try w.writeAll(name); - try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); - try emitLimits(bw, memory_import.limits()); + try w.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); + try emitLimits(w, memory_import.limits()); } -pub fn emitInit(bw: *std.io.BufferedWriter, init_expr: std.wasm.InitExpression) std.io.Writer.Error!void { +pub fn emitInit(w: *Writer, init_expr: std.wasm.InitExpression) Writer.Error!void { switch (init_expr) { inline else => |val, tag| { - try bw.writeByte(@intFromEnum(@field(std.wasm.Opcode, @tagName(tag)))); + try w.writeByte(@intFromEnum(@field(std.wasm.Opcode, @tagName(tag)))); switch (@typeInfo(@TypeOf(val))) { - .int => try bw.writeLeb128(val), - .float => |float| try bw.writeInt( + .int => try w.writeLeb128(val), + .float => |float| try w.writeInt( @Type(.{ .int = .{ .signedness = .unsigned, .bits = float.bits } }), @bitCast(val), .little, @@ -1335,44 +1336,44 @@ pub fn emitInit(bw: *std.io.BufferedWriter, init_expr: std.wasm.InitExpression) } }, } - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); } -pub fn emitExpr(wasm: *const Wasm, bw: *std.io.BufferedWriter, expr: Wasm.Expr) std.io.Writer.Error!void { +pub fn emitExpr(wasm: *const Wasm, w: *Writer, expr: Wasm.Expr) Writer.Error!void { const slice = expr.slice(wasm); - try bw.writeAll(slice[0 .. slice.len + 1]); // +1 to include end opcode + try w.writeAll(slice[0 .. slice.len + 1]); // +1 to include end opcode } -fn emitSegmentInfo(wasm: *Wasm, aw: *std.io.BufferedWriter) std.io.Writer.Error!void { - const bw = &aw.buffered_writer; - const header_offset = try reserveSectionHeader(bw); +fn emitSegmentInfo(wasm: *Wasm, aw: *Writer) Writer.Error!void { + const w = &aw.interface; + const header_offset = try reserveSectionHeader(w); defer replaceSectionHeader(aw, header_offset, @intFromEnum(Wasm.SubsectionType.segment_info)); - try bw.writeLeb128(wasm.segment_info.count()); + try w.writeLeb128(wasm.segment_info.count()); for (wasm.segment_info.values()) |segment_info| { log.debug("Emit segment: {s} align({d}) flags({b})", .{ segment_info.name, segment_info.alignment, segment_info.flags, }); - try bw.writeLeb128(segment_info.name.len); - try bw.writeAll(segment_info.name); - try bw.writeLeb128(segment_info.alignment.toLog2Units()); - try bw.writeLeb128(segment_info.flags); + try w.writeLeb128(segment_info.name.len); + try w.writeAll(segment_info.name); + try w.writeLeb128(segment_info.alignment.toLog2Units()); + try w.writeLeb128(segment_info.flags); } } fn emitTagNameTable( - bw: *std.io.BufferedWriter, + w: *Writer, tag_name_offs: []const u32, tag_name_bytes: []const u8, base: u32, comptime Int: type, -) std.io.Writer.Error!void { +) Writer.Error!void { for (tag_name_offs) |off| { const name_len: u32 = @intCast(mem.indexOfScalar(u8, tag_name_bytes[off..], 0).?); - try bw.writeInt(Int, base + off, .little); - try bw.writeInt(Int, name_len, .little); + try w.writeInt(Int, base + off, .little); + try w.writeInt(Int, name_len, .little); } } @@ -1536,8 +1537,8 @@ fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void { std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index)); } -fn emitCallCtorsFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { - try bw.writeUleb128(0); // no locals +fn emitCallCtorsFunction(wasm: *const Wasm, w: *Writer) Writer.Error!void { + try w.writeUleb128(0); // no locals for (wasm.object_init_funcs.items) |init_func| { const func = init_func.function_index.ptr(wasm); if (!func.object_index.ptr(wasm).is_included) continue; @@ -1546,16 +1547,16 @@ fn emitCallCtorsFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter) std.io.W // Call function by its function index const call_index: Wasm.OutputFunctionIndex = .fromObjectFunction(wasm, init_func.function_index); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.call)); - try bw.writeLeb128(@intFromEnum(call_index)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.call)); + try w.writeLeb128(@intFromEnum(call_index)); // drop all returned values from the stack as __wasm_call_ctors has no return value - try bw.splatByteAll(@intFromEnum(std.wasm.Opcode.drop), n_returns); + try w.splatByteAll(@intFromEnum(std.wasm.Opcode.drop), n_returns); } - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end function body + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end function body } -fn emitInitMemoryFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter, virtual_addrs: *const VirtualAddrs) std.io.Writer.Error!void { +fn emitInitMemoryFunction(wasm: *const Wasm, w: *Writer, virtual_addrs: *const VirtualAddrs) Writer.Error!void { const comp = wasm.base.comp; const shared_memory = comp.config.shared_memory; @@ -1566,13 +1567,13 @@ fn emitInitMemoryFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter, virtual // function. assert(wasm.any_passive_inits); - try bw.writeUleb128(0); // no locals + try w.writeUleb128(0); // no locals if (virtual_addrs.init_memory_flag) |flag_address| { assert(shared_memory); // destination blocks // based on values we jump to corresponding label - try bw.writeAll(&.{ + try w.writeAll(&.{ @intFromEnum(std.wasm.Opcode.block), // $drop @intFromEnum(std.wasm.BlockType.empty), @intFromEnum(std.wasm.Opcode.block), // $wait @@ -1582,24 +1583,24 @@ fn emitInitMemoryFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter, virtual }); // atomically check - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(flag_address))); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeSleb128(0); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeSleb128(1); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - try bw.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_rmw_cmpxchg)); - try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); - try bw.writeUleb128(0); // offset + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(flag_address))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeSleb128(0); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeSleb128(1); + try w.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try w.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_rmw_cmpxchg)); + try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try w.writeUleb128(0); // offset // based on the value from the atomic check, jump to the label. - try bw.writeByte(@intFromEnum(std.wasm.Opcode.br_table)); - try bw.writeUleb128(3 - 1); // length of the table (we have 3 blocks but because of the mandatory default the length is 2). - try bw.writeUleb128(0); // $init - try bw.writeUleb128(1); // $wait - try bw.writeUleb128(2); // $drop - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.br_table)); + try w.writeUleb128(3 - 1); // length of the table (we have 3 blocks but because of the mandatory default the length is 2). + try w.writeUleb128(0); // $init + try w.writeUleb128(1); // $wait + try w.writeUleb128(2); // $drop + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); } const segment_groups = wasm.flush_buffer.data_segment_groups.items; @@ -1615,79 +1616,79 @@ fn emitInitMemoryFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter, virtual // For passive BSS segments we can simply issue a memory.fill(0). For // non-BSS segments we do a memory.init. Both instructions take as // their first argument the destination address. - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(start_addr))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(start_addr))); if (shared_memory and segment.isTls(wasm)) { // When we initialize the TLS segment we also set the `__tls_base` // global. This allows the runtime to use this static copy of the // TLS data for the first/main thread. - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(start_addr))); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); - try bw.writeLeb128(virtual_addrs.tls_base.?); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(start_addr))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); + try w.writeLeb128(virtual_addrs.tls_base.?); } - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeSleb128(0); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(segment_size))); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeSleb128(0); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(segment_size))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); if (segment.isBss(wasm)) { // fill bss segment with zeroes - try bw.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_fill)); + try w.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_fill)); } else { // initialize the segment - try bw.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_init)); - try bw.writeLeb128(segment_index); + try w.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_init)); + try w.writeLeb128(segment_index); } - try bw.writeByte(0); // memory index immediate + try w.writeByte(0); // memory index immediate } if (virtual_addrs.init_memory_flag) |flag_address| { assert(shared_memory); // we set the init memory flag to value '2' - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(flag_address))); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeSleb128(2); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - try bw.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_store)); - try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); - try bw.writeUleb128(0); // offset + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(flag_address))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeSleb128(2); + try w.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try w.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_store)); + try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try w.writeUleb128(0); // offset // notify any waiters for segment initialization completion - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(flag_address))); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeSleb128(-1); // number of waiters + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(flag_address))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeSleb128(-1); // number of waiters - try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - try bw.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify)); - try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); - try bw.writeUleb128(0); // offset - try bw.writeByte(@intFromEnum(std.wasm.Opcode.drop)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try w.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify)); + try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try w.writeUleb128(0); // offset + try w.writeByte(@intFromEnum(std.wasm.Opcode.drop)); // branch and drop segments - try bw.writeByte(@intFromEnum(std.wasm.Opcode.br)); - try bw.writeUleb128(1); + try w.writeByte(@intFromEnum(std.wasm.Opcode.br)); + try w.writeUleb128(1); // wait for thread to initialize memory segments - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end $wait - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(flag_address))); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeSleb128(1); // expected flag value - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); - try bw.writeSleb128(-1); // timeout - try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - try bw.writeByte(@intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32)); - try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); - try bw.writeUleb128(0); // offset - try bw.writeByte(@intFromEnum(std.wasm.Opcode.drop)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end $wait + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(flag_address))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeSleb128(1); // expected flag value + try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); + try w.writeSleb128(-1); // timeout + try w.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try w.writeByte(@intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32)); + try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try w.writeUleb128(0); // offset + try w.writeByte(@intFromEnum(std.wasm.Opcode.drop)); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end $drop + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end $drop } for (segment_groups, 0..) |group, segment_index| { @@ -1698,20 +1699,20 @@ fn emitInitMemoryFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter, virtual // during the initialization of each thread (__wasm_init_tls). if (shared_memory and segment.isTls(wasm)) continue; - try bw.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); - try bw.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.data_drop)); - try bw.writeLeb128(segment_index); + try w.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); + try w.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.data_drop)); + try w.writeLeb128(segment_index); } // End of the function body - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); } -fn emitInitTlsFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn emitInitTlsFunction(wasm: *const Wasm, w: *Writer) Writer.Error!void { const comp = wasm.base.comp; assert(comp.config.shared_memory); - try bw.writeUleb128(0); // no locals + try w.writeUleb128(0); // no locals // If there's a TLS segment, initialize it during runtime using the bulk-memory feature // TLS segment is always the first one due to how we sort the data segments. @@ -1724,31 +1725,31 @@ fn emitInitTlsFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter) std.io.Wri const param_local: u32 = 0; - try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); - try bw.writeLeb128(param_local); + try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try w.writeLeb128(param_local); const tls_base_global_index: Wasm.GlobalIndex = @enumFromInt(wasm.globals.getIndex(.__tls_base).?); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); - try bw.writeLeb128(@intFromEnum(tls_base_global_index)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); + try w.writeLeb128(@intFromEnum(tls_base_global_index)); // load stack values for the bulk-memory operation { - try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); - try bw.writeLeb128(param_local); + try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try w.writeLeb128(param_local); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeSleb128(0); // segment offset + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeSleb128(0); // segment offset - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(group_size))); // segment offset + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(group_size))); // segment offset } // perform the bulk-memory operation to initialize the data segment - try bw.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); - try bw.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_init)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); + try w.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_init)); // segment immediate - try bw.writeLeb128(data_segment_index); - try bw.writeByte(0); // memory index immediate + try w.writeLeb128(data_segment_index); + try w.writeByte(0); // memory index immediate } // If we have to perform any TLS relocations, call the corresponding function @@ -1756,21 +1757,21 @@ fn emitInitTlsFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter) std.io.Wri // generated by the linker. if (wasm.functions.getIndex(.__wasm_apply_global_tls_relocs)) |function_index| { const output_function_index: Wasm.OutputFunctionIndex = .fromFunctionIndex(wasm, @enumFromInt(function_index)); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.call)); - try bw.writeLeb128(@intFromEnum(output_function_index)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.call)); + try w.writeLeb128(@intFromEnum(output_function_index)); } - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); } fn emitStartSection(aw: *std.io.AllocatingWriter, i: Wasm.OutputFunctionIndex) !void { - const header_offset = try reserveVecSectionHeader(&aw.buffered_writer); + const header_offset = try reserveVecSectionHeader(&aw.interface); defer replaceVecSectionHeader(aw, header_offset, .start, @intFromEnum(i)); } fn emitTagNameFunction( wasm: *Wasm, - bw: *std.io.BufferedWriter, + w: *Writer, table_base_addr: u32, table_index: u32, enum_type_ip: InternPool.Index, @@ -1782,33 +1783,33 @@ fn emitTagNameFunction( const enum_type = ip.loadEnumType(enum_type_ip); const tag_values = enum_type.values.get(ip); - try bw.writeUleb128(0); // no locals + try w.writeUleb128(0); // no locals const slice_abi_size: u32 = 8; if (tag_values.len == 0) { // Then it's auto-numbered and therefore a direct table lookup. - try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); - try bw.writeUleb128(0); + try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try w.writeUleb128(0); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); - try bw.writeUleb128(1); + try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try w.writeUleb128(1); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); if (std.math.isPowerOfTwo(slice_abi_size)) { - try bw.writeLeb128(@as(i32, @bitCast(@as(u32, std.math.log2_int(u32, slice_abi_size))))); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_shl)); + try w.writeLeb128(@as(i32, @bitCast(@as(u32, std.math.log2_int(u32, slice_abi_size))))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_shl)); } else { - try bw.writeLeb128(@as(i32, @bitCast(slice_abi_size))); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_mul)); + try w.writeLeb128(@as(i32, @bitCast(slice_abi_size))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_mul)); } - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_load)); - try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); - try bw.writeLeb128(table_base_addr + slice_abi_size * table_index); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_load)); + try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try w.writeLeb128(table_base_addr + slice_abi_size * table_index); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_store)); - try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); - try bw.writeUleb128(0); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_store)); + try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try w.writeUleb128(0); } else { const int_info = Zcu.Type.intInfo(.fromInterned(enum_type.tag_ty), zcu); const outer_block_type: std.wasm.BlockType = switch (int_info.bits) { @@ -1817,80 +1818,80 @@ fn emitTagNameFunction( else => return diags.fail("wasm linker does not yet implement @tagName for sparse enums with more than 64 bit integer tag types", .{}), }; - try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); - try bw.writeUleb128(0); + try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try w.writeUleb128(0); // Outer block that computes table offset. - try bw.writeByte(@intFromEnum(std.wasm.Opcode.block)); - try bw.writeByte(@intFromEnum(outer_block_type)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.block)); + try w.writeByte(@intFromEnum(outer_block_type)); for (tag_values, 0..) |tag_value, tag_index| { // block for this if case - try bw.writeByte(@intFromEnum(std.wasm.Opcode.block)); - try bw.writeByte(@intFromEnum(std.wasm.BlockType.empty)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.block)); + try w.writeByte(@intFromEnum(std.wasm.BlockType.empty)); // Tag value whose name should be returned. - try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); - try bw.writeUleb128(1); + try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try w.writeUleb128(1); const val: Zcu.Value = .fromInterned(tag_value); switch (outer_block_type) { .i32 => { - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, switch (int_info.signedness) { + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, switch (int_info.signedness) { .signed => @intCast(val.toSignedInt(zcu)), .unsigned => @bitCast(@as(u32, @intCast(val.toUnsignedInt(zcu)))), })); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_ne)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_ne)); }, .i64 => { - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); - try bw.writeLeb128(@as(i64, switch (int_info.signedness) { + try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); + try w.writeLeb128(@as(i64, switch (int_info.signedness) { .signed => val.toSignedInt(zcu), .unsigned => @bitCast(val.toUnsignedInt(zcu)), })); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_ne)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_ne)); }, else => unreachable, } // if they're not equal, break out of current branch - try bw.writeByte(@intFromEnum(std.wasm.Opcode.br_if)); - try bw.writeUleb128(0); + try w.writeByte(@intFromEnum(std.wasm.Opcode.br_if)); + try w.writeUleb128(0); // Put the table offset of the result on the stack. - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try bw.writeLeb128(@as(i32, @bitCast(@as(u32, @intCast(slice_abi_size * tag_index))))); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try w.writeLeb128(@as(i32, @bitCast(@as(u32, @intCast(slice_abi_size * tag_index))))); // break outside blocks - try bw.writeByte(@intFromEnum(std.wasm.Opcode.br)); - try bw.writeUleb128(1); + try w.writeByte(@intFromEnum(std.wasm.Opcode.br)); + try w.writeUleb128(1); // end the block for this case - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); } - try bw.writeByte(@intFromEnum(std.wasm.Opcode.@"unreachable")); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.@"unreachable")); + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_load)); - try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); - try bw.writeLeb128(table_base_addr + slice_abi_size * table_index); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_load)); + try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try w.writeLeb128(table_base_addr + slice_abi_size * table_index); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_store)); - try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); - try bw.writeUleb128(0); + try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_store)); + try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try w.writeUleb128(0); } // End of the function body - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); } -fn appendGlobal(bw: *std.io.BufferedWriter, mutable: bool, val: u32) std.io.Writer.Error!void { - try bw.writeAll(&.{ +fn appendGlobal(w: *Writer, mutable: bool, val: u32) Writer.Error!void { + try w.writeAll(&.{ @intFromEnum(std.wasm.Valtype.i32), @intFromBool(mutable), @intFromEnum(std.wasm.Opcode.i32_const), }); - try bw.writeLeb128(val); - try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try w.writeLeb128(val); + try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); } diff --git a/src/link/riscv.zig b/src/link/riscv.zig index 29bfdb3bde..bd7a877704 100644 --- a/src/link/riscv.zig +++ b/src/link/riscv.zig @@ -1,4 +1,4 @@ -pub fn writeSetSub6(comptime op: enum { set, sub }, addend: anytype, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn writeSetSub6(comptime op: enum { set, sub }, addend: anytype, bw: *Writer) Writer.Error!void { const mask: u8 = 0b11_000000; const actual: i8 = @truncate(addend); const old_value = (try bw.writableArray(1))[0]; @@ -9,7 +9,7 @@ pub fn writeSetSub6(comptime op: enum { set, sub }, addend: anytype, bw: *std.io try bw.writeByte(new_value); } -pub fn writeSetSubUleb(comptime op: enum { set, sub }, addend: i64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +pub fn writeSetSubUleb(comptime op: enum { set, sub }, addend: i64, bw: *Writer) Writer.Error!void { switch (op) { .set => try overwriteUleb(@intCast(addend), bw), .sub => { @@ -20,7 +20,7 @@ pub fn writeSetSubUleb(comptime op: enum { set, sub }, addend: i64, bw: *std.io. } } -fn overwriteUleb(new_value: u64, bw: *std.io.BufferedWriter) std.io.Writer.Error!void { +fn overwriteUleb(new_value: u64, bw: *Writer) Writer.Error!void { var value: u64 = new_value; while (true) { const byte = (try bw.writableArray(1))[0]; @@ -34,8 +34,8 @@ pub fn writeAddend( comptime Int: type, comptime op: enum { add, sub }, value: anytype, - bw: *std.io.BufferedWriter, -) std.io.Writer.Error!void { + bw: *Writer, +) Writer.Error!void { const n = @divExact(@bitSizeOf(Int), 8); var V: Int = mem.readInt(Int, (try bw.writableSliceGreedy(n))[0..n], .little); const addend: Int = @truncate(value); @@ -108,8 +108,9 @@ pub const Eflags = packed struct(u32) { }; }; -const mem = std.mem; const std = @import("std"); +const mem = std.mem; +const Writer = std.io.Writer; const encoding = @import("../arch/riscv64/encoding.zig"); const Instruction = encoding.Instruction; diff --git a/src/link/table_section.zig b/src/link/table_section.zig index ae2ccb7fbe..100aa9c2f7 100644 --- a/src/link/table_section.zig +++ b/src/link/table_section.zig @@ -39,7 +39,7 @@ pub fn TableSection(comptime Entry: type) type { return self.entries.items.len; } - pub fn format(self: Self, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) std.io.Writer.Error!void { + pub fn format(self: Self, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { comptime assert(unused_format_string.len == 0); try bw.writeAll("TableSection:\n"); for (self.entries.items, 0..) |entry, i| { @@ -57,3 +57,4 @@ const assert = std.debug.assert; const log = std.log.scoped(.link); const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; diff --git a/src/print_env.zig b/src/print_env.zig index f64a4acaf6..e76fceb3bd 100644 --- a/src/print_env.zig +++ b/src/print_env.zig @@ -22,8 +22,9 @@ pub fn cmdEnv(arena: Allocator, args: []const []const u8) !void { const triple = try host.zigTriple(arena); var buffer: [1024]u8 = undefined; - var bw: std.io.BufferedWriter = std.fs.File.stdout().writer().buffered(&buffer); - var jws: std.json.Stringify = .{ .writer = &bw, .options = .{ .whitespace = .indent_1 } }; + var stdout_writer = std.fs.File.stdout().writer(&buffer); + const w = &stdout_writer.interface(); + var jws: std.json.Stringify = .{ .writer = w, .options = .{ .whitespace = .indent_1 } }; try jws.beginObject(); @@ -54,7 +55,7 @@ pub fn cmdEnv(arena: Allocator, args: []const []const u8) !void { try jws.endObject(); try jws.endObject(); - try bw.writeByte('\n'); + try w.writeByte('\n'); - try bw.flush(); + try w.flush(); } diff --git a/src/print_targets.zig b/src/print_targets.zig index b089fae024..c46d11cd8a 100644 --- a/src/print_targets.zig +++ b/src/print_targets.zig @@ -10,6 +10,7 @@ const target = @import("target.zig"); const assert = std.debug.assert; const glibc = @import("libs/glibc.zig"); const introspect = @import("introspect.zig"); +const Writer = std.io.Writer; pub fn cmdTargets(arena: Allocator, args: []const []const u8) !void { _ = args; @@ -20,7 +21,7 @@ pub fn cmdTargets(arena: Allocator, args: []const []const u8) !void { try bw.flush(); } -fn print(arena: Allocator, output: *std.io.BufferedWriter, host: *const Target) std.io.Writer.Error!void { +fn print(arena: Allocator, output: *Writer, host: *const Target) Writer.Error!void { var zig_lib_directory = introspect.findZigLibDir(arena) catch |err| { fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)}); }; diff --git a/src/print_value.zig b/src/print_value.zig index bd73cd5ed2..4d3e29422b 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -9,6 +9,7 @@ const Sema = @import("Sema.zig"); const InternPool = @import("InternPool.zig"); const Allocator = std.mem.Allocator; const Target = std.Target; +const Writer = std.io.Writer; const max_aggregate_items = 100; const max_string_len = 256; @@ -20,7 +21,7 @@ pub const FormatContext = struct { depth: u8, }; -pub fn formatSema(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime fmt: []const u8) std.io.Writer.Error!void { +pub fn formatSema(ctx: FormatContext, bw: *Writer, comptime fmt: []const u8) std.io.Writer.Error!void { const sema = ctx.opt_sema.?; comptime std.debug.assert(fmt.len == 0); return print(ctx.val, bw, ctx.depth, ctx.pt, sema) catch |err| switch (err) { @@ -31,7 +32,7 @@ pub fn formatSema(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime fmt: }; } -pub fn format(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime fmt: []const u8) std.io.Writer.Error!void { +pub fn format(ctx: FormatContext, bw: *Writer, comptime fmt: []const u8) std.io.Writer.Error!void { std.debug.assert(ctx.opt_sema == null); comptime std.debug.assert(fmt.len == 0); return print(ctx.val, bw, ctx.depth, ctx.pt, null) catch |err| switch (err) { @@ -43,7 +44,7 @@ pub fn format(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime fmt: []co pub fn print( val: Value, - bw: *std.io.BufferedWriter, + bw: *Writer, level: u8, pt: Zcu.PerThread, opt_sema: ?*Sema, @@ -186,7 +187,7 @@ fn printAggregate( val: Value, aggregate: InternPool.Key.Aggregate, is_ref: bool, - bw: *std.io.BufferedWriter, + bw: *Writer, level: u8, pt: Zcu.PerThread, opt_sema: ?*Sema, @@ -272,7 +273,7 @@ fn printPtr( ptr_val: Value, /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen. want_kind: ?PrintPtrKind, - bw: *std.io.BufferedWriter, + bw: *Writer, level: u8, pt: Zcu.PerThread, opt_sema: ?*Sema, @@ -318,7 +319,7 @@ const PrintPtrKind = enum { lvalue, rvalue }; /// Returns the root derivation, which may be ignored. pub fn printPtrDerivation( derivation: Value.PointerDeriveStep, - bw: *std.io.BufferedWriter, + bw: *Writer, pt: Zcu.PerThread, /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen. /// If this is `.rvalue`, the result may look like `&foo`, so it's not necessarily valid to treat it as diff --git a/src/print_zir.zig b/src/print_zir.zig index 92d1014141..61fa2f56cf 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -10,7 +10,7 @@ const Zcu = @import("Zcu.zig"); const LazySrcLoc = Zcu.LazySrcLoc; /// Write human-readable, debug formatted ZIR code. -pub fn renderAsText(gpa: Allocator, tree: ?Ast, zir: Zir, bw: *std.io.BufferedWriter) !void { +pub fn renderAsText(gpa: Allocator, tree: ?Ast, zir: Zir, bw: *std.io.Writer) !void { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); @@ -57,7 +57,7 @@ pub fn renderInstructionContext( scope_file: *Zcu.File, parent_decl_node: Ast.Node.Index, indent: u32, - bw: *std.io.BufferedWriter, + bw: *std.io.Writer, ) !void { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); @@ -89,7 +89,7 @@ pub fn renderSingleInstruction( scope_file: *Zcu.File, parent_decl_node: Ast.Node.Index, indent: u32, - bw: *std.io.BufferedWriter, + bw: *std.io.Writer, ) !void { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); @@ -176,11 +176,11 @@ const Writer = struct { } } = .{}, - const Error = std.io.Writer.Error || std.mem.Allocator.Error; + const Error = std.io.Writer.Error || Allocator.Error; fn writeInstToStream( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const tags = self.code.instructions.items(.tag); @@ -510,7 +510,7 @@ const Writer = struct { } } - fn writeExtended(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeExtended(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const extended = self.code.instructions.items(.data)[@intFromEnum(inst)].extended; try stream.print("{s}(", .{@tagName(extended.opcode)}); switch (extended.opcode) { @@ -619,13 +619,13 @@ const Writer = struct { } } - fn writeExtNode(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeExtNode(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { try stream.writeAll(")) "); const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand))); try self.writeSrcNode(stream, src_node); } - fn writeArrayInitElemType(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeArrayInitElemType(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].bin; try self.writeInstRef(stream, inst_data.lhs); try stream.print(", {d})", .{@intFromEnum(inst_data.rhs)}); @@ -633,7 +633,7 @@ const Writer = struct { fn writeUnNode( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -644,7 +644,7 @@ const Writer = struct { fn writeUnTok( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].un_tok; @@ -655,7 +655,7 @@ const Writer = struct { fn writeValidateDestructure( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -669,7 +669,7 @@ const Writer = struct { fn writeValidateArrayInitTy( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -681,7 +681,7 @@ const Writer = struct { fn writeArrayTypeSentinel( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -697,7 +697,7 @@ const Writer = struct { fn writePtrType( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].ptr_type; @@ -740,12 +740,12 @@ const Writer = struct { try self.writeSrcNode(stream, extra.data.src_node); } - fn writeInt(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeInt(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].int; try stream.print("{d})", .{inst_data}); } - fn writeIntBig(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeIntBig(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str; const byte_count = inst_data.len * @sizeOf(std.math.big.Limb); const limb_bytes = self.code.string_bytes[@intFromEnum(inst_data.start)..][0..byte_count]; @@ -764,12 +764,12 @@ const Writer = struct { try stream.print("{s})", .{as_string}); } - fn writeFloat(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeFloat(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const number = self.code.instructions.items(.data)[@intFromEnum(inst)].float; try stream.print("{d})", .{number}); } - fn writeFloat128(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeFloat128(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; const number = extra.get(); @@ -780,7 +780,7 @@ const Writer = struct { fn writeStr( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str; @@ -788,7 +788,7 @@ const Writer = struct { try stream.print("\"{f}\")", .{std.zig.fmtEscapes(str)}); } - fn writeSliceStart(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeSliceStart(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data; try self.writeInstRef(stream, extra.lhs); @@ -798,7 +798,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeSliceEnd(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeSliceEnd(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data; try self.writeInstRef(stream, extra.lhs); @@ -810,7 +810,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeSliceSentinel(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeSliceSentinel(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data; try self.writeInstRef(stream, extra.lhs); @@ -824,7 +824,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeSliceLength(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeSliceLength(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data; try self.writeInstRef(stream, extra.lhs); @@ -840,7 +840,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeUnionInit(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeUnionInit(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; try self.writeInstRef(stream, extra.union_type); @@ -852,7 +852,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeShuffle(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeShuffle(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data; try self.writeInstRef(stream, extra.elem_type); @@ -866,7 +866,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeSelect(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeSelect(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.Select, extended.operand).data; try self.writeInstRef(stream, extra.elem_type); try stream.writeAll(", "); @@ -879,7 +879,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.node); } - fn writeMulAdd(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeMulAdd(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data; try self.writeInstRef(stream, extra.mulend1); @@ -891,7 +891,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeBuiltinCall(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeBuiltinCall(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data; @@ -907,7 +907,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeFieldParentPtr(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeFieldParentPtr(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.FieldParentPtr, extended.operand).data; const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?; const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small))); @@ -924,7 +924,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.src_node); } - fn writeBuiltinAsyncCall(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeBuiltinAsyncCall(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.AsyncCall, extended.operand).data; try self.writeInstRef(stream, extra.frame_buffer); try stream.writeAll(", "); @@ -937,7 +937,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.node); } - fn writeParam(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeParam(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok; const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index); const body = self.code.bodySlice(extra.end, extra.data.type.body_len); @@ -952,7 +952,7 @@ const Writer = struct { try self.writeSrcTok(stream, inst_data.src_tok); } - fn writePlNodeBin(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writePlNodeBin(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; try self.writeInstRef(stream, extra.lhs); @@ -962,7 +962,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writePlNodeMultiOp(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writePlNodeMultiOp(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); const args = self.code.refSlice(extra.end, extra.data.operands_len); @@ -975,7 +975,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeArrayMul(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeArrayMul(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data; try self.writeInstRef(stream, extra.res_ty); @@ -987,13 +987,13 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeElemValImm(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeElemValImm(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].elem_val_imm; try self.writeInstRef(stream, inst_data.operand); try stream.print(", {d})", .{inst_data.idx}); } - fn writeArrayInitElemPtr(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeArrayInitElemPtr(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; @@ -1002,7 +1002,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writePlNodeExport(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writePlNodeExport(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; @@ -1013,7 +1013,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeValidateArrayInitRefTy(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeValidateArrayInitRefTy(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.ArrayInitRefTy, inst_data.payload_index).data; @@ -1023,7 +1023,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeStructInit(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeStructInit(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); var field_i: u32 = 0; @@ -1047,7 +1047,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeCmpxchg(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeCmpxchg(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data; try self.writeInstRef(stream, extra.ptr); @@ -1063,7 +1063,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.node); } - fn writePtrCastFull(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writePtrCastFull(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?; const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small))); const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data; @@ -1079,7 +1079,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.node); } - fn writePtrCastNoDest(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writePtrCastNoDest(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?; const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small))); const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data; @@ -1090,7 +1090,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.node); } - fn writeAtomicLoad(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeAtomicLoad(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data; @@ -1103,7 +1103,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeAtomicStore(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeAtomicStore(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data; @@ -1116,7 +1116,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeAtomicRmw(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeAtomicRmw(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; @@ -1131,7 +1131,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeStructInitAnon(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeStructInitAnon(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); var field_i: u32 = 0; @@ -1152,7 +1152,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeStructInitFieldType(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeStructInitFieldType(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; try self.writeInstRef(stream, extra.container_type); @@ -1161,7 +1161,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeFieldTypeRef(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeFieldTypeRef(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data; try self.writeInstRef(stream, extra.container_type); @@ -1171,7 +1171,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeNodeMultiOp(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeNodeMultiOp(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); const operands = self.code.refSlice(extra.end, extended.small); @@ -1185,7 +1185,7 @@ const Writer = struct { fn writeInstNode( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].inst_node; @@ -1196,7 +1196,7 @@ const Writer = struct { fn writeAsm( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData, tmpl_is_expr: bool, ) !void { @@ -1274,7 +1274,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.data.src_node); } - fn writeOverflowArithmetic(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeOverflowArithmetic(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data; try self.writeInstRef(stream, extra.lhs); @@ -1286,7 +1286,7 @@ const Writer = struct { fn writeCall( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, comptime kind: enum { direct, field }, ) !void { @@ -1337,7 +1337,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeBlock(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeBlock(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index); const body = self.code.bodySlice(extra.end, extra.data.body_len); @@ -1346,7 +1346,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeBlockComptime(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeBlockComptime(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.BlockComptime, inst_data.payload_index); const body = self.code.bodySlice(extra.end, extra.data.body_len); @@ -1356,7 +1356,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeCondBr(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeCondBr(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); const then_body = self.code.bodySlice(extra.end, extra.data.then_body_len); @@ -1370,7 +1370,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeTry(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeTry(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.Try, inst_data.payload_index); const body = self.code.bodySlice(extra.end, extra.data.body_len); @@ -1381,7 +1381,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeStructDecl(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeStructDecl(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); const extra = self.code.extraData(Zir.Inst.StructDecl, extended.operand); @@ -1573,7 +1573,7 @@ const Writer = struct { try self.writeSrcNode(stream, .zero); } - fn writeUnionDecl(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeUnionDecl(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small)); const extra = self.code.extraData(Zir.Inst.UnionDecl, extended.operand); @@ -1724,7 +1724,7 @@ const Writer = struct { try self.writeSrcNode(stream, .zero); } - fn writeEnumDecl(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeEnumDecl(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small)); const extra = self.code.extraData(Zir.Inst.EnumDecl, extended.operand); @@ -1845,7 +1845,7 @@ const Writer = struct { fn writeOpaqueDecl( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData, ) !void { const small = @as(Zir.Inst.OpaqueDecl.Small, @bitCast(extended.small)); @@ -1887,7 +1887,7 @@ const Writer = struct { try self.writeSrcNode(stream, .zero); } - fn writeTupleDecl(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeTupleDecl(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const fields_len = extended.small; assert(fields_len != 0); const extra = self.code.extraData(Zir.Inst.TupleDecl, extended.operand); @@ -1915,7 +1915,7 @@ const Writer = struct { fn writeErrorSetDecl( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -1940,7 +1940,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeSwitchBlockErrUnion(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeSwitchBlockErrUnion(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index); @@ -2077,7 +2077,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeSwitchBlock(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeSwitchBlock(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); @@ -2207,7 +2207,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writePlNodeField(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writePlNodeField(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; const name = self.code.nullTerminatedString(extra.field_name_start); @@ -2216,7 +2216,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writePlNodeFieldNamed(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writePlNodeFieldNamed(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; try self.writeInstRef(stream, extra.lhs); @@ -2226,7 +2226,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeAs(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeAs(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.As, inst_data.payload_index).data; try self.writeInstRef(stream, extra.dest_type); @@ -2238,7 +2238,7 @@ const Writer = struct { fn writeNode( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const src_node = self.code.instructions.items(.data)[@intFromEnum(inst)].node; @@ -2248,7 +2248,7 @@ const Writer = struct { fn writeStrTok( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, ) Error!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_tok; @@ -2257,7 +2257,7 @@ const Writer = struct { try self.writeSrcTok(stream, inst_data.src_tok); } - fn writeStrOp(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeStrOp(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_op; const str = inst_data.getStr(self.code); try self.writeInstRef(stream, inst_data.operand); @@ -2266,7 +2266,7 @@ const Writer = struct { fn writeFunc( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inst: Zir.Inst.Index, inferred_error_set: bool, ) !void { @@ -2317,7 +2317,7 @@ const Writer = struct { ); } - fn writeFuncFancy(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeFuncFancy(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); @@ -2376,7 +2376,7 @@ const Writer = struct { ); } - fn writeAllocExtended(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeAllocExtended(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.AllocExtended, extended.operand); const small = @as(Zir.Inst.AllocExtended.Small, @bitCast(extended.small)); @@ -2399,7 +2399,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.data.src_node); } - fn writeTypeofPeer(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeTypeofPeer(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.TypeOfPeer, extended.operand); const body = self.code.bodySlice(extra.data.body_index, extra.data.body_len); try self.writeBracedBody(stream, body); @@ -2412,7 +2412,7 @@ const Writer = struct { try stream.writeAll("])"); } - fn writeBoolBr(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeBoolBr(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.BoolBr, inst_data.payload_index); const body = self.code.bodySlice(extra.end, extra.data.body_len); @@ -2423,7 +2423,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeIntType(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeIntType(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const int_type = self.code.instructions.items(.data)[@intFromEnum(inst)].int_type; const prefix: u8 = switch (int_type.signedness) { .signed => 'i', @@ -2433,7 +2433,7 @@ const Writer = struct { try self.writeSrcNode(stream, int_type.src_node); } - fn writeSaveErrRetIndex(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeSaveErrRetIndex(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].save_err_ret_index; try self.writeInstRef(stream, inst_data.operand); @@ -2441,7 +2441,7 @@ const Writer = struct { try stream.writeAll(")"); } - fn writeRestoreErrRetIndex(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeRestoreErrRetIndex(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const extra = self.code.extraData(Zir.Inst.RestoreErrRetIndex, extended.operand).data; try self.writeInstRef(stream, extra.block); @@ -2451,7 +2451,7 @@ const Writer = struct { try self.writeSrcNode(stream, extra.src_node); } - fn writeBreak(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeBreak(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"break"; const extra = self.code.extraData(Zir.Inst.Break, inst_data.payload_index).data; @@ -2461,7 +2461,7 @@ const Writer = struct { try stream.writeAll(")"); } - fn writeArrayInit(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeArrayInit(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); @@ -2477,7 +2477,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeArrayInitAnon(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeArrayInitAnon(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); @@ -2492,7 +2492,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeArrayInitSent(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeArrayInitSent(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); @@ -2512,7 +2512,7 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.src_node); } - fn writeUnreachable(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeUnreachable(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"unreachable"; try stream.writeAll(") "); try self.writeSrcNode(stream, inst_data.src_node); @@ -2520,7 +2520,7 @@ const Writer = struct { fn writeFuncCommon( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, inferred_error_set: bool, var_args: bool, is_noinline: bool, @@ -2557,19 +2557,19 @@ const Writer = struct { try self.writeSrcNode(stream, src_node); } - fn writeDbgStmt(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeDbgStmt(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 }); } - fn writeDefer(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeDefer(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"defer"; const body = self.code.bodySlice(inst_data.index, inst_data.len); try self.writeBracedBody(stream, body); try stream.writeByte(')'); } - fn writeDeferErrCode(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeDeferErrCode(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].defer_err_code; const extra = self.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data; @@ -2582,7 +2582,7 @@ const Writer = struct { try stream.writeByte(')'); } - fn writeDeclaration(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeDeclaration(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const decl = self.code.getDeclaration(inst); const prev_parent_decl_node = self.parent_decl_node; @@ -2639,26 +2639,26 @@ const Writer = struct { try self.writeSrcNode(stream, .zero); } - fn writeClosureGet(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeClosureGet(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { try stream.print("{d})) ", .{extended.small}); const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand))); try self.writeSrcNode(stream, src_node); } - fn writeBuiltinValue(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeBuiltinValue(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const val: Zir.Inst.BuiltinValue = @enumFromInt(extended.small); try stream.print("{s})) ", .{@tagName(val)}); const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand))); try self.writeSrcNode(stream, src_node); } - fn writeInplaceArithResultTy(self: *Writer, stream: *std.io.BufferedWriter, extended: Zir.Inst.Extended.InstData) !void { + fn writeInplaceArithResultTy(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void { const op: Zir.Inst.InplaceOp = @enumFromInt(extended.small); try self.writeInstRef(stream, @enumFromInt(extended.operand)); try stream.print(", {s}))", .{@tagName(op)}); } - fn writeInstRef(self: *Writer, stream: *std.io.BufferedWriter, ref: Zir.Inst.Ref) !void { + fn writeInstRef(self: *Writer, stream: *std.io.Writer, ref: Zir.Inst.Ref) !void { if (ref == .none) { return stream.writeAll(".none"); } else if (ref.toIndex()) |i| { @@ -2669,12 +2669,12 @@ const Writer = struct { } } - fn writeInstIndex(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeInstIndex(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { _ = self; return stream.print("%{d}", .{@intFromEnum(inst)}); } - fn writeCaptures(self: *Writer, stream: *std.io.BufferedWriter, extra_index: usize, captures_len: u32) !usize { + fn writeCaptures(self: *Writer, stream: *std.io.Writer, extra_index: usize, captures_len: u32) !usize { if (captures_len == 0) { try stream.writeAll("{}"); return extra_index; @@ -2694,7 +2694,7 @@ const Writer = struct { return extra_index + 2 * captures_len; } - fn writeCapture(self: *Writer, stream: *std.io.BufferedWriter, capture: Zir.Inst.Capture) !void { + fn writeCapture(self: *Writer, stream: *std.io.Writer, capture: Zir.Inst.Capture) !void { switch (capture.unwrap()) { .nested => |i| return stream.print("[{d}]", .{i}), .instruction => |inst| return self.writeInstIndex(stream, inst), @@ -2713,7 +2713,7 @@ const Writer = struct { fn writeOptionalInstRef( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, prefix: []const u8, inst: Zir.Inst.Ref, ) !void { @@ -2724,7 +2724,7 @@ const Writer = struct { fn writeOptionalInstRefOrBody( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, prefix: []const u8, ref: Zir.Inst.Ref, body: []const Zir.Inst.Index, @@ -2742,7 +2742,7 @@ const Writer = struct { fn writeFlag( self: *Writer, - stream: *std.io.BufferedWriter, + stream: *std.io.Writer, name: []const u8, flag: bool, ) !void { @@ -2751,7 +2751,7 @@ const Writer = struct { try stream.writeAll(name); } - fn writeSrcNode(self: *Writer, stream: *std.io.BufferedWriter, src_node: Ast.Node.Offset) !void { + fn writeSrcNode(self: *Writer, stream: *std.io.Writer, src_node: Ast.Node.Offset) !void { const tree = self.tree orelse return; const abs_node = src_node.toAbsolute(self.parent_decl_node); const src_span = tree.nodeToSpan(abs_node); @@ -2763,7 +2763,7 @@ const Writer = struct { }); } - fn writeSrcTok(self: *Writer, stream: *std.io.BufferedWriter, src_tok: Ast.TokenOffset) !void { + fn writeSrcTok(self: *Writer, stream: *std.io.Writer, src_tok: Ast.TokenOffset) !void { const tree = self.tree orelse return; const abs_tok = src_tok.toAbsolute(tree.firstToken(self.parent_decl_node)); const span_start = tree.tokenStart(abs_tok); @@ -2776,7 +2776,7 @@ const Writer = struct { }); } - fn writeSrcTokAbs(self: *Writer, stream: *std.io.BufferedWriter, src_tok: Ast.TokenIndex) !void { + fn writeSrcTokAbs(self: *Writer, stream: *std.io.Writer, src_tok: Ast.TokenIndex) !void { const tree = self.tree orelse return; const span_start = tree.tokenStart(src_tok); const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(src_tok).len)); @@ -2788,15 +2788,15 @@ const Writer = struct { }); } - fn writeBracedDecl(self: *Writer, stream: *std.io.BufferedWriter, body: []const Zir.Inst.Index) !void { + fn writeBracedDecl(self: *Writer, stream: *std.io.Writer, body: []const Zir.Inst.Index) !void { try self.writeBracedBodyConditional(stream, body, self.recurse_decls); } - fn writeBracedBody(self: *Writer, stream: *std.io.BufferedWriter, body: []const Zir.Inst.Index) !void { + fn writeBracedBody(self: *Writer, stream: *std.io.Writer, body: []const Zir.Inst.Index) !void { try self.writeBracedBodyConditional(stream, body, self.recurse_blocks); } - fn writeBracedBodyConditional(self: *Writer, stream: *std.io.BufferedWriter, body: []const Zir.Inst.Index, enabled: bool) !void { + fn writeBracedBodyConditional(self: *Writer, stream: *std.io.Writer, body: []const Zir.Inst.Index, enabled: bool) !void { if (body.len == 0) { try stream.writeAll("{}"); } else if (enabled) { @@ -2825,7 +2825,7 @@ const Writer = struct { } } - fn writeBody(self: *Writer, stream: *std.io.BufferedWriter, body: []const Zir.Inst.Index) !void { + fn writeBody(self: *Writer, stream: *std.io.Writer, body: []const Zir.Inst.Index) !void { for (body) |inst| { try stream.splatByteAll(' ', self.indent); try stream.print("%{d} ", .{@intFromEnum(inst)}); @@ -2834,7 +2834,7 @@ const Writer = struct { } } - fn writeImport(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { + fn writeImport(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok; const extra = self.code.extraData(Zir.Inst.Import, inst_data.payload_index).data; try self.writeInstRef(stream, extra.res_ty); diff --git a/src/print_zoir.zig b/src/print_zoir.zig index 69ce6f5b05..3828726437 100644 --- a/src/print_zoir.zig +++ b/src/print_zoir.zig @@ -1,4 +1,4 @@ -pub fn renderToWriter(zoir: Zoir, arena: Allocator, w: *std.io.BufferedWriter) error{ WriteFailed, OutOfMemory }!void { +pub fn renderToWriter(zoir: Zoir, arena: Allocator, w: *Writer) error{ WriteFailed, OutOfMemory }!void { assert(!zoir.hasCompileErrors()); const bytes_per_node = comptime n: { @@ -41,12 +41,12 @@ pub fn renderToWriter(zoir: Zoir, arena: Allocator, w: *std.io.BufferedWriter) e } const PrintZon = struct { - w: *std.io.BufferedWriter, + w: *Writer, arena: Allocator, zoir: Zoir, indent: u32, - const Error = std.io.Writer.Error; + const Error = Writer.Error; fn renderRoot(pz: *PrintZon) Error!void { try pz.renderNode(.root); @@ -113,3 +113,4 @@ const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const Zoir = std.zig.Zoir; +const Writer = std.io.Writer;