| author | |
| committer | |
| log | c2fc6b0b6cc0d5fa6eb6134ac16ba63c9a0059c4 |
| tree | ae6226b75f2466fd9fc37c14a527f9468099cde4 |
| parent | 00c6c836a66db0bc08309534a49d4c5941a416aa |
8 files changed, 164 insertions(+), 86 deletions(-)
lib/std/Build.zig+7-8| ... | @@ -1824,13 +1824,13 @@ pub fn validateUserInputDidItFail(b: *Build) bool { | ... | @@ -1824,13 +1824,13 @@ pub fn validateUserInputDidItFail(b: *Build) bool { |
| 1824 | return b.invalid_user_input; | 1824 | return b.invalid_user_input; |
| 1825 | } | 1825 | } |
| 1826 | 1826 | ||
| 1827 | fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 { | 1827 | fn allocPrintCmd(gpa: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 { |
| 1828 | var buf = ArrayList(u8).init(ally); | 1828 | var buf: std.ArrayListUnmanaged(u8) = .empty; |
| 1829 | if (opt_cwd) |cwd| try buf.writer().print("cd {s} && ", .{cwd}); | 1829 | if (opt_cwd) |cwd| try buf.print(gpa, "cd {s} && ", .{cwd}); |
| 1830 | for (argv) |arg| { | 1830 | for (argv) |arg| { |
| 1831 | try buf.writer().print("{s} ", .{arg}); | 1831 | try buf.print(gpa, "{s} ", .{arg}); |
| 1832 | } | 1832 | } |
| 1833 | return buf.toOwnedSlice(); | 1833 | return buf.toOwnedSlice(gpa); |
| 1834 | } | 1834 | } |
| 1835 | 1835 | ||
| 1836 | fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void { | 1836 | fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void { |
| ... | @@ -2766,11 +2766,10 @@ fn dumpBadDirnameHelp( | ... | @@ -2766,11 +2766,10 @@ fn dumpBadDirnameHelp( |
| 2766 | comptime msg: []const u8, | 2766 | comptime msg: []const u8, |
| 2767 | args: anytype, | 2767 | args: anytype, |
| 2768 | ) anyerror!void { | 2768 | ) anyerror!void { |
| 2769 | debug.lockStdErr(); | 2769 | var w = debug.lockStdErr2(); |
| 2770 | defer debug.unlockStdErr(); | 2770 | defer debug.unlockStdErr(); |
| 2771 | 2771 | ||
| 2772 | const stderr = io.getStdErr(); | 2772 | const stderr = io.getStdErr(); |
| 2773 | const w = stderr.writer(); | ||
| 2774 | try w.print(msg, args); | 2773 | try w.print(msg, args); |
| 2775 | 2774 | ||
| 2776 | const tty_config = std.io.tty.detectConfig(stderr); | 2775 | const tty_config = std.io.tty.detectConfig(stderr); |
| ... | @@ -2803,7 +2802,7 @@ pub fn dumpBadGetPathHelp( | ... | @@ -2803,7 +2802,7 @@ pub fn dumpBadGetPathHelp( |
| 2803 | src_builder: *Build, | 2802 | src_builder: *Build, |
| 2804 | asking_step: ?*Step, | 2803 | asking_step: ?*Step, |
| 2805 | ) anyerror!void { | 2804 | ) anyerror!void { |
| 2806 | const w = stderr.writer(); | 2805 | var w = stderr.unbufferedWriter(); |
| 2807 | try w.print( | 2806 | try w.print( |
| 2808 | \\getPath() was called on a GeneratedFile that wasn't built yet. | 2807 | \\getPath() was called on a GeneratedFile that wasn't built yet. |
| 2809 | \\ source package path: {s} | 2808 | \\ source package path: {s} |
lib/std/array_list.zig+9| ... | @@ -1001,6 +1001,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig | ... | @@ -1001,6 +1001,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1001 | return m.len; | 1001 | return m.len; |
| 1002 | } | 1002 | } |
| 1003 | 1003 | ||
| 1004 | pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { | ||
| 1005 | comptime assert(T == u8); | ||
| 1006 | try self.ensureUnusedCapacity(gpa, fmt.len); | ||
| 1007 | var alw: std.io.ArrayListWriter = undefined; | ||
| 1008 | const bw = alw.fromOwned(gpa, self); | ||
| 1009 | defer self.* = alw.toOwned(); | ||
| 1010 | bw.print(fmt, args) catch return error.OutOfMemory; | ||
| 1011 | } | ||
| 1012 | |||
| 1004 | pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed); | 1013 | pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed); |
| 1005 | 1014 | ||
| 1006 | /// Initializes a Writer which will append to the list but will return | 1015 | /// Initializes a Writer which will append to the list but will return |
lib/std/crypto/tls/Client.zig+1-3| ... | @@ -95,11 +95,9 @@ pub const StreamInterface = struct { | ... | @@ -95,11 +95,9 @@ pub const StreamInterface = struct { |
| 95 | @panic("unimplemented"); | 95 | @panic("unimplemented"); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | /// Returns the number of bytes read, which may be less than the buffer | ||
| 99 | /// space provided, indicating end-of-stream. | ||
| 100 | /// The `iovecs` parameter is mutable in case this function needs to mutate | 98 | /// The `iovecs` parameter is mutable in case this function needs to mutate |
| 101 | /// the fields in order to handle partial writes from the underlying layer. | 99 | /// the fields in order to handle partial writes from the underlying layer. |
| 102 | pub fn writevAll(this: @This(), iovecs: []std.posix.iovec_const) WriteError!usize { | 100 | pub fn writevAll(this: @This(), iovecs: []std.posix.iovec_const) WriteError!void { |
| 103 | // This can be implemented in terms of writev, or specialized if desired. | 101 | // This can be implemented in terms of writev, or specialized if desired. |
| 104 | _ = .{ this, iovecs }; | 102 | _ = .{ this, iovecs }; |
| 105 | @panic("unimplemented"); | 103 | @panic("unimplemented"); |
lib/std/debug.zig+3-2| ... | @@ -1669,7 +1669,8 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize | ... | @@ -1669,7 +1669,8 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize |
| 1669 | if (!enabled) return; | 1669 | if (!enabled) return; |
| 1670 | 1670 | ||
| 1671 | const tty_config = io.tty.detectConfig(std.io.getStdErr()); | 1671 | const tty_config = io.tty.detectConfig(std.io.getStdErr()); |
| 1672 | const stderr = io.getStdErr().writer(); | 1672 | var stderr = lockStdErr2(); |
| 1673 | defer unlockStdErr(); | ||
| 1673 | const end = @min(t.index, size); | 1674 | const end = @min(t.index, size); |
| 1674 | const debug_info = getSelfDebugInfo() catch |err| { | 1675 | const debug_info = getSelfDebugInfo() catch |err| { |
| 1675 | stderr.print( | 1676 | stderr.print( |
| ... | @@ -1686,7 +1687,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize | ... | @@ -1686,7 +1687,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize |
| 1686 | .index = frames.len, | 1687 | .index = frames.len, |
| 1687 | .instruction_addresses = frames, | 1688 | .instruction_addresses = frames, |
| 1688 | }; | 1689 | }; |
| 1689 | writeStackTrace(stack_trace, stderr, debug_info, tty_config) catch continue; | 1690 | writeStackTrace(stack_trace, &stderr, debug_info, tty_config) catch continue; |
| 1690 | } | 1691 | } |
| 1691 | if (t.index > end) { | 1692 | if (t.index > end) { |
| 1692 | stderr.print("{d} more traces not shown; consider increasing trace size\n", .{ | 1693 | stderr.print("{d} more traces not shown; consider increasing trace size\n", .{ |
lib/std/fs/File.zig+4-1| ... | @@ -1621,7 +1621,10 @@ const interface = struct { | ... | @@ -1621,7 +1621,10 @@ const interface = struct { |
| 1621 | 1621 | ||
| 1622 | var iovecs_buffer: [max_buffers_len]std.posix.iovec_const = undefined; | 1622 | var iovecs_buffer: [max_buffers_len]std.posix.iovec_const = undefined; |
| 1623 | const iovecs = iovecs_buffer[0..@min(iovecs_buffer.len, data.len)]; | 1623 | const iovecs = iovecs_buffer[0..@min(iovecs_buffer.len, data.len)]; |
| 1624 | for (iovecs, data[0..iovecs.len]) |*v, d| v.* = .{ .base = d.ptr, .len = d.len }; | 1624 | for (iovecs, data[0..iovecs.len]) |*v, d| v.* = .{ |
| 1625 | .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length. | ||
| 1626 | .len = d.len, | ||
| 1627 | }; | ||
| 1625 | return std.posix.writev(file, iovecs); | 1628 | return std.posix.writev(file, iovecs); |
| 1626 | } | 1629 | } |
| 1627 | 1630 |
lib/std/io.zig+2-61| ... | @@ -289,67 +289,6 @@ pub fn GenericReader( | ... | @@ -289,67 +289,6 @@ pub fn GenericReader( |
| 289 | }; | 289 | }; |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | pub fn GenericWriter( | ||
| 293 | comptime Context: type, | ||
| 294 | comptime WriteError: type, | ||
| 295 | comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize, | ||
| 296 | ) type { | ||
| 297 | return struct { | ||
| 298 | context: Context, | ||
| 299 | |||
| 300 | const Self = @This(); | ||
| 301 | pub const Error = WriteError; | ||
| 302 | |||
| 303 | pub inline fn write(self: Self, bytes: []const u8) Error!usize { | ||
| 304 | return writeFn(self.context, bytes); | ||
| 305 | } | ||
| 306 | |||
| 307 | pub inline fn writeAll(self: Self, bytes: []const u8) Error!void { | ||
| 308 | return @errorCast(self.any().writeAll(bytes)); | ||
| 309 | } | ||
| 310 | |||
| 311 | pub inline fn print(self: Self, comptime format: []const u8, args: anytype) Error!void { | ||
| 312 | return @errorCast(self.any().print(format, args)); | ||
| 313 | } | ||
| 314 | |||
| 315 | pub inline fn writeByte(self: Self, byte: u8) Error!void { | ||
| 316 | return @errorCast(self.any().writeByte(byte)); | ||
| 317 | } | ||
| 318 | |||
| 319 | pub inline fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void { | ||
| 320 | return @errorCast(self.any().writeByteNTimes(byte, n)); | ||
| 321 | } | ||
| 322 | |||
| 323 | pub inline fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) Error!void { | ||
| 324 | return @errorCast(self.any().writeBytesNTimes(bytes, n)); | ||
| 325 | } | ||
| 326 | |||
| 327 | pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) Error!void { | ||
| 328 | return @errorCast(self.any().writeInt(T, value, endian)); | ||
| 329 | } | ||
| 330 | |||
| 331 | pub inline fn writeStruct(self: Self, value: anytype) Error!void { | ||
| 332 | return @errorCast(self.any().writeStruct(value)); | ||
| 333 | } | ||
| 334 | |||
| 335 | pub inline fn writeStructEndian(self: Self, value: anytype, endian: std.builtin.Endian) Error!void { | ||
| 336 | return @errorCast(self.any().writeStructEndian(value, endian)); | ||
| 337 | } | ||
| 338 | |||
| 339 | pub inline fn any(self: *const Self) Writer { | ||
| 340 | return .{ | ||
| 341 | .context = @ptrCast(&self.context), | ||
| 342 | .writeFn = typeErasedWriteFn, | ||
| 343 | }; | ||
| 344 | } | ||
| 345 | |||
| 346 | fn typeErasedWriteFn(context: *const anyopaque, bytes: []const u8) anyerror!usize { | ||
| 347 | const ptr: *const Context = @alignCast(@ptrCast(context)); | ||
| 348 | return writeFn(ptr.*, bytes); | ||
| 349 | } | ||
| 350 | }; | ||
| 351 | } | ||
| 352 | |||
| 353 | /// Deprecated; consider switching to `AnyReader` or use `GenericReader` | 292 | /// Deprecated; consider switching to `AnyReader` or use `GenericReader` |
| 354 | /// to use previous API. To be removed after 0.14.0 is tagged. | 293 | /// to use previous API. To be removed after 0.14.0 is tagged. |
| 355 | pub const Reader = GenericReader; | 294 | pub const Reader = GenericReader; |
| ... | @@ -362,6 +301,7 @@ pub const AnyWriter = Writer; | ... | @@ -362,6 +301,7 @@ pub const AnyWriter = Writer; |
| 362 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; | 301 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; |
| 363 | 302 | ||
| 364 | pub const BufferedWriter = @import("io/BufferedWriter.zig"); | 303 | pub const BufferedWriter = @import("io/BufferedWriter.zig"); |
| 304 | pub const ArrayListWriter = @import("io/ArrayListWriter.zig"); | ||
| 365 | 305 | ||
| 366 | pub const BufferedReader = @import("io/buffered_reader.zig").BufferedReader; | 306 | pub const BufferedReader = @import("io/buffered_reader.zig").BufferedReader; |
| 367 | pub const bufferedReader = @import("io/buffered_reader.zig").bufferedReader; | 307 | pub const bufferedReader = @import("io/buffered_reader.zig").bufferedReader; |
| ... | @@ -844,6 +784,7 @@ test { | ... | @@ -844,6 +784,7 @@ test { |
| 844 | _ = Writer; | 784 | _ = Writer; |
| 845 | _ = CountingWriter; | 785 | _ = CountingWriter; |
| 846 | _ = FixedBufferStream; | 786 | _ = FixedBufferStream; |
| 787 | _ = ArrayListWriter; | ||
| 847 | _ = @import("io/bit_reader.zig"); | 788 | _ = @import("io/bit_reader.zig"); |
| 848 | _ = @import("io/bit_writer.zig"); | 789 | _ = @import("io/bit_writer.zig"); |
| 849 | _ = @import("io/buffered_atomic_file.zig"); | 790 | _ = @import("io/buffered_atomic_file.zig"); |
lib/std/io/ArrayListWriter.zig created+127| ... | @@ -0,0 +1,127 @@ | ||
| 1 | //! The straightforward way to use `std.ArrayList` as the underlying writer | ||
| 2 | //! when using `std.io.BufferedWriter` is to populate the `std.io.Writer` | ||
| 3 | //! interface and then use an empty buffer. However, this means that every use | ||
| 4 | //! of `std.io.BufferedWriter` will go through the vtable, including for | ||
| 5 | //! functions such as `writeByte`. This API instead maintains | ||
| 6 | //! `std.io.BufferedWriter` state such that it writes to the unused capacity of | ||
| 7 | //! the array list, filling it up completely before making a call through the | ||
| 8 | //! vtable, causing a resize. Consequently, the same, optimized, non-generic | ||
| 9 | //! machine code that uses `std.io.BufferedReader`, such as formatted printing, | ||
| 10 | //! is also used when the underlying writer is backed by `std.ArrayList`. | ||
| 11 | |||
| 12 | const std = @import("../std.zig"); | ||
| 13 | const ArrayListWriter = @This(); | ||
| 14 | const assert = std.debug.assert; | ||
| 15 | |||
| 16 | items: []u8, | ||
| 17 | allocator: std.mem.Allocator, | ||
| 18 | buffered_writer: std.io.BufferedWriter, | ||
| 19 | |||
| 20 | /// Replaces `array_list` with empty, taking ownership of the memory. | ||
| 21 | pub fn fromOwned( | ||
| 22 | alw: *ArrayListWriter, | ||
| 23 | allocator: std.mem.Allocator, | ||
| 24 | array_list: *std.ArrayListUnmanaged(u8), | ||
| 25 | ) *std.io.BufferedWriter { | ||
| 26 | alw.* = .{ | ||
| 27 | .allocated_slice = array_list.items, | ||
| 28 | .allocator = allocator, | ||
| 29 | .buffered_writer = .{ | ||
| 30 | .unbuffered_writer = .{ | ||
| 31 | .context = alw, | ||
| 32 | .vtable = &.{ | ||
| 33 | .writev = writev, | ||
| 34 | .writeFile = writeFile, | ||
| 35 | }, | ||
| 36 | }, | ||
| 37 | .buffer = array_list.unusedCapacitySlice(), | ||
| 38 | }, | ||
| 39 | }; | ||
| 40 | array_list.* = .empty; | ||
| 41 | return &alw.buffered_writer; | ||
| 42 | } | ||
| 43 | |||
| 44 | /// Returns the memory back that was borrowed with `fromOwned`. | ||
| 45 | pub fn toOwned(alw: *ArrayListWriter) std.ArrayListUnmanaged(u8) { | ||
| 46 | const end = alw.buffered_writer.end; | ||
| 47 | const result: std.ArrayListUnmanaged(u8) = .{ | ||
| 48 | .items = alw.items.ptr[0 .. alw.items.len + end], | ||
| 49 | .capacity = alw.buffered_writer.buffer.len - end, | ||
| 50 | }; | ||
| 51 | alw.* = undefined; | ||
| 52 | return result; | ||
| 53 | } | ||
| 54 | |||
| 55 | fn writev(context: *anyopaque, data: []const []const u8) anyerror!usize { | ||
| 56 | const alw: *ArrayListWriter = @alignCast(@ptrCast(context)); | ||
| 57 | const start_len = alw.items.len; | ||
| 58 | const bw = &alw.buffered_writer; | ||
| 59 | assert(data[0].ptr == alw.items.ptr + start_len); | ||
| 60 | const bw_end = data[0].len; | ||
| 61 | var list: std.ArrayListUnmanaged(u8) = .{ | ||
| 62 | .items = alw.items.ptr[0 .. start_len + bw_end], | ||
| 63 | .capacity = bw.buffer.len - bw_end, | ||
| 64 | }; | ||
| 65 | const rest = data[1..]; | ||
| 66 | var new_capacity: usize = list.capacity; | ||
| 67 | for (rest) |bytes| new_capacity += bytes.len; | ||
| 68 | try list.ensureTotalCapacity(alw.allocator, new_capacity + 1); | ||
| 69 | for (rest) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 70 | alw.items = list.items; | ||
| 71 | bw.buffer = list.unusedCapacitySlice(); | ||
| 72 | return list.items.len - start_len; | ||
| 73 | } | ||
| 74 | |||
| 75 | fn writeFile( | ||
| 76 | context: *anyopaque, | ||
| 77 | file: std.fs.File, | ||
| 78 | offset: u64, | ||
| 79 | len: std.io.Writer.VTable.FileLen, | ||
| 80 | headers_and_trailers_full: []const []const u8, | ||
| 81 | headers_len_full: usize, | ||
| 82 | ) anyerror!usize { | ||
| 83 | const alw: *ArrayListWriter = @alignCast(@ptrCast(context)); | ||
| 84 | const list = alw.array_list; | ||
| 85 | const bw = &alw.buffered_writer; | ||
| 86 | const start_len = list.items.len; | ||
| 87 | const headers_and_trailers, const headers_len = if (headers_len_full >= 1) b: { | ||
| 88 | assert(headers_and_trailers_full[0].ptr == list.items.ptr + start_len); | ||
| 89 | list.items.len += headers_and_trailers_full[0].len; | ||
| 90 | break :b .{ headers_and_trailers_full[1..], headers_len_full - 1 }; | ||
| 91 | } else .{ headers_and_trailers_full, headers_len_full }; | ||
| 92 | const gpa = alw.allocator; | ||
| 93 | const trailers = headers_and_trailers[headers_len..]; | ||
| 94 | if (len == .entire_file) { | ||
| 95 | var new_capacity: usize = list.capacity + std.atomic.cache_line; | ||
| 96 | for (headers_and_trailers) |bytes| new_capacity += bytes.len; | ||
| 97 | try list.ensureTotalCapacity(gpa, new_capacity); | ||
| 98 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 99 | const dest = list.items.ptr[list.items.len..list.capacity]; | ||
| 100 | const n = try file.pread(dest, offset); | ||
| 101 | if (n == 0) { | ||
| 102 | new_capacity = list.capacity; | ||
| 103 | for (trailers) |bytes| new_capacity += bytes.len; | ||
| 104 | try list.ensureTotalCapacity(gpa, new_capacity); | ||
| 105 | for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 106 | bw.buffer = list.unusedCapacitySlice(); | ||
| 107 | return list.items.len - start_len; | ||
| 108 | } | ||
| 109 | list.items.len += n; | ||
| 110 | bw.buffer = list.unusedCapacitySlice(); | ||
| 111 | return list.items.len - start_len; | ||
| 112 | } | ||
| 113 | var new_capacity: usize = list.capacity + len.int(); | ||
| 114 | for (headers_and_trailers) |bytes| new_capacity += bytes.len; | ||
| 115 | try list.ensureTotalCapacity(gpa, new_capacity); | ||
| 116 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 117 | const dest = list.items.ptr[list.items.len..][0..len.int()]; | ||
| 118 | const n = try file.pread(dest, offset); | ||
| 119 | list.items.len += n; | ||
| 120 | if (n < dest.len) { | ||
| 121 | bw.buffer = list.unusedCapacitySlice(); | ||
| 122 | return list.items.len - start_len; | ||
| 123 | } | ||
| 124 | for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 125 | bw.buffer = list.unusedCapacitySlice(); | ||
| 126 | return list.items.len - start_len; | ||
| 127 | } | ||
lib/std/io/BufferedWriter.zig+11-11| ... | @@ -19,23 +19,21 @@ end: usize = 0, | ... | @@ -19,23 +19,21 @@ end: usize = 0, |
| 19 | /// vectors through the underlying write calls as possible. | 19 | /// vectors through the underlying write calls as possible. |
| 20 | pub const max_buffers_len = 8; | 20 | pub const max_buffers_len = 8; |
| 21 | 21 | ||
| 22 | const passthru_vtable: Writer.VTable = .{ | ||
| 23 | .writev = passthru_writev, | ||
| 24 | .writeFile = passthru_writeFile, | ||
| 25 | }; | ||
| 26 | |||
| 27 | const fixed_vtable: Writer.VTable = .{ | ||
| 28 | .writev = fixed_writev, | ||
| 29 | .writeFile = fixed_writeFile, | ||
| 30 | }; | ||
| 31 | |||
| 32 | pub fn writer(bw: *BufferedWriter) Writer { | 22 | pub fn writer(bw: *BufferedWriter) Writer { |
| 33 | return .{ | 23 | return .{ |
| 34 | .context = bw, | 24 | .context = bw, |
| 35 | .vtable = &passthru_vtable, | 25 | .vtable = &.{ |
| 26 | .writev = passthru_writev, | ||
| 27 | .writeFile = passthru_writeFile, | ||
| 28 | }, | ||
| 36 | }; | 29 | }; |
| 37 | } | 30 | } |
| 38 | 31 | ||
| 32 | const fixed_vtable: Writer.VTable = .{ | ||
| 33 | .writev = fixed_writev, | ||
| 34 | .writeFile = fixed_writeFile, | ||
| 35 | }; | ||
| 36 | |||
| 39 | /// Replaces the `BufferedWriter` with a new one that writes to `buffer` and | 37 | /// Replaces the `BufferedWriter` with a new one that writes to `buffer` and |
| 40 | /// returns `error.NoSpaceLeft` when it is full. | 38 | /// returns `error.NoSpaceLeft` when it is full. |
| 41 | pub fn initFixed(bw: *BufferedWriter, buffer: []u8) void { | 39 | pub fn initFixed(bw: *BufferedWriter, buffer: []u8) void { |
| ... | @@ -97,6 +95,7 @@ fn passthru_writev(context: *anyopaque, data: []const []const u8) anyerror!usize | ... | @@ -97,6 +95,7 @@ fn passthru_writev(context: *anyopaque, data: []const []const u8) anyerror!usize |
| 97 | end = new_end; | 95 | end = new_end; |
| 98 | continue; | 96 | continue; |
| 99 | } | 97 | } |
| 98 | if (end == 0) return bw.unbuffered_writer.writev(data); | ||
| 100 | var buffers: [max_buffers_len][]const u8 = undefined; | 99 | var buffers: [max_buffers_len][]const u8 = undefined; |
| 101 | buffers[0] = buffer[0..end]; | 100 | buffers[0] = buffer[0..end]; |
| 102 | const remaining_data = data[i..]; | 101 | const remaining_data = data[i..]; |
| ... | @@ -365,6 +364,7 @@ fn passthru_writeFile( | ... | @@ -365,6 +364,7 @@ fn passthru_writeFile( |
| 365 | ) anyerror!usize { | 364 | ) anyerror!usize { |
| 366 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); | 365 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 367 | const buffer = bw.buffer; | 366 | const buffer = bw.buffer; |
| 367 | if (buffer.len == 0) return bw.unbuffered_writer.writeFile(file, offset, len, headers_and_trailers, headers_len); | ||
| 368 | const start_end = bw.end; | 368 | const start_end = bw.end; |
| 369 | const headers = headers_and_trailers[0..headers_len]; | 369 | const headers = headers_and_trailers[0..headers_len]; |
| 370 | const trailers = headers_and_trailers[headers_len..]; | 370 | const trailers = headers_and_trailers[headers_len..]; |