std: update zstd to new API

This commit is contained in:
Andrew Kelley 2025-06-24 11:35:03 -07:00
parent 743326f8e9
commit c27ab8b45d
5 changed files with 59 additions and 41 deletions

View File

@ -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 {});
}

View File

@ -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| {

View File

@ -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;

View File

@ -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,
};

View File

@ -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(