authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 17:31:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:10:11-07:00
log6eac56caf715bdc2dbd63b628ca48c0e32d5a70c
tree2fdf465c77963be579faef35461b9366fcddf8f6
parent2024abda6ae7c02c7fc1667d221e98da23ebcd2a

std.compress.flate.Decompress: allow users to swap out Writer


1 files changed, 26 insertions(+), 7 deletions(-)

lib/std/compress/flate/Decompress.zig+26-7
...@@ -58,7 +58,7 @@ pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {...@@ -58,7 +58,7 @@ pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {
58 .reader = .{58 .reader = .{
59 .vtable = &.{59 .vtable = &.{
60 .stream = stream,60 .stream = stream,
61 .rebase = rebase,61 .rebase = rebaseFallible,
62 .discard = discard,62 .discard = discard,
63 .readVec = readVec,63 .readVec = readVec,
64 },64 },
...@@ -78,12 +78,19 @@ pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {...@@ -78,12 +78,19 @@ pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {
78 };78 };
79}79}
8080
81fn rebase(r: *Reader, capacity: usize) Reader.RebaseError!void {81fn rebaseFallible(r: *Reader, capacity: usize) Reader.RebaseError!void {
82 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
83 rebase(d, capacity);
84}
85
86fn rebase(d: *Decompress, capacity: usize) void {
87 const r = &d.reader;
82 assert(capacity <= r.buffer.len - flate.history_len);88 assert(capacity <= r.buffer.len - flate.history_len);
83 assert(r.end + capacity > r.buffer.len);89 assert(r.end + capacity > r.buffer.len);
84 const discard_n = r.end - flate.history_len;90 const discard_n = r.end - flate.history_len;
85 const keep = r.buffer[discard_n..r.end];91 const keep = r.buffer[discard_n..r.end];
86 @memmove(r.buffer[0..keep.len], keep);92 @memmove(r.buffer[0..keep.len], keep);
93 assert(keep.len != 0);
87 r.end = keep.len;94 r.end = keep.len;
88 r.seek -= discard_n;95 r.seek -= discard_n;
89}96}
...@@ -101,6 +108,7 @@ fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {...@@ -101,6 +108,7 @@ fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
101 .end = r.end,108 .end = r.end,
102 };109 };
103 defer {110 defer {
111 assert(writer.end != 0);
104 r.end = writer.end;112 r.end = writer.end;
105 r.seek = r.end;113 r.seek = r.end;
106 }114 }
...@@ -115,14 +123,20 @@ fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {...@@ -115,14 +123,20 @@ fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
115123
116fn readVec(r: *Reader, data: [][]u8) Reader.Error!usize {124fn readVec(r: *Reader, data: [][]u8) Reader.Error!usize {
117 _ = data;125 _ = data;
118 assert(r.seek == r.end);126 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
119 r.rebase(flate.history_len) catch unreachable;127 return streamIndirect(d);
128}
129
130fn streamIndirect(d: *Decompress) Reader.Error!usize {
131 const r = &d.reader;
132 if (r.end + flate.history_len > r.buffer.len) rebase(d, flate.history_len);
120 var writer: Writer = .{133 var writer: Writer = .{
121 .buffer = r.buffer,134 .buffer = r.buffer,
122 .end = r.end,135 .end = r.end,
123 .vtable = &.{ .drain = Writer.fixedDrain },136 .vtable = &.{ .drain = Writer.fixedDrain },
124 };137 };
125 r.end += r.vtable.stream(r, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {138 defer r.end = writer.end;
139 _ = streamFallible(d, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {
126 error.WriteFailed => unreachable,140 error.WriteFailed => unreachable,
127 else => |e| return e,141 else => |e| return e,
128 };142 };
...@@ -188,7 +202,12 @@ fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {...@@ -188,7 +202,12 @@ fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {
188202
189pub fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {203pub fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
190 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));204 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
191 return readInner(d, w, limit) catch |err| switch (err) {205 if (w.end >= r.end) return streamFallible(d, w, limit);
206 return streamIndirect(d);
207}
208
209fn streamFallible(d: *Decompress, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
210 return streamInner(d, w, limit) catch |err| switch (err) {
192 error.EndOfStream => {211 error.EndOfStream => {
193 if (d.state == .end) {212 if (d.state == .end) {
194 return error.EndOfStream;213 return error.EndOfStream;
...@@ -207,7 +226,7 @@ pub fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!us...@@ -207,7 +226,7 @@ pub fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!us
207 };226 };
208}227}
209228
210fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.StreamError)!usize {229fn streamInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.StreamError)!usize {
211 var remaining = @intFromEnum(limit);230 var remaining = @intFromEnum(limit);
212 const in = d.input;231 const in = d.input;
213 sw: switch (d.state) {232 sw: switch (d.state) {