zbt

CLI Bittorrent client, written in Zig
Log | Files | Refs | README

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 }