Commit 4c04835a08

Andrew Kelley <andrew@ziglang.org>
2025-07-30 09:28:11
std.compress.zstd.Decompress: implement discard and readVec
1 parent 84e4343
Changed files (2)
lib
std
compress
Io
lib/std/compress/zstd/Decompress.zig
@@ -89,7 +89,7 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
                 .stream = stream,
                 .rebase = rebase,
                 .discard = discard,
-                .readVec = Reader.indirectReadVec,
+                .readVec = readVec,
             },
             .buffer = buffer,
             .seek = 0,
@@ -109,10 +109,20 @@ fn rebase(r: *Reader, capacity: usize) Reader.RebaseError!void {
     r.seek -= discard_n;
 }
 
-fn discard(r: *Reader, limit: Limit) Reader.Error!usize {
-    r.rebase(zstd.block_size_max) catch unreachable;
-    var d: Writer.Discarding = .init(r.buffer);
-    const n = r.stream(&d.writer, limit) catch |err| switch (err) {
+/// This could be improved so that when an amount is discarded that includes an
+/// entire frame, skip decoding that frame.
+fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
+    const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
+    r.rebase(d.window_len) catch unreachable;
+    var writer: Writer = .{
+        .vtable = &.{
+            .drain = std.Io.Writer.Discarding.drain,
+            .sendFile = std.Io.Writer.Discarding.sendFile,
+        },
+        .buffer = r.buffer,
+        .end = r.end,
+    };
+    const n = r.stream(&writer, limit) catch |err| switch (err) {
         error.WriteFailed => unreachable,
         error.ReadFailed => return error.ReadFailed,
         error.EndOfStream => return error.EndOfStream,
@@ -121,6 +131,23 @@ fn discard(r: *Reader, limit: Limit) Reader.Error!usize {
     return n;
 }
 
+fn readVec(r: *Reader, data: []const []u8) Reader.Error!usize {
+    _ = data;
+    const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
+    assert(r.seek == r.end);
+    r.rebase(d.window_len) catch unreachable;
+    var writer: Writer = .{
+        .buffer = r.buffer,
+        .end = r.end,
+        .vtable = &.{ .drain = Writer.fixedDrain },
+    };
+    r.end += r.vtable.stream(r, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {
+        error.WriteFailed => unreachable,
+        else => |e| return e,
+    };
+    return 0;
+}
+
 fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
     const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
     const in = d.input;
lib/std/Io/Reader.zig
@@ -438,23 +438,6 @@ pub fn defaultReadVec(r: *Reader, data: []const []u8) Error!usize {
     return 0;
 }
 
-/// Always writes to `Reader.buffer` and returns 0.
-pub fn indirectReadVec(r: *Reader, data: []const []u8) Error!usize {
-    _ = data;
-    assert(r.seek == r.end);
-    var writer: Writer = .{
-        .buffer = r.buffer,
-        .end = r.end,
-        .vtable = &.{ .drain = Writer.fixedDrain },
-    };
-    const limit: Limit = .limited(writer.buffer.len - writer.end);
-    r.end += r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
-        error.WriteFailed => unreachable,
-        else => |e| return e,
-    };
-    return 0;
-}
-
 pub fn buffered(r: *Reader) []u8 {
     return r.buffer[r.seek..r.end];
 }