| 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 | 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 { | |
| 1828 | var buf = ArrayList(u8).init(ally); | |
| 1829 | if (opt_cwd) |cwd| try buf.writer().print("cd {s} && ", .{cwd}); | |
| 1827 | fn allocPrintCmd(gpa: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 { | |
| 1828 | var buf: std.ArrayListUnmanaged(u8) = .empty; | |
| 1829 | if (opt_cwd) |cwd| try buf.print(gpa, "cd {s} && ", .{cwd}); | |
| 1830 | 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 | 1836 | fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void { |
| ... | ... | @@ -2766,11 +2766,10 @@ fn dumpBadDirnameHelp( |
| 2766 | 2766 | comptime msg: []const u8, |
| 2767 | 2767 | args: anytype, |
| 2768 | 2768 | ) anyerror!void { |
| 2769 | debug.lockStdErr(); | |
| 2769 | var w = debug.lockStdErr2(); | |
| 2770 | 2770 | defer debug.unlockStdErr(); |
| 2771 | 2771 | |
| 2772 | 2772 | const stderr = io.getStdErr(); |
| 2773 | const w = stderr.writer(); | |
| 2774 | 2773 | try w.print(msg, args); |
| 2775 | 2774 | |
| 2776 | 2775 | const tty_config = std.io.tty.detectConfig(stderr); |
| ... | ... | @@ -2803,7 +2802,7 @@ pub fn dumpBadGetPathHelp( |
| 2803 | 2802 | src_builder: *Build, |
| 2804 | 2803 | asking_step: ?*Step, |
| 2805 | 2804 | ) anyerror!void { |
| 2806 | const w = stderr.writer(); | |
| 2805 | var w = stderr.unbufferedWriter(); | |
| 2807 | 2806 | try w.print( |
| 2808 | 2807 | \\getPath() was called on a GeneratedFile that wasn't built yet. |
| 2809 | 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 | 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 | 1013 | pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed); |
| 1005 | 1014 | |
| 1006 | 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 | 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 | 98 | /// The `iovecs` parameter is mutable in case this function needs to mutate |
| 101 | 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 | 101 | // This can be implemented in terms of writev, or specialized if desired. |
| 104 | 102 | _ = .{ this, iovecs }; |
| 105 | 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 | 1669 | if (!enabled) return; |
| 1670 | 1670 | |
| 1671 | 1671 | const tty_config = io.tty.detectConfig(std.io.getStdErr()); |
| 1672 | const stderr = io.getStdErr().writer(); | |
| 1672 | var stderr = lockStdErr2(); | |
| 1673 | defer unlockStdErr(); | |
| 1673 | 1674 | const end = @min(t.index, size); |
| 1674 | 1675 | const debug_info = getSelfDebugInfo() catch |err| { |
| 1675 | 1676 | stderr.print( |
| ... | ... | @@ -1686,7 +1687,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize |
| 1686 | 1687 | .index = frames.len, |
| 1687 | 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 | 1692 | if (t.index > end) { |
| 1692 | 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 | 1621 | |
| 1622 | 1622 | var iovecs_buffer: [max_buffers_len]std.posix.iovec_const = undefined; |
| 1623 | 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 | 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 | 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 | 292 | /// Deprecated; consider switching to `AnyReader` or use `GenericReader` |
| 354 | 293 | /// to use previous API. To be removed after 0.14.0 is tagged. |
| 355 | 294 | pub const Reader = GenericReader; |
| ... | ... | @@ -362,6 +301,7 @@ pub const AnyWriter = Writer; |
| 362 | 301 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; |
| 363 | 302 | |
| 364 | 303 | pub const BufferedWriter = @import("io/BufferedWriter.zig"); |
| 304 | pub const ArrayListWriter = @import("io/ArrayListWriter.zig"); | |
| 365 | 305 | |
| 366 | 306 | pub const BufferedReader = @import("io/buffered_reader.zig").BufferedReader; |
| 367 | 307 | pub const bufferedReader = @import("io/buffered_reader.zig").bufferedReader; |
| ... | ... | @@ -844,6 +784,7 @@ test { |
| 844 | 784 | _ = Writer; |
| 845 | 785 | _ = CountingWriter; |
| 846 | 786 | _ = FixedBufferStream; |
| 787 | _ = ArrayListWriter; | |
| 847 | 788 | _ = @import("io/bit_reader.zig"); |
| 848 | 789 | _ = @import("io/bit_writer.zig"); |
| 849 | 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 | 19 | /// vectors through the underlying write calls as possible. |
| 20 | 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 | 22 | pub fn writer(bw: *BufferedWriter) Writer { |
| 33 | 23 | return .{ |
| 34 | 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 | 37 | /// Replaces the `BufferedWriter` with a new one that writes to `buffer` and |
| 40 | 38 | /// returns `error.NoSpaceLeft` when it is full. |
| 41 | 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 | 95 | end = new_end; |
| 98 | 96 | continue; |
| 99 | 97 | } |
| 98 | if (end == 0) return bw.unbuffered_writer.writev(data); | |
| 100 | 99 | var buffers: [max_buffers_len][]const u8 = undefined; |
| 101 | 100 | buffers[0] = buffer[0..end]; |
| 102 | 101 | const remaining_data = data[i..]; |
| ... | ... | @@ -365,6 +364,7 @@ fn passthru_writeFile( |
| 365 | 364 | ) anyerror!usize { |
| 366 | 365 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 367 | 366 | const buffer = bw.buffer; |
| 367 | if (buffer.len == 0) return bw.unbuffered_writer.writeFile(file, offset, len, headers_and_trailers, headers_len); | |
| 368 | 368 | const start_end = bw.end; |
| 369 | 369 | const headers = headers_and_trailers[0..headers_len]; |
| 370 | 370 | const trailers = headers_and_trailers[headers_len..]; |