From 03ac8ba23946d0193b3009d0c564e26bbeebaa3f Mon Sep 17 00:00:00 2001 From: Ian Johnson Date: Mon, 9 Oct 2023 00:10:30 -0400 Subject: [PATCH] Add type-erased writer and GenericWriter This is a companion to #17344 to apply the same change to the `std.io.Writer` interface. --- CMakeLists.txt | 2 +- lib/std/io.zig | 64 +++++++++++++++++++++++++++++++++++++++-- lib/std/io/Writer.zig | 60 ++++++++++++++++++++++++++++++++++++++ lib/std/io/writer.zig | 67 ------------------------------------------- 4 files changed, 123 insertions(+), 70 deletions(-) create mode 100644 lib/std/io/Writer.zig delete mode 100644 lib/std/io/writer.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f486ed64f22..c1ed1247deeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,7 +265,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/io/limited_reader.zig" "${CMAKE_SOURCE_DIR}/lib/std/io/Reader.zig" "${CMAKE_SOURCE_DIR}/lib/std/io/seekable_stream.zig" - "${CMAKE_SOURCE_DIR}/lib/std/io/writer.zig" + "${CMAKE_SOURCE_DIR}/lib/std/io/Writer.zig" "${CMAKE_SOURCE_DIR}/lib/std/json.zig" "${CMAKE_SOURCE_DIR}/lib/std/json/stringify.zig" "${CMAKE_SOURCE_DIR}/lib/std/leb128.zig" diff --git a/lib/std/io.zig b/lib/std/io.zig index 337dcc4cb8d0..985297e051c1 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -333,13 +333,73 @@ pub fn GenericReader( }; } +pub fn GenericWriter( + comptime Context: type, + comptime WriteError: type, + comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize, +) type { + return struct { + context: Context, + + const Self = @This(); + pub const Error = WriteError; + + pub inline fn write(self: Self, bytes: []const u8) Error!usize { + return writeFn(self.context, bytes); + } + + pub inline fn writeAll(self: Self, bytes: []const u8) Error!void { + return @errorCast(self.any().writeAll(bytes)); + } + + pub inline fn print(self: Self, comptime format: []const u8, args: anytype) Error!void { + return @errorCast(self.any().print(format, args)); + } + + pub inline fn writeByte(self: Self, byte: u8) Error!void { + return @errorCast(self.any().writeByte(byte)); + } + + pub inline fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void { + return @errorCast(self.any().writeByteNTimes(byte, n)); + } + + pub inline fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) Error!void { + return @errorCast(self.any().writeBytesNTimes(bytes, n)); + } + + pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) Error!void { + return @errorCast(self.any().writeInt(T, value, endian)); + } + + pub inline fn writeStruct(self: Self, value: anytype) Error!void { + return @errorCast(self.any().writeStruct(value)); + } + + pub inline fn any(self: *const Self) AnyWriter { + return .{ + .context = @ptrCast(&self.context), + .writeFn = typeErasedWriteFn, + }; + } + + fn typeErasedWriteFn(context: *const anyopaque, bytes: []const u8) anyerror!usize { + const ptr: *const Context = @alignCast(@ptrCast(context)); + return writeFn(ptr.*, bytes); + } + }; +} + /// Deprecated; consider switching to `AnyReader` or use `GenericReader` /// to use previous API. pub const Reader = GenericReader; +/// Deprecated; consider switching to `AnyWriter` or use `GenericWriter` +/// to use previous API. +pub const Writer = GenericWriter; pub const AnyReader = @import("io/Reader.zig"); +pub const AnyWriter = @import("io/Writer.zig"); -pub const Writer = @import("io/writer.zig").Writer; pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; pub const BufferedWriter = @import("io/buffered_writer.zig").BufferedWriter; @@ -652,6 +712,7 @@ pub fn PollFiles(comptime StreamEnum: type) type { test { _ = AnyReader; + _ = AnyWriter; _ = @import("io/bit_reader.zig"); _ = @import("io/bit_writer.zig"); _ = @import("io/buffered_atomic_file.zig"); @@ -661,7 +722,6 @@ test { _ = @import("io/counting_writer.zig"); _ = @import("io/counting_reader.zig"); _ = @import("io/fixed_buffer_stream.zig"); - _ = @import("io/writer.zig"); _ = @import("io/peek_stream.zig"); _ = @import("io/seekable_stream.zig"); _ = @import("io/stream_source.zig"); diff --git a/lib/std/io/Writer.zig b/lib/std/io/Writer.zig new file mode 100644 index 000000000000..82040efc3a42 --- /dev/null +++ b/lib/std/io/Writer.zig @@ -0,0 +1,60 @@ +const std = @import("../std.zig"); +const assert = std.debug.assert; +const mem = std.mem; + +context: *const anyopaque, +writeFn: *const fn (context: *const anyopaque, bytes: []const u8) anyerror!usize, + +const Self = @This(); +pub const Error = anyerror; + +pub fn write(self: Self, bytes: []const u8) anyerror!usize { + return self.writeFn(self.context, bytes); +} + +pub fn writeAll(self: Self, bytes: []const u8) anyerror!void { + var index: usize = 0; + while (index != bytes.len) { + index += try self.write(bytes[index..]); + } +} + +pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void { + return std.fmt.format(self, format, args); +} + +pub fn writeByte(self: Self, byte: u8) anyerror!void { + const array = [1]u8{byte}; + return self.writeAll(&array); +} + +pub fn writeByteNTimes(self: Self, byte: u8, n: usize) anyerror!void { + var bytes: [256]u8 = undefined; + @memset(bytes[0..], byte); + + var remaining: usize = n; + while (remaining > 0) { + const to_write = @min(remaining, bytes.len); + try self.writeAll(bytes[0..to_write]); + remaining -= to_write; + } +} + +pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) anyerror!void { + var i: usize = 0; + while (i < n) : (i += 1) { + try self.writeAll(bytes); + } +} + +pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void { + var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined; + mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); + return self.writeAll(&bytes); +} + +pub fn writeStruct(self: Self, value: anytype) anyerror!void { + // Only extern and packed structs have defined in-memory layout. + comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != .Auto); + return self.writeAll(mem.asBytes(&value)); +} diff --git a/lib/std/io/writer.zig b/lib/std/io/writer.zig deleted file mode 100644 index 5fe06120cda2..000000000000 --- a/lib/std/io/writer.zig +++ /dev/null @@ -1,67 +0,0 @@ -const std = @import("../std.zig"); -const assert = std.debug.assert; -const mem = std.mem; - -pub fn Writer( - comptime Context: type, - comptime WriteError: type, - comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize, -) type { - return struct { - context: Context, - - const Self = @This(); - pub const Error = WriteError; - - pub fn write(self: Self, bytes: []const u8) Error!usize { - return writeFn(self.context, bytes); - } - - pub fn writeAll(self: Self, bytes: []const u8) Error!void { - var index: usize = 0; - while (index != bytes.len) { - index += try self.write(bytes[index..]); - } - } - - pub fn print(self: Self, comptime format: []const u8, args: anytype) Error!void { - return std.fmt.format(self, format, args); - } - - pub fn writeByte(self: Self, byte: u8) Error!void { - const array = [1]u8{byte}; - return self.writeAll(&array); - } - - pub fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void { - var bytes: [256]u8 = undefined; - @memset(bytes[0..], byte); - - var remaining: usize = n; - while (remaining > 0) { - const to_write = @min(remaining, bytes.len); - try self.writeAll(bytes[0..to_write]); - remaining -= to_write; - } - } - - pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) Error!void { - var i: usize = 0; - while (i < n) : (i += 1) { - try self.writeAll(bytes); - } - } - - pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) Error!void { - var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined; - mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); - return self.writeAll(&bytes); - } - - pub fn writeStruct(self: Self, value: anytype) Error!void { - // Only extern and packed structs have defined in-memory layout. - comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != .Auto); - return self.writeAll(mem.asBytes(&value)); - } - }; -}