From 27aef9a965cb9febfa4d1a767d0fb107b0c0f92d Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Sun, 24 May 2026 03:41:51 -0700 Subject: [PATCH] add AllocatingWriter --- allocating_writer.zig | 83 +++++++++++++++++++++++++++++++++++++++++++ nio.zig | 2 ++ 2 files changed, 85 insertions(+) create mode 100644 allocating_writer.zig diff --git a/allocating_writer.zig b/allocating_writer.zig new file mode 100644 index 0000000000000000000000000000000000000000..cbea9806bf0f6294637ec4698a06d028d115cb84 --- /dev/null +++ b/allocating_writer.zig @@ -0,0 +1,83 @@ +const std = @import("std"); +const nio = @import("./nio.zig"); +const builtin = @import("builtin"); + +const sys = switch (builtin.target.os.tag) { + .linux => @import("sys-linux"), + else => unreachable, +}; + +pub const AllocatingWriter = struct { + allocator: std.mem.Allocator, + items: []u8, + capacity: usize, + + pub fn init(allocator: std.mem.Allocator) AllocatingWriter { + return .{ + .allocator = allocator, + .items = "", + .capacity = 0, + }; + } + + pub fn deinit(self: *AllocatingWriter) void { + self.allocator.free(self.allocatedSlice()); + } + + pub fn allocatedSlice(self: *AllocatingWriter) []u8 { + return self.items.ptr[0..self.capacity]; + } + + pub fn toOwnedSlice(self: *AllocatingWriter) ![]u8 { + if (self.allocator.resize(self.allocatedSlice(), self.items.len)) { + defer self.capacity = 0; + defer self.items = ""; + return self.items; + } + const new_slice = try self.allocator.dupe(u8, self.items); + self.allocator.free(self.allocatedSlice()); + return new_slice; + } + + pub fn ensureUnusedCapacity(self: *AllocatingWriter, capacity: usize) !void { + if (self.capacity - self.items.len >= capacity) return; + const len = self.items.len; + const new_capacity = std.math.ceilPowerOfTwo(usize, @max(len + capacity, self.capacity)) catch return error.OutOfMemory; + const new_slice = try self.allocator.alloc(u8, new_capacity); + @memcpy(new_slice[0..len], self.items); + self.allocator.free(self.allocatedSlice()); + self.items = new_slice; + self.items.len = len; + self.capacity = new_capacity; + } + + fn unusedSlice(self: *AllocatingWriter) []u8 { + return self.allocatedSlice()[self.items.len..]; + } + + const W = nio.Writable(@This(), ._var); + pub const writeAll = W.writeAll; + pub const writevAll = W.writevAll; + pub const writeByteNTimes = W.writeByteNTimes; + pub const writeNTimes = W.writeNTimes; + pub const writeInt = W.writeInt; + pub const writeStruct = W.writeStruct; + pub const writeIntPretty = W.writeIntPretty; + pub const print = W.print; + + pub const WriteError = std.mem.Allocator.Error; + + pub fn write(self: *AllocatingWriter, bytes: []const u8) WriteError!usize { + try self.ensureUnusedCapacity(bytes.len); + @memcpy(self.unusedSlice()[0..bytes.len], bytes); + self.items.len += bytes.len; + return bytes.len; + } + pub fn writev(self: *AllocatingWriter, iovec: []const sys.struct_iovec) WriteError!usize { + var len: usize = 0; + for (iovec) |vec| len += vec.len; + try self.ensureUnusedCapacity(len); + for (iovec) |vec| _ = self.write(vec.base[0..vec.len]) catch unreachable; + return len; + } +}; diff --git a/nio.zig b/nio.zig index aca5349ad61e05dd4c09e0ad5e3f16c9ce33b245..cc002e0db93ed31e14b258ab25d30359d2417a48 100644 --- a/nio.zig +++ b/nio.zig @@ -337,3 +337,5 @@ pub const BufferedWriter = @import("./buffered_writer.zig").BufferedWriter; pub const CountingWriter = @import("./counting_writer.zig").CountingWriter; pub const NullWriter = @import("./null_writer.zig").NullWriter; + +pub const AllocatingWriter = @import("./allocating_writer.zig").AllocatingWriter; -- 2.54.0