anywriter.zig (2665B)
1 //! std.io.Writer drop in replacement that uses function pointer instead of 2 //! compile time construct. Analogous to std.io.AnyReader. 3 4 const std = @import("std"); 5 const AnyWriter = @This(); 6 pub const Error = anyerror; 7 8 context: *const anyopaque, 9 writeFn: *const fn (context: *const anyopaque, buffer: []const u8) anyerror!usize, 10 11 // Must create a wrapper around the original writer in order to add a typeErasedWriteFn 12 // and keep a reference to it alive until we're done writing to it 13 // Usage might look like this: 14 // var wrap = AnyWriter.wrapper(myWriter); 15 // var aw = wrap.any(); 16 pub fn wrapper(writer: anytype) Wrapper(@TypeOf(writer)) { 17 return .{ .ww = writer }; 18 } 19 pub fn Wrapper(comptime writerType: type) type { 20 return struct { 21 ww: writerType, 22 fn typeErasedWriteFn(context: *const anyopaque, buffer: []const u8) anyerror!usize { 23 const self: *const @This() = @alignCast(@ptrCast(context)); 24 return self.ww.write(buffer); 25 } 26 pub fn any(self: *@This()) AnyWriter { 27 return .{ 28 .context = @ptrCast(self), 29 .writeFn = &typeErasedWriteFn, 30 }; 31 } 32 }; 33 } 34 35 pub fn write(self: AnyWriter, bytes: []const u8) anyerror!usize { 36 return self.writeFn(self.context, bytes); 37 } 38 39 pub fn writeAll(self: AnyWriter, bytes: []const u8) anyerror!void { 40 var index: usize = 0; 41 while (index != bytes.len) { 42 index += try self.write(bytes[index..]); 43 } 44 } 45 46 pub fn print(self: AnyWriter, comptime format: []const u8, args: anytype) anyerror!void { 47 return std.fmt.format(self, format, args); 48 } 49 50 pub fn writeByte(self: AnyWriter, byte: u8) anyerror!void { 51 const array = [1]u8{byte}; 52 return self.writeAll(&array); 53 } 54 55 pub fn writeByteNTimes(self: AnyWriter, byte: u8, n: usize) anyerror!void { 56 var bytes: [256]u8 = undefined; 57 @memset(bytes[0..], byte); 58 59 var remaining: usize = n; 60 while (remaining > 0) { 61 const to_write = @min(remaining, bytes.len); 62 try self.writeAll(bytes[0..to_write]); 63 remaining -= to_write; 64 } 65 } 66 67 pub inline fn writeInt(self: AnyWriter, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void { 68 var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined; 69 std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); 70 return self.writeAll(&bytes); 71 } 72 73 pub fn writeStruct(self: AnyWriter, value: anytype) anyerror!void { 74 // Only extern and packed structs have defined in-memory layout. 75 comptime std.debug.assert(@typeInfo(@TypeOf(value)).Struct.layout != .Auto); 76 return self.writeAll(std.mem.asBytes(&value)); 77 }