A poolable string builder (aka string buffer) for Zig
0

Configure Feed

Select the types of activity you want to include in your feed.

zig 0.15

Karl Seguin (Aug 21, 2025, 8:09 AM +0800) 30f9512f fdd34230

+20 -58
+1 -1
readme.md
··· 21 21 buf.string(); // "over 9000!" 22 22 ``` 23 23 24 - You can call `buf.writer()` to get an `std.io.Writer`. 24 + You can access `&buf.interface` to get an `*std.io.Writer`. 25 25 26 26 You can use `writeU16Big`, `writeU32Big`, `writeU64Big` and `writeU16Little`, `writeU32Little`, `writeU64Little` to write integer values. 27 27
+19 -57
src/buffer.zig
··· 32 32 // created when we try to write more than static.len 33 33 dynamic: ?[]u8, 34 34 35 + interface: std.Io.Writer, 36 + 35 37 pub fn init(allocator: Allocator, size: usize) !Buffer { 36 38 const static = try allocator.alloc(u8, size); 37 39 return .{ ··· 41 43 .buf = static, 42 44 .static = static, 43 45 .dynamic = null, 46 + .interface = .{ 47 + .buffer = &.{}, 48 + .vtable = &.{ 49 + .drain = drain, 50 + }, 51 + } 44 52 }; 45 53 } 46 54 ··· 50 58 if (self.dynamic) |dyn| { 51 59 (self._da orelse allocator).free(dyn); 52 60 } 61 + } 62 + 63 + pub fn drain(io_w: *std.io.Writer, data: []const []const u8, splat: usize) error{WriteFailed}!usize { 64 + _ = splat; 65 + const self: *Buffer = @alignCast(@fieldParentPtr("interface", io_w)); 66 + self.write(data[0]) catch return error.WriteFailed; 67 + return data[0].len; 53 68 } 54 69 55 70 pub fn reset(self: *Buffer) void { ··· 217 232 @memcpy(c, self.buf[0..pos]); 218 233 return c; 219 234 } 220 - 221 - pub fn writer(self: *Buffer) Writer { 222 - return .init(self); 223 - } 224 - 225 - pub const Writer = struct { 226 - w: *Buffer, 227 - interface: std.io.Writer, 228 - 229 - pub const Error = Allocator.Error; 230 - 231 - fn init(w: *Buffer) Writer { 232 - return .{ 233 - .w = w, 234 - .interface = .{ 235 - .vtable = &.{ 236 - .drain = drain, 237 - }, 238 - .buffer = &.{}, 239 - }, 240 - }; 241 - } 242 - 243 - pub fn adaptToNewApi(self: Writer) Adapter { 244 - return .{ .new_interface = self.interface }; 245 - } 246 - 247 - pub fn drain(io_w: *std.io.Writer, data: []const []const u8, splat: usize) error{WriteFailed}!usize { 248 - _ = splat; 249 - const self: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); 250 - self.w.write(data[0]) catch return error.WriteFailed; 251 - return data[0].len; 252 - } 253 - 254 - // Legacy API 255 - pub fn writeByte(self: Writer, b: u8) !void { 256 - return self.w.writeByte(b); 257 - } 258 - pub fn writeByteNTimes(self: *Writer, b: u8, n: usize) !void { 259 - return self.w.writeByteNTimes(b, n); 260 - } 261 - pub fn print(self: *Writer, comptime fmt: []const u8, args: anytype) !void { 262 - return self.interface.print(fmt, args) catch return error.OutOfMemory; 263 - } 264 - pub fn writeAll(self: Writer, data: []const u8) !void { 265 - return self.w.write(data); 266 - } 267 - 268 - pub const Adapter = struct { 269 - err: ?Error = null, 270 - new_interface: std.Io.Writer, 271 - }; 272 - }; 273 235 }; 274 236 275 237 pub const View = struct { ··· 488 450 } 489 451 490 452 test "fuzz" { 491 - var control = std.ArrayList(u8).init(t.allocator); 492 - defer control.deinit(); 453 + var control: std.ArrayList(u8) = .empty; 454 + defer control.deinit(t.allocator); 493 455 494 456 var r = t.getRandom(); 495 457 const random = r.random(); ··· 506 468 for (1..100) |_| { 507 469 const input = testString(aa, random); 508 470 try w.write(input); 509 - try control.appendSlice(input); 471 + try control.appendSlice(t.allocator, input); 510 472 try t.expectString(control.items, w.string()); 511 473 } 512 474 w.reset(); ··· 519 481 var w = try Buffer.init(t.allocator, 10); 520 482 defer w.deinit(); 521 483 522 - try std.json.stringify(.{ .over = 9000, .spice = "must flow", .ok = true }, .{}, w.writer()); 484 + try std.json.Stringify.value(.{ .over = 9000, .spice = "must flow", .ok = true }, .{}, &w.interface); 523 485 try t.expectString("{\"over\":9000,\"spice\":\"must flow\",\"ok\":true}", w.string()); 524 486 } 525 487