authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-07 23:52:53-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-02-07 23:52:53-08:00
log3122fd0ba0eb4cdb17616658b462a255a37f1ad7
tree2564a986d66fab02726aa405d23df0c645b27db5
parent9ca6cc1e2f6af1b5197f92e4b56865ab822f4040
parent2b2c9c5db893c7bc0352d1738c1658a5fcd32d62
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #17634 from ianprime0509/type-erased-writer

Add type-erased writer and GenericWriter

6 files changed, 181 insertions(+), 83 deletions(-)

CMakeLists.txt+1-1
...@@ -265,7 +265,7 @@ set(ZIG_STAGE2_SOURCES...@@ -265,7 +265,7 @@ set(ZIG_STAGE2_SOURCES
265 "${CMAKE_SOURCE_DIR}/lib/std/io/limited_reader.zig"265 "${CMAKE_SOURCE_DIR}/lib/std/io/limited_reader.zig"
266 "${CMAKE_SOURCE_DIR}/lib/std/io/Reader.zig"266 "${CMAKE_SOURCE_DIR}/lib/std/io/Reader.zig"
267 "${CMAKE_SOURCE_DIR}/lib/std/io/seekable_stream.zig"267 "${CMAKE_SOURCE_DIR}/lib/std/io/seekable_stream.zig"
268 "${CMAKE_SOURCE_DIR}/lib/std/io/writer.zig"268 "${CMAKE_SOURCE_DIR}/lib/std/io/Writer.zig"
269 "${CMAKE_SOURCE_DIR}/lib/std/json.zig"269 "${CMAKE_SOURCE_DIR}/lib/std/json.zig"
270 "${CMAKE_SOURCE_DIR}/lib/std/json/stringify.zig"270 "${CMAKE_SOURCE_DIR}/lib/std/json/stringify.zig"
271 "${CMAKE_SOURCE_DIR}/lib/std/leb128.zig"271 "${CMAKE_SOURCE_DIR}/lib/std/leb128.zig"
lib/std/fmt.zig+5-2
...@@ -1986,7 +1986,10 @@ pub const BufPrintError = error{...@@ -1986,7 +1986,10 @@ pub const BufPrintError = error{
1986/// Returns a slice of the bytes printed to.1986/// Returns a slice of the bytes printed to.
1987pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 {1987pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 {
1988 var fbs = std.io.fixedBufferStream(buf);1988 var fbs = std.io.fixedBufferStream(buf);
1989 try format(fbs.writer(), fmt, args);1989 format(fbs.writer().any(), fmt, args) catch |err| switch (err) {
1990 error.NoSpaceLeft => return error.NoSpaceLeft,
1991 else => unreachable,
1992 };
1990 return fbs.getWritten();1993 return fbs.getWritten();
1991}1994}
19921995
...@@ -1998,7 +2001,7 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr...@@ -1998,7 +2001,7 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr
1998/// Count the characters needed for format. Useful for preallocating memory2001/// Count the characters needed for format. Useful for preallocating memory
1999pub fn count(comptime fmt: []const u8, args: anytype) u64 {2002pub fn count(comptime fmt: []const u8, args: anytype) u64 {
2000 var counting_writer = std.io.countingWriter(std.io.null_writer);2003 var counting_writer = std.io.countingWriter(std.io.null_writer);
2001 format(counting_writer.writer(), fmt, args) catch |err| switch (err) {};2004 format(counting_writer.writer().any(), fmt, args) catch unreachable;
2002 return counting_writer.bytes_written;2005 return counting_writer.bytes_written;
2003}2006}
20042007
lib/std/io.zig+62-2
...@@ -333,13 +333,73 @@ pub fn GenericReader(...@@ -333,13 +333,73 @@ pub fn GenericReader(
333 };333 };
334}334}
335335
336pub fn GenericWriter(
337 comptime Context: type,
338 comptime WriteError: type,
339 comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
340) type {
341 return struct {
342 context: Context,
343
344 const Self = @This();
345 pub const Error = WriteError;
346
347 pub inline fn write(self: Self, bytes: []const u8) Error!usize {
348 return writeFn(self.context, bytes);
349 }
350
351 pub inline fn writeAll(self: Self, bytes: []const u8) Error!void {
352 return @errorCast(self.any().writeAll(bytes));
353 }
354
355 pub inline fn print(self: Self, comptime format: []const u8, args: anytype) Error!void {
356 return @errorCast(self.any().print(format, args));
357 }
358
359 pub inline fn writeByte(self: Self, byte: u8) Error!void {
360 return @errorCast(self.any().writeByte(byte));
361 }
362
363 pub inline fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void {
364 return @errorCast(self.any().writeByteNTimes(byte, n));
365 }
366
367 pub inline fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) Error!void {
368 return @errorCast(self.any().writeBytesNTimes(bytes, n));
369 }
370
371 pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) Error!void {
372 return @errorCast(self.any().writeInt(T, value, endian));
373 }
374
375 pub inline fn writeStruct(self: Self, value: anytype) Error!void {
376 return @errorCast(self.any().writeStruct(value));
377 }
378
379 pub inline fn any(self: *const Self) AnyWriter {
380 return .{
381 .context = @ptrCast(&self.context),
382 .writeFn = typeErasedWriteFn,
383 };
384 }
385
386 fn typeErasedWriteFn(context: *const anyopaque, bytes: []const u8) anyerror!usize {
387 const ptr: *const Context = @alignCast(@ptrCast(context));
388 return writeFn(ptr.*, bytes);
389 }
390 };
391}
392
336/// Deprecated; consider switching to `AnyReader` or use `GenericReader`393/// Deprecated; consider switching to `AnyReader` or use `GenericReader`
337/// to use previous API.394/// to use previous API.
338pub const Reader = GenericReader;395pub const Reader = GenericReader;
396/// Deprecated; consider switching to `AnyWriter` or use `GenericWriter`
397/// to use previous API.
398pub const Writer = GenericWriter;
339399
340pub const AnyReader = @import("io/Reader.zig");400pub const AnyReader = @import("io/Reader.zig");
401pub const AnyWriter = @import("io/Writer.zig");
341402
342pub const Writer = @import("io/writer.zig").Writer;
343pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;403pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
344404
345pub const BufferedWriter = @import("io/buffered_writer.zig").BufferedWriter;405pub const BufferedWriter = @import("io/buffered_writer.zig").BufferedWriter;
...@@ -652,6 +712,7 @@ pub fn PollFiles(comptime StreamEnum: type) type {...@@ -652,6 +712,7 @@ pub fn PollFiles(comptime StreamEnum: type) type {
652712
653test {713test {
654 _ = AnyReader;714 _ = AnyReader;
715 _ = AnyWriter;
655 _ = @import("io/bit_reader.zig");716 _ = @import("io/bit_reader.zig");
656 _ = @import("io/bit_writer.zig");717 _ = @import("io/bit_writer.zig");
657 _ = @import("io/buffered_atomic_file.zig");718 _ = @import("io/buffered_atomic_file.zig");
...@@ -661,7 +722,6 @@ test {...@@ -661,7 +722,6 @@ test {
661 _ = @import("io/counting_writer.zig");722 _ = @import("io/counting_writer.zig");
662 _ = @import("io/counting_reader.zig");723 _ = @import("io/counting_reader.zig");
663 _ = @import("io/fixed_buffer_stream.zig");724 _ = @import("io/fixed_buffer_stream.zig");
664 _ = @import("io/writer.zig");
665 _ = @import("io/peek_stream.zig");725 _ = @import("io/peek_stream.zig");
666 _ = @import("io/seekable_stream.zig");726 _ = @import("io/seekable_stream.zig");
667 _ = @import("io/stream_source.zig");727 _ = @import("io/stream_source.zig");
lib/std/io/Writer.zig created+60
...@@ -0,0 +1,60 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4
5context: *const anyopaque,
6writeFn: *const fn (context: *const anyopaque, bytes: []const u8) anyerror!usize,
7
8const Self = @This();
9pub const Error = anyerror;
10
11pub fn write(self: Self, bytes: []const u8) anyerror!usize {
12 return self.writeFn(self.context, bytes);
13}
14
15pub fn writeAll(self: Self, bytes: []const u8) anyerror!void {
16 var index: usize = 0;
17 while (index != bytes.len) {
18 index += try self.write(bytes[index..]);
19 }
20}
21
22pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void {
23 return std.fmt.format(self, format, args);
24}
25
26pub fn writeByte(self: Self, byte: u8) anyerror!void {
27 const array = [1]u8{byte};
28 return self.writeAll(&array);
29}
30
31pub fn writeByteNTimes(self: Self, byte: u8, n: usize) anyerror!void {
32 var bytes: [256]u8 = undefined;
33 @memset(bytes[0..], byte);
34
35 var remaining: usize = n;
36 while (remaining > 0) {
37 const to_write = @min(remaining, bytes.len);
38 try self.writeAll(bytes[0..to_write]);
39 remaining -= to_write;
40 }
41}
42
43pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) anyerror!void {
44 var i: usize = 0;
45 while (i < n) : (i += 1) {
46 try self.writeAll(bytes);
47 }
48}
49
50pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void {
51 var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined;
52 mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
53 return self.writeAll(&bytes);
54}
55
56pub fn writeStruct(self: Self, value: anytype) anyerror!void {
57 // Only extern and packed structs have defined in-memory layout.
58 comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != .Auto);
59 return self.writeAll(mem.asBytes(&value));
60}
lib/std/io/writer.zig deleted-67
...@@ -1,67 +0,0 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4
5pub fn Writer(
6 comptime Context: type,
7 comptime WriteError: type,
8 comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
9) type {
10 return struct {
11 context: Context,
12
13 const Self = @This();
14 pub const Error = WriteError;
15
16 pub fn write(self: Self, bytes: []const u8) Error!usize {
17 return writeFn(self.context, bytes);
18 }
19
20 pub fn writeAll(self: Self, bytes: []const u8) Error!void {
21 var index: usize = 0;
22 while (index != bytes.len) {
23 index += try self.write(bytes[index..]);
24 }
25 }
26
27 pub fn print(self: Self, comptime format: []const u8, args: anytype) Error!void {
28 return std.fmt.format(self, format, args);
29 }
30
31 pub fn writeByte(self: Self, byte: u8) Error!void {
32 const array = [1]u8{byte};
33 return self.writeAll(&array);
34 }
35
36 pub fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void {
37 var bytes: [256]u8 = undefined;
38 @memset(bytes[0..], byte);
39
40 var remaining: usize = n;
41 while (remaining > 0) {
42 const to_write = @min(remaining, bytes.len);
43 try self.writeAll(bytes[0..to_write]);
44 remaining -= to_write;
45 }
46 }
47
48 pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) Error!void {
49 var i: usize = 0;
50 while (i < n) : (i += 1) {
51 try self.writeAll(bytes);
52 }
53 }
54
55 pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) Error!void {
56 var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined;
57 mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
58 return self.writeAll(&bytes);
59 }
60
61 pub fn writeStruct(self: Self, value: anytype) Error!void {
62 // Only extern and packed structs have defined in-memory layout.
63 comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != .Auto);
64 return self.writeAll(mem.asBytes(&value));
65 }
66 };
67}
src/codegen/c.zig+53-11
...@@ -306,7 +306,7 @@ pub const Function = struct {...@@ -306,7 +306,7 @@ pub const Function = struct {
306 const ty = f.typeOf(ref);306 const ty = f.typeOf(ref);
307307
308 const result: CValue = if (lowersToArray(ty, mod)) result: {308 const result: CValue = if (lowersToArray(ty, mod)) result: {
309 const writer = f.object.code_header.writer();309 const writer = f.object.codeHeaderWriter();
310 const alignment: Alignment = .none;310 const alignment: Alignment = .none;
311 const decl_c_value = try f.allocLocalValue(ty, alignment);311 const decl_c_value = try f.allocLocalValue(ty, alignment);
312 const gpa = f.object.dg.gpa;312 const gpa = f.object.dg.gpa;
...@@ -534,6 +534,10 @@ pub const Object = struct {...@@ -534,6 +534,10 @@ pub const Object = struct {
534 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {534 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {
535 return o.indent_writer.writer();535 return o.indent_writer.writer();
536 }536 }
537
538 fn codeHeaderWriter(o: *Object) ArrayListWriter {
539 return arrayListWriter(&o.code_header);
540 }
537};541};
538542
539/// This data is available both when outputting .c code and when outputting an .h file.543/// This data is available both when outputting .c code and when outputting an .h file.
...@@ -557,6 +561,10 @@ pub const DeclGen = struct {...@@ -557,6 +561,10 @@ pub const DeclGen = struct {
557 flush,561 flush,
558 };562 };
559563
564 fn fwdDeclWriter(dg: *DeclGen) ArrayListWriter {
565 return arrayListWriter(&dg.fwd_decl);
566 }
567
560 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {568 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
561 @setCold(true);569 @setCold(true);
562 const mod = dg.module;570 const mod = dg.module;
...@@ -1982,7 +1990,7 @@ pub const DeclGen = struct {...@@ -1982,7 +1990,7 @@ pub const DeclGen = struct {
1982 fwd_kind: enum { tentative, final },1990 fwd_kind: enum { tentative, final },
1983 ) !void {1991 ) !void {
1984 const decl = dg.module.declPtr(decl_index);1992 const decl = dg.module.declPtr(decl_index);
1985 const fwd = dg.fwd_decl.writer();1993 const fwd = dg.fwdDeclWriter();
1986 const is_global = variable.is_extern or dg.declIsGlobal(.{ .ty = decl.ty, .val = decl.val });1994 const is_global = variable.is_extern or dg.declIsGlobal(.{ .ty = decl.ty, .val = decl.val });
1987 try fwd.writeAll(if (is_global) "zig_extern " else "static ");1995 try fwd.writeAll(if (is_global) "zig_extern " else "static ");
1988 const maybe_exports = dg.module.decl_exports.get(decl_index);1996 const maybe_exports = dg.module.decl_exports.get(decl_index);
...@@ -2668,7 +2676,7 @@ fn genExports(o: *Object) !void {...@@ -2668,7 +2676,7 @@ fn genExports(o: *Object) !void {
2668 };2676 };
2669 const decl = mod.declPtr(decl_index);2677 const decl = mod.declPtr(decl_index);
2670 const tv: TypedValue = .{ .ty = decl.ty, .val = Value.fromInterned((try decl.internValue(mod))) };2678 const tv: TypedValue = .{ .ty = decl.ty, .val = Value.fromInterned((try decl.internValue(mod))) };
2671 const fwd = o.dg.fwd_decl.writer();2679 const fwd = o.dg.fwdDeclWriter();
26722680
2673 const exports = mod.decl_exports.get(decl_index) orelse return;2681 const exports = mod.decl_exports.get(decl_index) orelse return;
2674 if (exports.items.len < 2) return;2682 if (exports.items.len < 2) return;
...@@ -2782,7 +2790,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {...@@ -2782,7 +2790,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2782 const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete);2790 const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete);
2783 const fn_info = fn_cty.cast(CType.Payload.Function).?.data;2791 const fn_info = fn_cty.cast(CType.Payload.Function).?.data;
27842792
2785 const fwd_decl_writer = o.dg.fwd_decl.writer();2793 const fwd_decl_writer = o.dg.fwdDeclWriter();
2786 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});2794 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
2787 try o.dg.renderFunctionSignature(2795 try o.dg.renderFunctionSignature(
2788 fwd_decl_writer,2796 fwd_decl_writer,
...@@ -2824,7 +2832,7 @@ pub fn genFunc(f: *Function) !void {...@@ -2824,7 +2832,7 @@ pub fn genFunc(f: *Function) !void {
2824 defer o.code_header.deinit();2832 defer o.code_header.deinit();
28252833
2826 const is_global = o.dg.declIsGlobal(tv);2834 const is_global = o.dg.declIsGlobal(tv);
2827 const fwd_decl_writer = o.dg.fwd_decl.writer();2835 const fwd_decl_writer = o.dg.fwdDeclWriter();
2828 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2836 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
28292837
2830 if (mod.decl_exports.get(decl_index)) |exports|2838 if (mod.decl_exports.get(decl_index)) |exports|
...@@ -2879,7 +2887,7 @@ pub fn genFunc(f: *Function) !void {...@@ -2879,7 +2887,7 @@ pub fn genFunc(f: *Function) !void {
2879 };2887 };
2880 free_locals.sort(SortContext{ .keys = free_locals.keys() });2888 free_locals.sort(SortContext{ .keys = free_locals.keys() });
28812889
2882 const w = o.code_header.writer();2890 const w = o.codeHeaderWriter();
2883 for (free_locals.values()) |list| {2891 for (free_locals.values()) |list| {
2884 for (list.keys()) |local_index| {2892 for (list.keys()) |local_index| {
2885 const local = f.locals.items[local_index];2893 const local = f.locals.items[local_index];
...@@ -2907,7 +2915,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2907,7 +2915,7 @@ pub fn genDecl(o: *Object) !void {
29072915
2908 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return;2916 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return;
2909 if (tv.val.getExternFunc(mod)) |_| {2917 if (tv.val.getExternFunc(mod)) |_| {
2910 const fwd_decl_writer = o.dg.fwd_decl.writer();2918 const fwd_decl_writer = o.dg.fwdDeclWriter();
2911 try fwd_decl_writer.writeAll("zig_extern ");2919 try fwd_decl_writer.writeAll("zig_extern ");
2912 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });2920 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
2913 try fwd_decl_writer.writeAll(";\n");2921 try fwd_decl_writer.writeAll(";\n");
...@@ -2948,7 +2956,7 @@ pub fn genDeclValue(...@@ -2948,7 +2956,7 @@ pub fn genDeclValue(
2948 link_section: InternPool.OptionalNullTerminatedString,2956 link_section: InternPool.OptionalNullTerminatedString,
2949) !void {2957) !void {
2950 const mod = o.dg.module;2958 const mod = o.dg.module;
2951 const fwd_decl_writer = o.dg.fwd_decl.writer();2959 const fwd_decl_writer = o.dg.fwdDeclWriter();
29522960
2953 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2961 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2954 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, alignment, .complete);2962 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, alignment, .complete);
...@@ -2992,7 +3000,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -2992,7 +3000,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
2992 .ty = decl.ty,3000 .ty = decl.ty,
2993 .val = decl.val,3001 .val = decl.val,
2994 };3002 };
2995 const writer = dg.fwd_decl.writer();3003 const writer = dg.fwdDeclWriter();
29963004
2997 switch (tv.ty.zigTypeTag(mod)) {3005 switch (tv.ty.zigTypeTag(mod)) {
2998 .Fn => if (dg.declIsGlobal(tv)) {3006 .Fn => if (dg.declIsGlobal(tv)) {
...@@ -7517,11 +7525,25 @@ fn toAtomicRmwSuffix(order: std.builtin.AtomicRmwOp) []const u8 {...@@ -7517,11 +7525,25 @@ fn toAtomicRmwSuffix(order: std.builtin.AtomicRmwOp) []const u8 {
7517 };7525 };
7518}7526}
75197527
7528const ArrayListWriter = ErrorOnlyGenericWriter(std.ArrayList(u8).Writer.Error);
7529
7530fn arrayListWriter(list: *std.ArrayList(u8)) ArrayListWriter {
7531 return .{ .context = .{
7532 .context = list,
7533 .writeFn = struct {
7534 fn write(context: *const anyopaque, bytes: []const u8) anyerror!usize {
7535 const l: *std.ArrayList(u8) = @alignCast(@constCast(@ptrCast(context)));
7536 return l.writer().write(bytes);
7537 }
7538 }.write,
7539 } };
7540}
7541
7520fn IndentWriter(comptime UnderlyingWriter: type) type {7542fn IndentWriter(comptime UnderlyingWriter: type) type {
7521 return struct {7543 return struct {
7522 const Self = @This();7544 const Self = @This();
7523 pub const Error = UnderlyingWriter.Error;7545 pub const Error = UnderlyingWriter.Error;
7524 pub const Writer = std.io.Writer(*Self, Error, write);7546 pub const Writer = ErrorOnlyGenericWriter(Error);
75257547
7526 pub const indent_delta = 1;7548 pub const indent_delta = 1;
75277549
...@@ -7530,7 +7552,10 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {...@@ -7530,7 +7552,10 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {
7530 current_line_empty: bool = true,7552 current_line_empty: bool = true,
75317553
7532 pub fn writer(self: *Self) Writer {7554 pub fn writer(self: *Self) Writer {
7533 return .{ .context = self };7555 return .{ .context = .{
7556 .context = self,
7557 .writeFn = writeAny,
7558 } };
7534 }7559 }
75357560
7536 pub fn write(self: *Self, bytes: []const u8) Error!usize {7561 pub fn write(self: *Self, bytes: []const u8) Error!usize {
...@@ -7545,6 +7570,11 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {...@@ -7545,6 +7570,11 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {
7545 return self.writeNoIndent(bytes);7570 return self.writeNoIndent(bytes);
7546 }7571 }
75477572
7573 fn writeAny(context: *const anyopaque, bytes: []const u8) anyerror!usize {
7574 const self: *Self = @alignCast(@constCast(@ptrCast(context)));
7575 return self.write(bytes);
7576 }
7577
7548 pub fn insertNewline(self: *Self) Error!void {7578 pub fn insertNewline(self: *Self) Error!void {
7549 _ = try self.writeNoIndent("\n");7579 _ = try self.writeNoIndent("\n");
7550 }7580 }
...@@ -7570,6 +7600,18 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {...@@ -7570,6 +7600,18 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {
7570 };7600 };
7571}7601}
75727602
7603/// A wrapper around `std.io.AnyWriter` that maintains a generic error set while
7604/// erasing the rest of the implementation. This is intended to avoid duplicate
7605/// generic instantiations for writer types which share the same error set, while
7606/// maintaining ease of error handling.
7607fn ErrorOnlyGenericWriter(comptime Error: type) type {
7608 return std.io.GenericWriter(std.io.AnyWriter, Error, struct {
7609 fn write(context: std.io.AnyWriter, bytes: []const u8) Error!usize {
7610 return @errorCast(context.write(bytes));
7611 }
7612 }.write);
7613}
7614
7573fn toCIntBits(zig_bits: u32) ?u32 {7615fn toCIntBits(zig_bits: u32) ?u32 {
7574 for (&[_]u8{ 8, 16, 32, 64, 128 }) |c_bits| {7616 for (&[_]u8{ 8, 16, 32, 64, 128 }) |c_bits| {
7575 if (zig_bits <= c_bits) {7617 if (zig_bits <= c_bits) {