//! std.io.Writer drop in replacement that uses function pointer instead of //! compile time construct. Analogous to std.io.AnyReader. const std = @import("std"); const AnyWriter = @This(); pub const Error = anyerror; context: *const anyopaque, writeFn: *const fn (context: *const anyopaque, buffer: []const u8) anyerror!usize, // Must create a wrapper around the original writer in order to add a typeErasedWriteFn // and keep a reference to it alive until we're done writing to it // Usage might look like this: // var wrap = AnyWriter.wrapper(myWriter); // var aw = wrap.any(); pub fn wrapper(writer: anytype) Wrapper(@TypeOf(writer)) { return .{ .ww = writer }; } pub fn Wrapper(comptime writerType: type) type { return struct { ww: writerType, fn typeErasedWriteFn(context: *const anyopaque, buffer: []const u8) anyerror!usize { const self: *const @This() = @alignCast(@ptrCast(context)); return self.ww.write(buffer); } pub fn any(self: *@This()) AnyWriter { return .{ .context = @ptrCast(self), .writeFn = &typeErasedWriteFn, }; } }; } pub fn write(self: AnyWriter, bytes: []const u8) anyerror!usize { return self.writeFn(self.context, bytes); } pub fn writeAll(self: AnyWriter, bytes: []const u8) anyerror!void { var index: usize = 0; while (index != bytes.len) { index += try self.write(bytes[index..]); } } pub fn print(self: AnyWriter, comptime format: []const u8, args: anytype) anyerror!void { return std.fmt.format(self, format, args); } pub fn writeByte(self: AnyWriter, byte: u8) anyerror!void { const array = [1]u8{byte}; return self.writeAll(&array); } pub fn writeByteNTimes(self: AnyWriter, 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 inline fn writeInt(self: AnyWriter, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void { var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined; std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); return self.writeAll(&bytes); } pub fn writeStruct(self: AnyWriter, value: anytype) anyerror!void { // Only extern and packed structs have defined in-memory layout. comptime std.debug.assert(@typeInfo(@TypeOf(value)).Struct.layout != .Auto); return self.writeAll(std.mem.asBytes(&value)); }