authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-06-23 03:48:12-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:29-07:00
logaf24e722fba2245d50473dc7a6fb7671851e07dc
tree4dbc325e0836ffe5a62857c05d9949087251691c
parent52b3275eb2cc11a9d81510f465458208eddfd796

update some stuff to std.io API


13 files changed, 102 insertions(+), 67 deletions(-)

lib/std/debug.zig+1-1
......@@ -588,7 +588,7 @@ pub fn panicExtra(
588588 // a minor annoyance with this is that it will result in the NoSpaceLeft
589589 // error being part of the @panic stack trace (but that error should
590590 // only happen rarely)
591 const msg = if (bw.print(format, args)) |_| bw.getWritten() else |_| blk: {
591 const msg = if (bw.print(format, args)) |_| bw.buffered() else |_| blk: {
592592 @memcpy(buf[size..], trunc_msg);
593593 break :blk &buf;
594594 };
lib/std/fs/Dir.zig+2-5
......@@ -2612,10 +2612,7 @@ pub fn updateFile(
26122612 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode });
26132613 defer atomic_file.deinit();
26142614
2615 var src_reader: File.Reader = .{
2616 .file = src_file,
2617 .size = src_stat.size,
2618 };
2615 var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size);
26192616 var buffer: [2000]u8 = undefined;
26202617 var dest_writer = atomic_file.file_writer.writer(&buffer);
26212618
......@@ -2658,7 +2655,7 @@ pub fn copyFile(
26582655 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });
26592656 defer atomic_file.deinit();
26602657
2661 try copy_file(in_file.handle, atomic_file.file.handle, size);
2658 try copy_file(in_file.handle, atomic_file.file_writer.file.handle, size);
26622659 try atomic_file.finish();
26632660}
26642661
lib/std/fs/File.zig+12-7
......@@ -961,6 +961,14 @@ pub const Reader = struct {
961961 };
962962 }
963963
964 pub fn initSize(file: File, buffer: []u8, size: u64) Reader {
965 return .{
966 .file = file,
967 .interface = initInterface(buffer),
968 .size = size,
969 };
970 }
971
964972 pub fn getSize(r: *Reader) GetEndPosError!u64 {
965973 return r.size orelse {
966974 if (r.size_err) |err| return err;
......@@ -1436,18 +1444,15 @@ pub fn readerStreaming(file: File) Reader {
14361444///
14371445/// Positional is more threadsafe, since the global seek position is not
14381446/// affected.
1439pub fn writer(file: File) Writer {
1440 return .{ .file = file };
1447pub fn writer(file: File, buffer: []u8) Writer {
1448 return .init(file, buffer);
14411449}
14421450
14431451/// Positional is more threadsafe, since the global seek position is not
14441452/// affected, but when such syscalls are not available, preemptively choosing
14451453/// `Writer.Mode.streaming` will skip a failed syscall.
1446pub fn writerStreaming(file: File) Writer {
1447 return .{
1448 .file = file,
1449 .mode = .streaming,
1450 };
1454pub fn writerStreaming(file: File, buffer: []u8) Writer {
1455 return .initMode(file, buffer, .streaming);
14511456}
14521457
14531458const range_off: windows.LARGE_INTEGER = 0;
lib/std/http.zig+8-1
......@@ -433,12 +433,18 @@ pub const Reader = struct {
433433 ///
434434 /// See also:
435435 /// * `interfaceDecompressing`
436 pub fn bodyReader(reader: *Reader, transfer_encoding: TransferEncoding, content_length: ?u64) std.io.Reader {
436 pub fn bodyReader(
437 reader: *Reader,
438 buffer: []u8,
439 transfer_encoding: TransferEncoding,
440 content_length: ?u64,
441 ) std.io.Reader {
437442 assert(reader.state == .received_head);
438443 return switch (transfer_encoding) {
439444 .chunked => {
440445 reader.state = .{ .body_remaining_chunk_len = .head };
441446 return .{
447 .buffer = buffer,
442448 .context = reader,
443449 .vtable = &.{
444450 .read = chunkedRead,
......@@ -450,6 +456,7 @@ pub const Reader = struct {
450456 if (content_length) |len| {
451457 reader.state = .{ .body_remaining_content_length = len };
452458 return .{
459 .buffer = buffer,
453460 .context = reader,
454461 .vtable = &.{
455462 .read = contentLengthRead,
lib/std/http/Client.zig+2-2
......@@ -667,11 +667,11 @@ pub const Response = struct {
667667 ///
668668 /// See also:
669669 /// * `readerDecompressing`
670 pub fn reader(response: *Response) std.io.Reader {
670 pub fn reader(response: *Response, buffer: []u8) std.io.Reader {
671671 const req = response.request;
672672 if (!req.method.responseHasBody()) return .ending;
673673 const head = &response.head;
674 return req.reader.bodyReader(head.transfer_encoding, head.content_length);
674 return req.reader.bodyReader(buffer, head.transfer_encoding, head.content_length);
675675 }
676676
677677 /// If compressed body has been negotiated this will return decompressed bytes.
lib/std/http/test.zig+2-1
......@@ -1198,8 +1198,9 @@ test "redirect to different connection" {
11981198
11991199 try req.sendBodiless();
12001200 var response = try req.receiveHead(&redirect_buffer);
1201 var reader = response.reader(&.{});
12011202
1202 const body = try response.reader().readRemainingAlloc(gpa, .limited(8192));
1203 const body = try reader.allocRemaining(gpa, .limited(8192));
12031204 defer gpa.free(body);
12041205
12051206 try expectEqualStrings("good job, you pass", body);
lib/std/io/Reader.zig+29-5
......@@ -162,9 +162,9 @@ pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
162162 };
163163 if (n > @intFromEnum(limit)) {
164164 const over_amt = n - @intFromEnum(limit);
165 assert(over_amt <= w.buffer.len); // limit may be exceeded only by an amount within buffer capacity.
166165 r.seek = w.end - over_amt;
167166 r.end = w.end;
167 assert(r.end <= w.buffer.len); // limit may be exceeded only by an amount within buffer capacity.
168168 return @intFromEnum(limit);
169169 }
170170 return n;
......@@ -740,12 +740,20 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
740740 }
741741 if (seek > 0) {
742742 const remainder = buffer[seek..];
743 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
743 @memmove(buffer[0..remainder.len], remainder);
744744 r.end = remainder.len;
745745 r.seek = 0;
746746 }
747 var writer: Writer = .{
748 .buffer = r.buffer,
749 .vtable = &.{ .drain = Writer.fixedDrain },
750 };
747751 while (r.end < r.buffer.len) {
748 const n = try r.unbuffered_reader.readVec(&.{r.buffer[r.end..]});
752 writer.end = r.end;
753 const n = r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) {
754 error.WriteFailed => unreachable,
755 else => |e| return e,
756 };
749757 const prev_end = r.end;
750758 r.end = prev_end + n;
751759 if (std.mem.indexOfScalarPos(u8, r.buffer[0..r.end], prev_end, delimiter)) |end| {
......@@ -929,8 +937,16 @@ pub fn fill(r: *Reader, n: usize) Error!void {
929937 return;
930938 }
931939 rebaseCapacity(r, n);
940 var writer: Writer = .{
941 .buffer = r.buffer,
942 .vtable = &.{ .drain = Writer.fixedDrain },
943 };
932944 while (r.end < r.seek + n) {
933 r.end += try r.unbuffered_reader.readVec(&.{r.buffer[r.end..]});
945 writer.end = r.end;
946 r.end += r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) {
947 error.WriteFailed => unreachable,
948 else => |e| return e,
949 };
934950 }
935951}
936952
......@@ -941,7 +957,15 @@ pub fn fill(r: *Reader, n: usize) Error!void {
941957/// Asserts buffer capacity is at least 1.
942958pub fn fillMore(r: *Reader) Error!void {
943959 rebaseCapacity(r, 1);
944 r.end += try r.unbuffered_reader.readVec(&.{r.buffer[r.end..]});
960 var writer: Writer = .{
961 .buffer = r.buffer,
962 .end = r.end,
963 .vtable = &.{ .drain = Writer.fixedDrain },
964 };
965 r.end += r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) {
966 error.WriteFailed => unreachable,
967 else => |e| return e,
968 };
945969}
946970
947971/// Returns the next byte from the stream or returns `error.EndOfStream`.
lib/std/io/Writer.zig+24-20
......@@ -1722,7 +1722,7 @@ pub fn unimplementedSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit
17221722/// time to return an error. However, we still need to make sure all of the
17231723/// available buffer has been filled. Also, it may be called from `flush` in
17241724/// which case it should return successfully.
1725fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
1725pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
17261726 if (data.len == 0) return 0;
17271727 for (data[0 .. data.len - 1]) |bytes| {
17281728 const dest = w.buffer[w.end..];
......@@ -1860,24 +1860,30 @@ pub const Allocating = struct {
18601860 pub fn init(allocator: Allocator) Allocating {
18611861 return .{
18621862 .allocator = allocator,
1863 .interface = init_interface,
1864 .buffer = &.{},
1863 .interface = .{
1864 .buffer = &.{},
1865 .vtable = &vtable,
1866 },
18651867 };
18661868 }
18671869
18681870 pub fn initCapacity(allocator: Allocator, capacity: usize) error{OutOfMemory}!Allocating {
18691871 return .{
18701872 .allocator = allocator,
1871 .interface = init_interface,
1872 .buffer = try allocator.alloc(u8, capacity),
1873 .interface = .{
1874 .buffer = try allocator.alloc(u8, capacity),
1875 .vtable = &vtable,
1876 },
18731877 };
18741878 }
18751879
18761880 pub fn initOwnedSlice(allocator: Allocator, slice: []u8) Allocating {
18771881 return .{
18781882 .allocator = allocator,
1879 .interface = init_interface,
1880 .buffer = slice,
1883 .interface = .{
1884 .buffer = slice,
1885 .vtable = &vtable,
1886 },
18811887 };
18821888 }
18831889
......@@ -1886,23 +1892,21 @@ pub const Allocating = struct {
18861892 defer array_list.* = .empty;
18871893 return .{
18881894 .allocator = allocator,
1889 .interface = init_interface,
1890 .buffer = array_list.allocatedSlice(),
1891 .end = array_list.items.len,
1895 .interface = .{
1896 .vtable = &vtable,
1897 .buffer = array_list.allocatedSlice(),
1898 .end = array_list.items.len,
1899 },
18921900 };
18931901 }
18941902
1895 const init_interface: Writer = .{
1896 .interface = .{
1897 .vtable = &.{
1898 .drain = Allocating.drain,
1899 .sendFile = Allocating.sendFile,
1900 },
1901 },
1903 const vtable: VTable = .{
1904 .drain = Allocating.drain,
1905 .sendFile = Allocating.sendFile,
19021906 };
19031907
19041908 pub fn deinit(a: *Allocating) void {
1905 a.allocator.free(a.buffer);
1909 a.allocator.free(a.interface.buffer);
19061910 a.* = undefined;
19071911 }
19081912
......@@ -1983,8 +1987,8 @@ pub const Allocating = struct {
19831987 }
19841988
19851989 fn setArrayList(a: *Allocating, list: std.ArrayListUnmanaged(u8)) void {
1986 a.buffer = list.allocatedSlice();
1987 a.end = list.items.len;
1990 a.interface.buffer = list.allocatedSlice();
1991 a.interface.end = list.items.len;
19881992 }
19891993
19901994 test Allocating {
lib/std/net.zig+2-6
......@@ -970,7 +970,7 @@ pub fn getAddressList(gpa: Allocator, name: []const u8, port: u16) GetAddressLis
970970 const name_c = try gpa.dupeZ(u8, name);
971971 defer gpa.free(name_c);
972972
973 const port_c = try std.fmt.allocPrintZ(gpa, "{}", .{port});
973 const port_c = try std.fmt.allocPrintSentinel(gpa, "{d}", .{port}, 0);
974974 defer gpa.free(port_c);
975975
976976 const hints: posix.addrinfo = .{
......@@ -1985,10 +1985,7 @@ pub const Stream = struct {
19851985 return .{
19861986 .stream = stream,
19871987 .interface = .{
1988 .context = undefined,
1989 .vtable = &.{
1990 .drain = drain,
1991 },
1988 .vtable = &.{ .drain = drain },
19921989 .buffer = buffer,
19931990 },
19941991 };
......@@ -2090,7 +2087,6 @@ pub const Stream = struct {
20902087 pub fn init(stream: Stream, buffer: []u8) Writer {
20912088 return .{
20922089 .interface = .{
2093 .context = undefined,
20942090 .vtable = &.{
20952091 .drain = drain,
20962092 .sendFile = sendFile,
lib/std/tar/test.zig+3-3
......@@ -347,7 +347,7 @@ test "run test cases" {
347347
348348 for (cases) |case| {
349349 var br: std.io.Reader = .fixed(case.data);
350 var iter = tar.iterator(&br, .{
350 var iter: tar.Iterator = .init(&br, .{
351351 .file_name_buffer = &file_name_buffer,
352352 .link_name_buffer = &link_name_buffer,
353353 });
......@@ -391,7 +391,7 @@ test "pax/gnu long names with small buffer" {
391391
392392 for (long_name_cases) |case| {
393393 var br: std.io.Reader = .fixed(case.data);
394 var iter = tar.iterator(&br, .{
394 var iter: tar.Iterator = .init(&br, .{
395395 .file_name_buffer = &min_file_name_buffer,
396396 .link_name_buffer = &min_link_name_buffer,
397397 });
......@@ -412,7 +412,7 @@ test "insufficient buffer in Header name filed" {
412412 var min_link_name_buffer: [100]u8 = undefined;
413413
414414 var br: std.io.Reader = .fixed(cases[0].data);
415 var iter = tar.iterator(&br, .{
415 var iter: tar.Iterator = .init(&br, .{
416416 .file_name_buffer = &min_file_name_buffer,
417417 .link_name_buffer = &min_link_name_buffer,
418418 });
lib/std/tz.zig+5-3
......@@ -55,10 +55,12 @@ pub const Tz = struct {
5555 };
5656
5757 pub fn parse(allocator: std.mem.Allocator, reader: *std.io.Reader) !Tz {
58 var legacy_header = try reader.takeStruct(Header);
58 var legacy_header = (try reader.takeStruct(Header)).*;
5959 if (!std.mem.eql(u8, &legacy_header.magic, "TZif")) return error.BadHeader;
60 if (legacy_header.version != 0 and legacy_header.version != '2' and legacy_header.version != '3') return error.BadVersion;
61
60 switch (legacy_header.version) {
61 0, '2', '3' => {},
62 else => return error.BadVersion,
63 }
6264 if (builtin.target.cpu.arch.endian() != std.builtin.Endian.big) {
6365 std.mem.byteSwapAllFields(@TypeOf(legacy_header.counts), &legacy_header.counts);
6466 }
lib/std/zig/system/linux.zig+6-9
......@@ -355,20 +355,17 @@ fn testParser(
355355// When all the lines have been analyzed the finalize method is called.
356356fn CpuinfoParser(comptime impl: anytype) type {
357357 return struct {
358 fn parse(arch: Target.Cpu.Arch, reader: anytype) anyerror!?Target.Cpu {
359 var line_buf: [1024]u8 = undefined;
358 fn parse(arch: Target.Cpu.Arch, reader: *std.io.Reader) !?Target.Cpu {
360359 var obj: impl = .{};
361
362 while (true) {
363 const line = (try reader.readUntilDelimiterOrEof(&line_buf, '\n')) orelse break;
360 while (reader.takeDelimiterExclusive('\n')) |line| {
364361 const colon_pos = mem.indexOfScalar(u8, line, ':') orelse continue;
365362 const key = mem.trimEnd(u8, line[0..colon_pos], " \t");
366363 const value = mem.trimStart(u8, line[colon_pos + 1 ..], " \t");
367
368 if (!try obj.line_hook(key, value))
369 break;
364 if (!try obj.line_hook(key, value)) break;
365 } else |err| switch (err) {
366 error.EndOfStream => {},
367 else => |e| return e,
370368 }
371
372369 return obj.finalize(arch);
373370 }
374371 };
lib/std/zip/test.zig+6-4
......@@ -51,10 +51,10 @@ const FileStore = struct {
5151 uncompressed_size: usize,
5252};
5353
54fn makeZip(file_writer: *std.fs.File.Writer, files: []const File, options: WriteZipOptions) !std.io.Reader {
54fn makeZip(file_writer: *std.fs.File.Writer, files: []const File, options: WriteZipOptions) !void {
5555 const store = try std.testing.allocator.alloc(FileStore, files.len);
5656 defer std.testing.allocator.free(store);
57 return makeZipWithStore(file_writer, files, options, store);
57 try makeZipWithStore(file_writer, files, options, store);
5858}
5959
6060fn makeZipWithStore(
......@@ -312,7 +312,8 @@ fn testZipWithStore(
312312
313313 var file = tmp.createFile();
314314 defer file.close();
315 var file_writer = file.writer();
315 var buffer: [100]u8 = undefined;
316 var file_writer = file.writer(&buffer);
316317 try makeZipWithStore(&file_writer, test_files, write_opt, store);
317318 var file_reader = file_writer.moveToReader();
318319 try zip.extract(tmp.dir, &file_reader, options);
......@@ -323,7 +324,8 @@ fn testZipError(expected_error: anyerror, file: File, options: zip.ExtractOption
323324 defer tmp.cleanup();
324325 const tmp_file = tmp.createFile();
325326 defer tmp_file.close();
326 var file_writer = tmp_file.writer();
327 var buffer: [100]u8 = undefined;
328 var file_writer = tmp_file.writer(&buffer);
327329 var store: [1]FileStore = undefined;
328330 try makeZipWithStore(&file_writer, &[_]File{file}, .{}, &store);
329331 var file_reader = file_writer.moveToReader();