From c27ab8b45d767388eba5c3e69fc4b4764ae5e1c4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 24 Jun 2025 11:35:03 -0700 Subject: [PATCH] std: update zstd to new API --- lib/std/compress/zstd.zig | 10 ++++--- lib/std/compress/zstd/Decompress.zig | 26 ++++++++-------- lib/std/fs/File.zig | 13 ++++++-- lib/std/io/Reader.zig | 6 ++-- lib/std/io/Writer.zig | 45 +++++++++++++++++----------- 5 files changed, 59 insertions(+), 41 deletions(-) diff --git a/lib/std/compress/zstd.zig b/lib/std/compress/zstd.zig index 8dea3db5d9..701f9af5d4 100644 --- a/lib/std/compress/zstd.zig +++ b/lib/std/compress/zstd.zig @@ -81,10 +81,11 @@ pub const table_size_max = struct { fn testDecompress(gpa: std.mem.Allocator, compressed: []const u8) ![]u8 { var out: std.ArrayListUnmanaged(u8) = .empty; defer out.deinit(gpa); + try out.ensureUnusedCapacity(gpa, default_window_len); var in: std.io.Reader = .fixed(compressed); - var zstd_stream: Decompress = .init(&in, .{}); - try zstd_stream.reader().readRemainingArrayList(gpa, null, &out, .unlimited, default_window_len); + var zstd_stream: Decompress = .init(&in, &.{}, .{}); + try zstd_stream.interface.appendRemaining(gpa, null, &out, .unlimited); return out.toOwnedSlice(gpa); } @@ -101,12 +102,13 @@ fn testExpectDecompressError(err: anyerror, compressed: []const u8) !void { var out: std.ArrayListUnmanaged(u8) = .empty; defer out.deinit(gpa); + try out.ensureUnusedCapacity(gpa, default_window_len); var in: std.io.Reader = .fixed(compressed); - var zstd_stream: Decompress = .init(&in, .{}); + var zstd_stream: Decompress = .init(&in, &.{}, .{}); try std.testing.expectError( error.ReadFailed, - zstd_stream.reader().readRemainingArrayList(gpa, null, &out, .unlimited, default_window_len), + zstd_stream.interface.appendRemaining(gpa, null, &out, .unlimited), ); try std.testing.expectError(err, zstd_stream.err orelse {}); } diff --git a/lib/std/compress/zstd/Decompress.zig b/lib/std/compress/zstd/Decompress.zig index 440bfba1a9..63ccd1c367 100644 --- a/lib/std/compress/zstd/Decompress.zig +++ b/lib/std/compress/zstd/Decompress.zig @@ -7,6 +7,7 @@ const zstd = @import("../zstd.zig"); const Writer = std.io.Writer; input: *Reader, +interface: Reader, state: State, verify_checksum: bool, err: ?Error = null, @@ -62,34 +63,33 @@ pub const Error = error{ WindowSizeUnknown, }; -pub fn init(input: *Reader, options: Options) Decompress { +pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress { return .{ .input = input, .state = .new_frame, .verify_checksum = options.verify_checksum, + .interface = .{ + .vtable = &.{ .stream = stream }, + .buffer = buffer, + .seek = 0, + .end = 0, + }, }; } -pub fn reader(self: *Decompress) Reader { - return .{ - .context = self, - .vtable = &.{ .read = read }, - }; -} - -fn read(context: ?*anyopaque, bw: *Writer, limit: Limit) Reader.StreamError!usize { - const d: *Decompress = @ptrCast(@alignCast(context)); +fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { + const d: *Decompress = @alignCast(@fieldParentPtr("interface", r)); const in = d.input; switch (d.state) { .new_frame => { // Allow error.EndOfStream only on the frame magic. const magic = try in.takeEnumNonexhaustive(Frame.Magic, .little); - initFrame(d, bw.buffer.len, magic) catch |err| { + initFrame(d, w.buffer.len, magic) catch |err| { d.err = err; return error.ReadFailed; }; - return readInFrame(d, bw, limit, &d.state.in_frame) catch |err| switch (err) { + return readInFrame(d, w, limit, &d.state.in_frame) catch |err| switch (err) { error.ReadFailed => return error.ReadFailed, error.WriteFailed => return error.WriteFailed, else => |e| { @@ -99,7 +99,7 @@ fn read(context: ?*anyopaque, bw: *Writer, limit: Limit) Reader.StreamError!usiz }; }, .in_frame => |*in_frame| { - return readInFrame(d, bw, limit, in_frame) catch |err| switch (err) { + return readInFrame(d, w, limit, in_frame) catch |err| switch (err) { error.ReadFailed => return error.ReadFailed, error.WriteFailed => return error.WriteFailed, else => |e| { diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 3c50bfe757..7f349e633e 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1047,12 +1047,11 @@ pub const Reader = struct { const r: *Reader = @fieldParentPtr("interface", io_reader); switch (r.mode) { .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) { - error.ReadFailed => return error.ReadFailed, - error.WriteFailed => return error.WriteFailed, error.Unimplemented => { r.mode = r.mode.toReading(); return 0; }, + else => |e| return e, }, .positional_reading => { if (is_windows) { @@ -1239,7 +1238,7 @@ pub const Reader = struct { pub fn atEnd(r: *Reader) bool { // Even if stat fails, size is set when end is encountered. - const size = r.getSize() orelse return false; + const size = r.size orelse return false; return size - r.pos == 0; } }; @@ -1460,6 +1459,10 @@ pub const Writer = struct { return 0; }, }; + if (n == 0) { + file_reader.size = file_reader.pos; + return error.EndOfStream; + } file_reader.pos += n; w.pos += n; return n; @@ -1497,6 +1500,10 @@ pub const Writer = struct { w.copy_file_range_err = err; return 0; }; + if (n == 0) { + file_reader.size = file_reader.pos; + return error.EndOfStream; + } file_reader.pos += n; w.pos += n; return n; diff --git a/lib/std/io/Reader.zig b/lib/std/io/Reader.zig index 5c999fff78..b9071be378 100644 --- a/lib/std/io/Reader.zig +++ b/lib/std/io/Reader.zig @@ -146,7 +146,7 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize { } else .unlimited; r.seek = 0; r.end = 0; - const n = r.vtable.discard(r, remaining); + const n = try r.vtable.discard(r, remaining); assert(n <= @intFromEnum(remaining)); return buffered_len + n; } @@ -386,7 +386,7 @@ pub fn readVecAll(r: *Reader, data: [][]u8) Error!void { pub fn readAll(r: *Reader, w: *Writer, limit: Limit) StreamError!void { var remaining = limit; while (remaining.nonzero()) { - const n = try r.read(w, remaining); + const n = try r.stream(w, remaining); remaining = remaining.subtract(n).?; } } @@ -1472,7 +1472,7 @@ pub fn Hashed(comptime Hasher: type) type { fn discard(r: *Reader, limit: Limit) Error!usize { const this: *@This() = @alignCast(@fieldParentPtr("interface", r)); var w = this.hasher.writer(&.{}); - const n = this.in.read(&w, limit) catch |err| switch (err) { + const n = this.in.stream(&w, limit) catch |err| switch (err) { error.WriteFailed => unreachable, else => |e| return e, }; diff --git a/lib/std/io/Writer.zig b/lib/std/io/Writer.zig index 08f8f8e89c..309829ae7b 100644 --- a/lib/std/io/Writer.zig +++ b/lib/std/io/Writer.zig @@ -84,18 +84,29 @@ pub const Error = error{ WriteFailed, }; -pub const ReadingFileError = error{ +pub const FileAllError = error{ /// Detailed diagnostics are found on the `File.Reader` struct. ReadFailed, /// See the `Writer` implementation for detailed diagnostics. WriteFailed, }; +pub const FileReadingError = error{ + /// Detailed diagnostics are found on the `File.Reader` struct. + ReadFailed, + /// See the `Writer` implementation for detailed diagnostics. + WriteFailed, + /// Reached the end of the file being read. + EndOfStream, +}; + pub const FileError = error{ /// Detailed diagnostics are found on the `File.Reader` struct. ReadFailed, /// See the `Writer` implementation for detailed diagnostics. WriteFailed, + /// Reached the end of the file being read. + EndOfStream, /// Indicates the caller should do its own file reading; the callee cannot /// offer a more efficient implementation. Unimplemented, @@ -642,28 +653,24 @@ pub fn sendFileTo(w: *Writer, other: *Writer, file_reader: *File.Reader, limit: } /// Asserts nonzero buffer capacity. -pub fn sendFileReading(w: *Writer, file_reader: *File.Reader, limit: Limit) ReadingFileError!usize { +pub fn sendFileReading(w: *Writer, file_reader: *File.Reader, limit: Limit) FileReadingError!usize { const dest = limit.slice(try w.writableSliceGreedy(1)); - const n = file_reader.read(dest) catch |err| switch (err) { - error.EndOfStream => 0, - error.ReadFailed => return error.ReadFailed, - }; + const n = try file_reader.read(dest); w.advance(n); return n; } -pub fn sendFileAll(w: *Writer, file_reader: *File.Reader, limit: Limit) ReadingFileError!usize { +pub fn sendFileAll(w: *Writer, file_reader: *File.Reader, limit: Limit) FileAllError!usize { var remaining = @intFromEnum(limit); while (remaining > 0) { const n = sendFile(w, file_reader, .limited(remaining)) catch |err| switch (err) { - error.EndOfStream => return 0, - error.ReadFailed => return error.ReadFailed, - error.WriteFailed => return error.WriteFailed, + error.EndOfStream => break, error.Unimplemented => { file_reader.mode = file_reader.mode.toReading(); - try w.sendFileReadingAll(file_reader, remaining); - return; + remaining -= try w.sendFileReadingAll(file_reader, .limited(remaining)); + break; }, + else => |e| return e, }; remaining -= n; } @@ -676,13 +683,15 @@ pub fn sendFileAll(w: *Writer, file_reader: *File.Reader, limit: Limit) ReadingF /// that error code does not appear in this function's error set. /// /// Asserts nonzero buffer capacity. -pub fn sendFileReadingAll(w: *Writer, file_reader: *File.Reader, limit: Limit) ReadingFileError!void { - var remaining = limit; - while (remaining.nonzero()) { - const n = try sendFileReading(w, file_reader, remaining); - if (n == 0) return; - remaining = remaining.subtract(n).?; +pub fn sendFileReadingAll(w: *Writer, file_reader: *File.Reader, limit: Limit) FileAllError!usize { + var remaining = @intFromEnum(limit); + while (remaining > 0) { + remaining -= sendFileReading(w, file_reader, .limited(remaining)) catch |err| switch (err) { + error.EndOfStream => break, + else => |e| return e, + }; } + return @intFromEnum(limit) - remaining; } pub fn alignBuffer(