| author | |
| committer | |
| log | 084e45fd865e73f862d85da2a634f8f2cb74580d |
| tree | 0f53a4bdc7a0ccb7db6437170c3cc6189b683a33 |
| parent | b393112674d0b948832c3223d5b300f080c71151 |
and specify that data.len == 0 means "flush"6 files changed, 205 insertions(+), 161 deletions(-)
lib/compiler/resinator/errors.zig+13-10| ... | @@ -1081,11 +1081,17 @@ const CorrespondingLines = struct { | ... | @@ -1081,11 +1081,17 @@ const CorrespondingLines = struct { |
| 1081 | last_byte: u8 = 0, | 1081 | last_byte: u8 = 0, |
| 1082 | at_eof: bool = false, | 1082 | at_eof: bool = false, |
| 1083 | span: SourceMappings.CorrespondingSpan, | 1083 | span: SourceMappings.CorrespondingSpan, |
| 1084 | file: std.fs.File, | 1084 | file_reader: *std.fs.File.Reader, |
| 1085 | buffered_reader: *std.io.Reader, | ||
| 1086 | code_page: SupportedCodePage, | 1085 | code_page: SupportedCodePage, |
| 1087 | 1086 | ||
| 1088 | pub fn init(cwd: std.fs.Dir, err_details: ErrorDetails, line_for_comparison: []const u8, corresponding_span: SourceMappings.CorrespondingSpan, corresponding_file: []const u8) !CorrespondingLines { | 1087 | pub fn init( |
| 1088 | cwd: std.fs.Dir, | ||
| 1089 | err_details: ErrorDetails, | ||
| 1090 | line_for_comparison: []const u8, | ||
| 1091 | corresponding_span: SourceMappings.CorrespondingSpan, | ||
| 1092 | corresponding_file: []const u8, | ||
| 1093 | file_read_buffer: []u8, | ||
| 1094 | ) !CorrespondingLines { | ||
| 1089 | // We don't do line comparison for this error, so don't print the note if the line | 1095 | // We don't do line comparison for this error, so don't print the note if the line |
| 1090 | // number is different | 1096 | // number is different |
| 1091 | if (err_details.err == .string_literal_too_long and err_details.token.line_number != corresponding_span.start_line) { | 1097 | if (err_details.err == .string_literal_too_long and err_details.token.line_number != corresponding_span.start_line) { |
| ... | @@ -1097,15 +1103,12 @@ const CorrespondingLines = struct { | ... | @@ -1097,15 +1103,12 @@ const CorrespondingLines = struct { |
| 1097 | return error.NotWorthPrintingLines; | 1103 | return error.NotWorthPrintingLines; |
| 1098 | } | 1104 | } |
| 1099 | 1105 | ||
| 1100 | var corresponding_lines = CorrespondingLines{ | 1106 | var file = try utils.openFileNotDir(cwd, corresponding_file, .{}); |
| 1107 | var corresponding_lines: CorrespondingLines = .{ | ||
| 1101 | .span = corresponding_span, | 1108 | .span = corresponding_span, |
| 1102 | .file = try utils.openFileNotDir(cwd, corresponding_file, .{}), | 1109 | .file_reader = file.reader(&file_read_buffer), |
| 1103 | .buffered_reader = undefined, | ||
| 1104 | .code_page = err_details.code_page, | 1110 | .code_page = err_details.code_page, |
| 1105 | }; | 1111 | }; |
| 1106 | corresponding_lines.buffered_reader = .{ | ||
| 1107 | .unbuffered_reader = corresponding_lines.file.reader(), | ||
| 1108 | }; | ||
| 1109 | errdefer corresponding_lines.deinit(); | 1112 | errdefer corresponding_lines.deinit(); |
| 1110 | 1113 | ||
| 1111 | var fbs = std.io.fixedBufferStream(&corresponding_lines.line_buf); | 1114 | var fbs = std.io.fixedBufferStream(&corresponding_lines.line_buf); |
| ... | @@ -1215,7 +1218,7 @@ const CorrespondingLines = struct { | ... | @@ -1215,7 +1218,7 @@ const CorrespondingLines = struct { |
| 1215 | } | 1218 | } |
| 1216 | 1219 | ||
| 1217 | pub fn deinit(self: *CorrespondingLines) void { | 1220 | pub fn deinit(self: *CorrespondingLines) void { |
| 1218 | self.file.close(); | 1221 | self.file_reader.file.close(); |
| 1219 | } | 1222 | } |
| 1220 | }; | 1223 | }; |
| 1221 | 1224 |
lib/std/fs/File.zig+54-14| ... | @@ -1027,14 +1027,10 @@ pub const Reader = struct { | ... | @@ -1027,14 +1027,10 @@ pub const Reader = struct { |
| 1027 | /// vectors through the underlying read calls as possible. | 1027 | /// vectors through the underlying read calls as possible. |
| 1028 | const max_buffers_len = 16; | 1028 | const max_buffers_len = 16; |
| 1029 | 1029 | ||
| 1030 | fn stream( | 1030 | fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { |
| 1031 | io_reader: *std.io.Reader, | ||
| 1032 | bw: *std.io.Writer, | ||
| 1033 | limit: std.io.Limit, | ||
| 1034 | ) std.io.Reader.StreamError!usize { | ||
| 1035 | const r: *Reader = @fieldParentPtr("interface", io_reader); | 1031 | const r: *Reader = @fieldParentPtr("interface", io_reader); |
| 1036 | switch (r.mode) { | 1032 | switch (r.mode) { |
| 1037 | .positional, .streaming => return bw.writeFile(r, limit, &.{}, 0) catch |write_err| switch (write_err) { | 1033 | .positional, .streaming => return w.writeFile(r, limit, &.{}, 0) catch |write_err| switch (write_err) { |
| 1038 | error.ReadFailed => return error.ReadFailed, | 1034 | error.ReadFailed => return error.ReadFailed, |
| 1039 | error.WriteFailed => return error.WriteFailed, | 1035 | error.WriteFailed => return error.WriteFailed, |
| 1040 | error.Unimplemented => { | 1036 | error.Unimplemented => { |
| ... | @@ -1043,16 +1039,60 @@ pub const Reader = struct { | ... | @@ -1043,16 +1039,60 @@ pub const Reader = struct { |
| 1043 | }, | 1039 | }, |
| 1044 | }, | 1040 | }, |
| 1045 | .positional_reading => { | 1041 | .positional_reading => { |
| 1046 | const dest = limit.slice(try bw.writableSliceGreedy(1)); | 1042 | if (is_windows) { |
| 1047 | const n = try readPositional(r, dest); | 1043 | // Unfortunately, `ReadFileScatter` cannot be used since it |
| 1048 | bw.advance(n); | 1044 | // requires page alignment. |
| 1049 | return n; | 1045 | const dest = limit.slice(try w.writableSliceGreedy(1)); |
| 1046 | const n = try readPositional(r, dest); | ||
| 1047 | w.advance(n); | ||
| 1048 | return n; | ||
| 1049 | } | ||
| 1050 | var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; | ||
| 1051 | const dest = w.writableVectorPosix(&iovecs_buffer, limit); | ||
| 1052 | assert(dest[0].len > 0); | ||
| 1053 | const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) { | ||
| 1054 | error.Unseekable => { | ||
| 1055 | r.mode = r.mode.toStreaming(); | ||
| 1056 | if (r.pos != 0) r.seekBy(@intCast(r.pos)) catch { | ||
| 1057 | r.mode = .failure; | ||
| 1058 | return error.ReadFailed; | ||
| 1059 | }; | ||
| 1060 | return 0; | ||
| 1061 | }, | ||
| 1062 | else => |e| { | ||
| 1063 | r.err = e; | ||
| 1064 | return error.ReadFailed; | ||
| 1065 | }, | ||
| 1066 | }; | ||
| 1067 | if (n == 0) { | ||
| 1068 | r.size = r.pos; | ||
| 1069 | return error.EndOfStream; | ||
| 1070 | } | ||
| 1071 | r.pos += n; | ||
| 1072 | return w.advanceVector(n); | ||
| 1050 | }, | 1073 | }, |
| 1051 | .streaming_reading => { | 1074 | .streaming_reading => { |
| 1052 | const dest = limit.slice(try bw.writableSliceGreedy(1)); | 1075 | if (is_windows) { |
| 1053 | const n = try readStreaming(r, dest); | 1076 | // Unfortunately, `ReadFileScatter` cannot be used since it |
| 1054 | bw.advance(n); | 1077 | // requires page alignment. |
| 1055 | return n; | 1078 | const dest = limit.slice(try w.writableSliceGreedy(1)); |
| 1079 | const n = try readStreaming(r, dest); | ||
| 1080 | w.advance(n); | ||
| 1081 | return n; | ||
| 1082 | } | ||
| 1083 | var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; | ||
| 1084 | const dest = w.writableVectorPosix(&iovecs_buffer, limit); | ||
| 1085 | assert(dest[0].len > 0); | ||
| 1086 | const n = posix.pread(r.file.handle, dest) catch |err| { | ||
| 1087 | r.err = err; | ||
| 1088 | return error.ReadFailed; | ||
| 1089 | }; | ||
| 1090 | if (n == 0) { | ||
| 1091 | r.size = r.pos; | ||
| 1092 | return error.EndOfStream; | ||
| 1093 | } | ||
| 1094 | r.pos += n; | ||
| 1095 | return w.advanceVector(n); | ||
| 1056 | }, | 1096 | }, |
| 1057 | .failure => return error.ReadFailed, | 1097 | .failure => return error.ReadFailed, |
| 1058 | } | 1098 | } |
lib/std/io/Reader.zig+77-54| ... | @@ -22,12 +22,12 @@ seek: usize, | ... | @@ -22,12 +22,12 @@ seek: usize, |
| 22 | end: usize, | 22 | end: usize, |
| 23 | 23 | ||
| 24 | pub const VTable = struct { | 24 | pub const VTable = struct { |
| 25 | /// Writes bytes from the internally tracked logical position to `bw`. | 25 | /// Writes bytes from the internally tracked logical position to `w`. |
| 26 | /// | 26 | /// |
| 27 | /// Returns the number of bytes written, which will be at minimum `0` and | 27 | /// Returns the number of bytes written, which will be at minimum `0` and |
| 28 | /// at most `limit`. The number returned, including zero, does not indicate | 28 | /// at most `limit`. The number returned, including zero, does not indicate |
| 29 | /// end of stream. `limit` is guaranteed to be at least as large as the | 29 | /// end of stream. `limit` is guaranteed to be at least as large as the |
| 30 | /// buffer capacity of `bw`. | 30 | /// buffer capacity of `w`. |
| 31 | /// | 31 | /// |
| 32 | /// The reader's internal logical seek position moves forward in accordance | 32 | /// The reader's internal logical seek position moves forward in accordance |
| 33 | /// with the number of bytes returned from this function. | 33 | /// with the number of bytes returned from this function. |
| ... | @@ -35,6 +35,8 @@ pub const VTable = struct { | ... | @@ -35,6 +35,8 @@ pub const VTable = struct { |
| 35 | /// Implementations are encouraged to utilize mandatory minimum buffer | 35 | /// Implementations are encouraged to utilize mandatory minimum buffer |
| 36 | /// sizes combined with short reads (returning a value less than `limit`) | 36 | /// sizes combined with short reads (returning a value less than `limit`) |
| 37 | /// in order to minimize complexity. | 37 | /// in order to minimize complexity. |
| 38 | /// | ||
| 39 | /// This function is always called when `buffer` is empty. | ||
| 38 | stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize, | 40 | stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize, |
| 39 | 41 | ||
| 40 | /// Consumes bytes from the internally tracked stream position without | 42 | /// Consumes bytes from the internally tracked stream position without |
| ... | @@ -51,7 +53,7 @@ pub const VTable = struct { | ... | @@ -51,7 +53,7 @@ pub const VTable = struct { |
| 51 | /// sizes combined with short reads (returning a value less than `limit`) | 53 | /// sizes combined with short reads (returning a value less than `limit`) |
| 52 | /// in order to minimize complexity. | 54 | /// in order to minimize complexity. |
| 53 | /// | 55 | /// |
| 54 | /// The default implementation is is based on calling `read`, borrowing | 56 | /// The default implementation is is based on calling `stream`, borrowing |
| 55 | /// `buffer` to construct a temporary `Writer` and ignoring the written | 57 | /// `buffer` to construct a temporary `Writer` and ignoring the written |
| 56 | /// data. | 58 | /// data. |
| 57 | discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard, | 59 | discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard, |
| ... | @@ -88,7 +90,7 @@ pub const ShortError = error{ | ... | @@ -88,7 +90,7 @@ pub const ShortError = error{ |
| 88 | pub const failing: Reader = .{ | 90 | pub const failing: Reader = .{ |
| 89 | .context = undefined, | 91 | .context = undefined, |
| 90 | .vtable = &.{ | 92 | .vtable = &.{ |
| 91 | .read = failingRead, | 93 | .read = failingStream, |
| 92 | .discard = failingDiscard, | 94 | .discard = failingDiscard, |
| 93 | }, | 95 | }, |
| 94 | .buffer = &.{}, | 96 | .buffer = &.{}, |
| ... | @@ -107,7 +109,7 @@ pub fn fixed(buffer: []const u8) Reader { | ... | @@ -107,7 +109,7 @@ pub fn fixed(buffer: []const u8) Reader { |
| 107 | return .{ | 109 | return .{ |
| 108 | .context = undefined, | 110 | .context = undefined, |
| 109 | .vtable = &.{ | 111 | .vtable = &.{ |
| 110 | .read = endingRead, | 112 | .stream = endingStream, |
| 111 | .discard = endingDiscard, | 113 | .discard = endingDiscard, |
| 112 | }, | 114 | }, |
| 113 | // This cast is safe because all potential writes to it will instead | 115 | // This cast is safe because all potential writes to it will instead |
| ... | @@ -274,9 +276,17 @@ pub fn appendRemaining( | ... | @@ -274,9 +276,17 @@ pub fn appendRemaining( |
| 274 | /// The reader's internal logical seek position moves forward in accordance | 276 | /// The reader's internal logical seek position moves forward in accordance |
| 275 | /// with the number of bytes returned from this function. | 277 | /// with the number of bytes returned from this function. |
| 276 | pub fn readVec(r: *Reader, data: []const []u8) Error!usize { | 278 | pub fn readVec(r: *Reader, data: []const []u8) Error!usize { |
| 277 | return readVecLimit(r, data, .unlimited); | 279 | return readVec(r, data, .unlimited); |
| 278 | } | 280 | } |
| 279 | 281 | ||
| 282 | const VectorWrapped = struct { | ||
| 283 | writer: Writer, | ||
| 284 | first: []u8, | ||
| 285 | middle: []const []u8, | ||
| 286 | last: []u8, | ||
| 287 | var unique_address: u8 = undefined; | ||
| 288 | }; | ||
| 289 | |||
| 280 | /// Equivalent to `readVec` but reads at most `limit` bytes. | 290 | /// Equivalent to `readVec` but reads at most `limit` bytes. |
| 281 | /// | 291 | /// |
| 282 | /// This ultimately will lower to a call to `stream`, but it must ensure | 292 | /// This ultimately will lower to a call to `stream`, but it must ensure |
| ... | @@ -296,42 +306,55 @@ pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize { | ... | @@ -296,42 +306,55 @@ pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize { |
| 296 | if (remaining == 0) break; | 306 | if (remaining == 0) break; |
| 297 | if (buf.len - copy_len == 0) continue; | 307 | if (buf.len - copy_len == 0) continue; |
| 298 | 308 | ||
| 309 | // All of `buffer` has been copied to `data`. We now set up a structure | ||
| 310 | // that enables the `Writer.writableVector` API, while also ensuring | ||
| 311 | // API that directly operates on the `Writable.buffer` has its minimum | ||
| 312 | // buffer capacity requirements met. | ||
| 299 | r.seek = 0; | 313 | r.seek = 0; |
| 300 | r.end = 0; | 314 | r.end = 0; |
| 301 | var vecs: [8][]u8 = undefined; // Arbitrarily chosen value. | 315 | const first = buf[copy_len..]; |
| 302 | const available_remaining_buf = buf[copy_len..]; | 316 | var wrapped: VectorWrapped = .{ |
| 303 | vecs[0] = available_remaining_buf[0..@min(available_remaining_buf.len, remaining)]; | 317 | .first = first, |
| 304 | const vec_start_remaining = remaining; | 318 | .middle = data[i + 1 ..], |
| 305 | remaining -= vecs[0].len; | 319 | .last = r.buffer, |
| 306 | var vecs_i: usize = 1; | 320 | .writer = .{ |
| 307 | var data_i: usize = i + 1; | 321 | .context = &VectorWrapped.unique_address, |
| 308 | while (true) { | 322 | .buffer = if (first.len >= r.buffer.len) first else r.buffer, |
| 309 | if (vecs.len - vecs_i == 0) { | 323 | .vtable = &.{ .drain = Writer.fixedDrain }, |
| 310 | const n = try r.unbuffered_reader.readVec(&vecs); | 324 | }, |
| 311 | return @intFromEnum(limit) - vec_start_remaining + n; | 325 | }; |
| 312 | } | 326 | var n = r.vtable.stream(r, &wrapped.writer, .limited(remaining)) catch |err| switch (err) { |
| 313 | if (remaining == 0 or data.len - data_i == 0) { | 327 | error.WriteFailed => { |
| 314 | vecs[vecs_i] = r.buffer; | 328 | if (wrapped.writer.buffer.ptr == first.ptr) { |
| 315 | vecs_i += 1; | 329 | remaining -= wrapped.writer.end; |
| 316 | const n = try r.unbuffered_reader.readVec(vecs[0..vecs_i]); | ||
| 317 | const cutoff = vec_start_remaining - remaining; | ||
| 318 | if (n > cutoff) { | ||
| 319 | r.end = n - cutoff; | ||
| 320 | return @intFromEnum(limit) - remaining; | ||
| 321 | } else { | 330 | } else { |
| 322 | return @intFromEnum(limit) - vec_start_remaining + n; | 331 | r.end = wrapped.writer.end; |
| 323 | } | 332 | } |
| 333 | break; | ||
| 334 | }, | ||
| 335 | else => |e| return e, | ||
| 336 | }; | ||
| 337 | assert(n == wrapped.writer.end); | ||
| 338 | if (wrapped.writer.buffer.ptr != first.ptr) { | ||
| 339 | r.end = n; | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | if (n < first.len) { | ||
| 343 | remaining -= n; | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | remaining -= first.len; | ||
| 347 | n -= first.len; | ||
| 348 | for (wrapped.middle) |middle| { | ||
| 349 | if (n < middle.len) { | ||
| 350 | remaining -= n; | ||
| 351 | break; | ||
| 324 | } | 352 | } |
| 325 | if (data[data_i].len == 0) { | 353 | remaining -= middle.len; |
| 326 | data_i += 1; | 354 | n -= middle.len; |
| 327 | continue; | ||
| 328 | } | ||
| 329 | const data_elem = data[data_i]; | ||
| 330 | vecs[vecs_i] = data_elem[0..@min(data_elem.len, remaining)]; | ||
| 331 | remaining -= vecs[vecs_i].len; | ||
| 332 | vecs_i += 1; | ||
| 333 | data_i += 1; | ||
| 334 | } | 355 | } |
| 356 | r.end = n; | ||
| 357 | break; | ||
| 335 | } | 358 | } |
| 336 | return @intFromEnum(limit) - remaining; | 359 | return @intFromEnum(limit) - remaining; |
| 337 | } | 360 | } |
| ... | @@ -366,10 +389,10 @@ pub fn readVecAll(r: *Reader, data: [][]u8) Error!void { | ... | @@ -366,10 +389,10 @@ pub fn readVecAll(r: *Reader, data: [][]u8) Error!void { |
| 366 | } | 389 | } |
| 367 | 390 | ||
| 368 | /// "Pump" data from the reader to the writer. | 391 | /// "Pump" data from the reader to the writer. |
| 369 | pub fn readAll(r: *Reader, bw: *Writer, limit: Limit) StreamError!void { | 392 | pub fn readAll(r: *Reader, w: *Writer, limit: Limit) StreamError!void { |
| 370 | var remaining = limit; | 393 | var remaining = limit; |
| 371 | while (remaining.nonzero()) { | 394 | while (remaining.nonzero()) { |
| 372 | const n = try r.read(bw, remaining); | 395 | const n = try r.read(w, remaining); |
| 373 | remaining = remaining.subtract(n).?; | 396 | remaining = remaining.subtract(n).?; |
| 374 | } | 397 | } |
| 375 | } | 398 | } |
| ... | @@ -774,12 +797,12 @@ pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { | ... | @@ -774,12 +797,12 @@ pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 774 | return result[0 .. result.len - 1]; | 797 | return result[0 .. result.len - 1]; |
| 775 | } | 798 | } |
| 776 | 799 | ||
| 777 | /// Appends to `bw` contents by reading from the stream until `delimiter` is | 800 | /// Appends to `w` contents by reading from the stream until `delimiter` is |
| 778 | /// found. Does not write the delimiter itself. | 801 | /// found. Does not write the delimiter itself. |
| 779 | /// | 802 | /// |
| 780 | /// Returns number of bytes streamed. | 803 | /// Returns number of bytes streamed. |
| 781 | pub fn readDelimiter(r: *Reader, bw: *Writer, delimiter: u8) StreamError!usize { | 804 | pub fn readDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize { |
| 782 | const amount, const to = try r.readAny(bw, delimiter, .unlimited); | 805 | const amount, const to = try r.readAny(w, delimiter, .unlimited); |
| 783 | return switch (to) { | 806 | return switch (to) { |
| 784 | .delimiter => amount, | 807 | .delimiter => amount, |
| 785 | .limit => unreachable, | 808 | .limit => unreachable, |
| ... | @@ -787,7 +810,7 @@ pub fn readDelimiter(r: *Reader, bw: *Writer, delimiter: u8) StreamError!usize { | ... | @@ -787,7 +810,7 @@ pub fn readDelimiter(r: *Reader, bw: *Writer, delimiter: u8) StreamError!usize { |
| 787 | }; | 810 | }; |
| 788 | } | 811 | } |
| 789 | 812 | ||
| 790 | /// Appends to `bw` contents by reading from the stream until `delimiter` is found. | 813 | /// Appends to `w` contents by reading from the stream until `delimiter` is found. |
| 791 | /// Does not write the delimiter itself. | 814 | /// Does not write the delimiter itself. |
| 792 | /// | 815 | /// |
| 793 | /// Succeeds if stream ends before delimiter found. | 816 | /// Succeeds if stream ends before delimiter found. |
| ... | @@ -795,10 +818,10 @@ pub fn readDelimiter(r: *Reader, bw: *Writer, delimiter: u8) StreamError!usize { | ... | @@ -795,10 +818,10 @@ pub fn readDelimiter(r: *Reader, bw: *Writer, delimiter: u8) StreamError!usize { |
| 795 | /// Returns number of bytes streamed. The end is not signaled to the writer. | 818 | /// Returns number of bytes streamed. The end is not signaled to the writer. |
| 796 | pub fn readDelimiterEnding( | 819 | pub fn readDelimiterEnding( |
| 797 | r: *Reader, | 820 | r: *Reader, |
| 798 | bw: *Writer, | 821 | w: *Writer, |
| 799 | delimiter: u8, | 822 | delimiter: u8, |
| 800 | ) StreamRemainingError!usize { | 823 | ) StreamRemainingError!usize { |
| 801 | const amount, const to = try r.readAny(bw, delimiter, .unlimited); | 824 | const amount, const to = try r.readAny(w, delimiter, .unlimited); |
| 802 | return switch (to) { | 825 | return switch (to) { |
| 803 | .delimiter, .end => amount, | 826 | .delimiter, .end => amount, |
| 804 | .limit => unreachable, | 827 | .limit => unreachable, |
| ... | @@ -812,17 +835,17 @@ pub const StreamDelimiterLimitedError = StreamRemainingError || error{ | ... | @@ -812,17 +835,17 @@ pub const StreamDelimiterLimitedError = StreamRemainingError || error{ |
| 812 | StreamTooLong, | 835 | StreamTooLong, |
| 813 | }; | 836 | }; |
| 814 | 837 | ||
| 815 | /// Appends to `bw` contents by reading from the stream until `delimiter` is found. | 838 | /// Appends to `w` contents by reading from the stream until `delimiter` is found. |
| 816 | /// Does not write the delimiter itself. | 839 | /// Does not write the delimiter itself. |
| 817 | /// | 840 | /// |
| 818 | /// Returns number of bytes streamed. | 841 | /// Returns number of bytes streamed. |
| 819 | pub fn readDelimiterLimit( | 842 | pub fn readDelimiterLimit( |
| 820 | r: *Reader, | 843 | r: *Reader, |
| 821 | bw: *Writer, | 844 | w: *Writer, |
| 822 | delimiter: u8, | 845 | delimiter: u8, |
| 823 | limit: Limit, | 846 | limit: Limit, |
| 824 | ) StreamDelimiterLimitedError!usize { | 847 | ) StreamDelimiterLimitedError!usize { |
| 825 | const amount, const to = try r.readAny(bw, delimiter, limit); | 848 | const amount, const to = try r.readAny(w, delimiter, limit); |
| 826 | return switch (to) { | 849 | return switch (to) { |
| 827 | .delimiter => amount, | 850 | .delimiter => amount, |
| 828 | .limit => error.StreamTooLong, | 851 | .limit => error.StreamTooLong, |
| ... | @@ -832,7 +855,7 @@ pub fn readDelimiterLimit( | ... | @@ -832,7 +855,7 @@ pub fn readDelimiterLimit( |
| 832 | 855 | ||
| 833 | fn readAny( | 856 | fn readAny( |
| 834 | r: *Reader, | 857 | r: *Reader, |
| 835 | bw: *Writer, | 858 | w: *Writer, |
| 836 | delimiter: ?u8, | 859 | delimiter: ?u8, |
| 837 | limit: Limit, | 860 | limit: Limit, |
| 838 | ) StreamRemainingError!struct { usize, enum { delimiter, limit, end } } { | 861 | ) StreamRemainingError!struct { usize, enum { delimiter, limit, end } } { |
| ... | @@ -844,11 +867,11 @@ fn readAny( | ... | @@ -844,11 +867,11 @@ fn readAny( |
| 844 | error.EndOfStream => return .{ amount, .end }, | 867 | error.EndOfStream => return .{ amount, .end }, |
| 845 | }); | 868 | }); |
| 846 | if (delimiter) |d| if (std.mem.indexOfScalar(u8, available, d)) |delimiter_index| { | 869 | if (delimiter) |d| if (std.mem.indexOfScalar(u8, available, d)) |delimiter_index| { |
| 847 | try bw.writeAll(available[0..delimiter_index]); | 870 | try w.writeAll(available[0..delimiter_index]); |
| 848 | r.toss(delimiter_index + 1); | 871 | r.toss(delimiter_index + 1); |
| 849 | return .{ amount + delimiter_index, .delimiter }; | 872 | return .{ amount + delimiter_index, .delimiter }; |
| 850 | }; | 873 | }; |
| 851 | try bw.writeAll(available); | 874 | try w.writeAll(available); |
| 852 | r.toss(available.len); | 875 | r.toss(available.len); |
| 853 | amount += available.len; | 876 | amount += available.len; |
| 854 | remaining = remaining.subtract(available.len).?; | 877 | remaining = remaining.subtract(available.len).?; |
| ... | @@ -1303,7 +1326,7 @@ test "expected error.EndOfStream" { | ... | @@ -1303,7 +1326,7 @@ test "expected error.EndOfStream" { |
| 1303 | try std.testing.expectError(error.EndOfStream, r.isBytes("foo")); | 1326 | try std.testing.expectError(error.EndOfStream, r.isBytes("foo")); |
| 1304 | } | 1327 | } |
| 1305 | 1328 | ||
| 1306 | fn endingRead(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { | 1329 | fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { |
| 1307 | _ = r; | 1330 | _ = r; |
| 1308 | _ = w; | 1331 | _ = w; |
| 1309 | _ = limit; | 1332 | _ = limit; |
| ... | @@ -1316,7 +1339,7 @@ fn endingDiscard(r: *Reader, limit: Limit) Error!usize { | ... | @@ -1316,7 +1339,7 @@ fn endingDiscard(r: *Reader, limit: Limit) Error!usize { |
| 1316 | return error.EndOfStream; | 1339 | return error.EndOfStream; |
| 1317 | } | 1340 | } |
| 1318 | 1341 | ||
| 1319 | fn failingRead(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { | 1342 | fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { |
| 1320 | _ = r; | 1343 | _ = r; |
| 1321 | _ = w; | 1344 | _ = w; |
| 1322 | _ = limit; | 1345 | _ = limit; |
| ... | @@ -1409,8 +1432,8 @@ pub fn Hashed(comptime Hasher: type) type { | ... | @@ -1409,8 +1432,8 @@ pub fn Hashed(comptime Hasher: type) type { |
| 1409 | 1432 | ||
| 1410 | fn discard(r: *Reader, limit: Limit) Error!usize { | 1433 | fn discard(r: *Reader, limit: Limit) Error!usize { |
| 1411 | const this: *@This() = @alignCast(@fieldParentPtr("interface", r)); | 1434 | const this: *@This() = @alignCast(@fieldParentPtr("interface", r)); |
| 1412 | var bw = this.hasher.writable(&.{}); | 1435 | var w = this.hasher.writable(&.{}); |
| 1413 | const n = this.in.read(&bw, limit) catch |err| switch (err) { | 1436 | const n = this.in.read(&w, limit) catch |err| switch (err) { |
| 1414 | error.WriteFailed => unreachable, | 1437 | error.WriteFailed => unreachable, |
| 1415 | else => |e| return e, | 1438 | else => |e| return e, |
| 1416 | }; | 1439 | }; |
lib/std/io/Writer.zig+29-18| ... | @@ -9,7 +9,12 @@ const File = std.fs.File; | ... | @@ -9,7 +9,12 @@ const File = std.fs.File; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const Allocator = std.mem.Allocator; | 10 | const Allocator = std.mem.Allocator; |
| 11 | 11 | ||
| 12 | context: ?*anyopaque, | 12 | /// There are two strategies for obtaining context; one can use this field, or |
| 13 | /// embed the `Writer` and use `@fieldParentPtr`. This field must be either set | ||
| 14 | /// to a valid pointer or left as `null` because the interface will sometimes | ||
| 15 | /// check if this pointer value is a known special value, for example to make | ||
| 16 | /// `writableVector` work. | ||
| 17 | context: ?*anyopaque = null, | ||
| 13 | vtable: *const VTable, | 18 | vtable: *const VTable, |
| 14 | /// If this has length zero, the writer is unbuffered, and `flush` is a no-op. | 19 | /// If this has length zero, the writer is unbuffered, and `flush` is a no-op. |
| 15 | buffer: []u8, | 20 | buffer: []u8, |
| ... | @@ -30,11 +35,16 @@ pub const VTable = struct { | ... | @@ -30,11 +35,16 @@ pub const VTable = struct { |
| 30 | /// order. Elements of `data` may alias each other but may not alias | 35 | /// order. Elements of `data` may alias each other but may not alias |
| 31 | /// `buffer`. | 36 | /// `buffer`. |
| 32 | /// | 37 | /// |
| 33 | /// This function modifies `Writer` state. | 38 | /// This function modifies `Writer.end` and `Writer.buffer`. |
| 34 | /// | 39 | /// |
| 35 | /// `data.len` must be greater than zero, and the last element of `data` is | 40 | /// If `data.len` is zero, it indicates this is a "flush" operation; all |
| 36 | /// special. It is repeated as necessary so that it is written `splat` | 41 | /// remaining buffered data must be logically consumed. Generally, this |
| 37 | /// number of times, which may be zero. | 42 | /// means that `end` will be set to zero before returning, however, it is |
| 43 | /// legal for implementations to manage that data differently. There may be | ||
| 44 | /// subsequent calls to `drain` and `sendFile` after a flush operation. | ||
| 45 | /// | ||
| 46 | /// The last element of `data` is special. It is repeated as necessary so | ||
| 47 | /// that it is written `splat` number of times, which may be zero. | ||
| 38 | /// | 48 | /// |
| 39 | /// Number of bytes actually written is returned, excluding bytes from | 49 | /// Number of bytes actually written is returned, excluding bytes from |
| 40 | /// `buffer`. Bytes from `buffer` are tracked by modifying `end`. | 50 | /// `buffer`. Bytes from `buffer` are tracked by modifying `end`. |
| ... | @@ -94,7 +104,6 @@ pub const FileError = error{ | ... | @@ -94,7 +104,6 @@ pub const FileError = error{ |
| 94 | /// modified externally, `count` will always equal `end`. | 104 | /// modified externally, `count` will always equal `end`. |
| 95 | pub fn fixed(buffer: []u8) Writer { | 105 | pub fn fixed(buffer: []u8) Writer { |
| 96 | return .{ | 106 | return .{ |
| 97 | .context = undefined, | ||
| 98 | .vtable = &.{ .drain = fixedDrain }, | 107 | .vtable = &.{ .drain = fixedDrain }, |
| 99 | .buffer = buffer, | 108 | .buffer = buffer, |
| 100 | }; | 109 | }; |
| ... | @@ -105,7 +114,6 @@ pub fn hashed(w: *Writer, hasher: anytype) Hashed(@TypeOf(hasher)) { | ... | @@ -105,7 +114,6 @@ pub fn hashed(w: *Writer, hasher: anytype) Hashed(@TypeOf(hasher)) { |
| 105 | } | 114 | } |
| 106 | 115 | ||
| 107 | pub const failing: Writer = .{ | 116 | pub const failing: Writer = .{ |
| 108 | .context = undefined, | ||
| 109 | .vtable = &.{ | 117 | .vtable = &.{ |
| 110 | .drain = failingDrain, | 118 | .drain = failingDrain, |
| 111 | .sendFile = failingSendFile, | 119 | .sendFile = failingSendFile, |
| ... | @@ -114,7 +122,6 @@ pub const failing: Writer = .{ | ... | @@ -114,7 +122,6 @@ pub const failing: Writer = .{ |
| 114 | 122 | ||
| 115 | pub fn discarding(buffer: []u8) Writer { | 123 | pub fn discarding(buffer: []u8) Writer { |
| 116 | return .{ | 124 | return .{ |
| 117 | .context = undefined, | ||
| 118 | .vtable = &.{ | 125 | .vtable = &.{ |
| 119 | .drain = discardingDrain, | 126 | .drain = discardingDrain, |
| 120 | .sendFile = discardingSendFile, | 127 | .sendFile = discardingSendFile, |
| ... | @@ -199,12 +206,11 @@ pub fn writeSplatLimit( | ... | @@ -199,12 +206,11 @@ pub fn writeSplatLimit( |
| 199 | } | 206 | } |
| 200 | 207 | ||
| 201 | /// Drains all remaining buffered data. | 208 | /// Drains all remaining buffered data. |
| 209 | /// | ||
| 210 | /// It is legal for `VTable.drain` implementations to refrain from modifying | ||
| 211 | /// `end`. | ||
| 202 | pub fn flush(w: *Writer) Error!void { | 212 | pub fn flush(w: *Writer) Error!void { |
| 203 | const drainFn = w.vtable.drain; | 213 | assert(0 == try w.vtable.drain(w, &.{}, 0)); |
| 204 | // This implementation allows for drain functions that do not modify `end`, | ||
| 205 | // such as `fixedDrain`. | ||
| 206 | var remaining = w.end; | ||
| 207 | while (remaining != 0) remaining -= try drainFn(w, &.{""}, 1); | ||
| 208 | } | 214 | } |
| 209 | 215 | ||
| 210 | pub fn unusedCapacitySlice(w: *const Writer) []u8 { | 216 | pub fn unusedCapacitySlice(w: *const Writer) []u8 { |
| ... | @@ -321,14 +327,13 @@ pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void { | ... | @@ -321,14 +327,13 @@ pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void { |
| 321 | 327 | ||
| 322 | pub fn write(w: *Writer, bytes: []const u8) Error!usize { | 328 | pub fn write(w: *Writer, bytes: []const u8) Error!usize { |
| 323 | if (w.end + bytes.len <= w.buffer.len) { | 329 | if (w.end + bytes.len <= w.buffer.len) { |
| 330 | @branchHint(.likely); | ||
| 324 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); | 331 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); |
| 325 | w.end += bytes.len; | 332 | w.end += bytes.len; |
| 326 | w.count += bytes.len; | 333 | w.count += bytes.len; |
| 327 | return bytes.len; | 334 | return bytes.len; |
| 328 | } | 335 | } |
| 329 | const end = w.end; | 336 | return w.vtable.drain(w, &.{bytes}, 1); |
| 330 | const n = try w.vtable.drain(w, &.{bytes}, 1); | ||
| 331 | return n -| end; | ||
| 332 | } | 337 | } |
| 333 | 338 | ||
| 334 | /// Calls `write` as many times as necessary such that all of `bytes` are | 339 | /// Calls `write` as many times as necessary such that all of `bytes` are |
| ... | @@ -1675,6 +1680,7 @@ pub fn unimplementedSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit | ... | @@ -1675,6 +1680,7 @@ pub fn unimplementedSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit |
| 1675 | /// available buffer has been filled. Also, it may be called from `flush` in | 1680 | /// available buffer has been filled. Also, it may be called from `flush` in |
| 1676 | /// which case it should return successfully. | 1681 | /// which case it should return successfully. |
| 1677 | fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { | 1682 | fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { |
| 1683 | if (data.len == 0) return 0; | ||
| 1678 | for (data[0 .. data.len - 1]) |bytes| { | 1684 | for (data[0 .. data.len - 1]) |bytes| { |
| 1679 | const dest = w.buffer[w.end..]; | 1685 | const dest = w.buffer[w.end..]; |
| 1680 | const len = @min(bytes.len, dest.len); | 1686 | const len = @min(bytes.len, dest.len); |
| ... | @@ -1726,7 +1732,6 @@ pub fn Hashed(comptime Hasher: type) type { | ... | @@ -1726,7 +1732,6 @@ pub fn Hashed(comptime Hasher: type) type { |
| 1726 | .out = out, | 1732 | .out = out, |
| 1727 | .hasher = .{}, | 1733 | .hasher = .{}, |
| 1728 | .interface = .{ | 1734 | .interface = .{ |
| 1729 | .context = undefined, | ||
| 1730 | .vtable = &.{@This().drain}, | 1735 | .vtable = &.{@This().drain}, |
| 1731 | }, | 1736 | }, |
| 1732 | }; | 1737 | }; |
| ... | @@ -1734,6 +1739,13 @@ pub fn Hashed(comptime Hasher: type) type { | ... | @@ -1734,6 +1739,13 @@ pub fn Hashed(comptime Hasher: type) type { |
| 1734 | 1739 | ||
| 1735 | fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { | 1740 | fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { |
| 1736 | const this: *@This() = @alignCast(@fieldParentPtr("interface", w)); | 1741 | const this: *@This() = @alignCast(@fieldParentPtr("interface", w)); |
| 1742 | if (data.len == 0) { | ||
| 1743 | const buf = w.buffered(); | ||
| 1744 | try this.out.writeAll(buf); | ||
| 1745 | this.hasher.update(buf); | ||
| 1746 | w.end = 0; | ||
| 1747 | return buf.len; | ||
| 1748 | } | ||
| 1737 | const aux_n = try this.out.writeSplatAux(w.buffered(), data, splat); | 1749 | const aux_n = try this.out.writeSplatAux(w.buffered(), data, splat); |
| 1738 | if (aux_n < w.end) { | 1750 | if (aux_n < w.end) { |
| 1739 | this.hasher.update(w.buffer[0..aux_n]); | 1751 | this.hasher.update(w.buffer[0..aux_n]); |
| ... | @@ -1839,7 +1851,6 @@ pub const Allocating = struct { | ... | @@ -1839,7 +1851,6 @@ pub const Allocating = struct { |
| 1839 | 1851 | ||
| 1840 | const init_interface: Writer = .{ | 1852 | const init_interface: Writer = .{ |
| 1841 | .interface = .{ | 1853 | .interface = .{ |
| 1842 | .context = undefined, | ||
| 1843 | .vtable = &.{ | 1854 | .vtable = &.{ |
| 1844 | .drain = Allocating.drain, | 1855 | .drain = Allocating.drain, |
| 1845 | .sendFile = Allocating.sendFile, | 1856 | .sendFile = Allocating.sendFile, |
lib/std/net.zig+3-23| ... | @@ -1912,10 +1912,7 @@ pub const Stream = struct { | ... | @@ -1912,10 +1912,7 @@ pub const Stream = struct { |
| 1912 | return .{ | 1912 | return .{ |
| 1913 | .interface_state = .{ | 1913 | .interface_state = .{ |
| 1914 | .context = undefined, | 1914 | .context = undefined, |
| 1915 | .vtable = &.{ | 1915 | .vtable = &.{ .stream = stream }, |
| 1916 | .stream = stream, | ||
| 1917 | .discard = discard, | ||
| 1918 | }, | ||
| 1919 | .buffer = buffer, | 1916 | .buffer = buffer, |
| 1920 | }, | 1917 | }, |
| 1921 | .net_stream = net_stream, | 1918 | .net_stream = net_stream, |
| ... | @@ -1924,19 +1921,9 @@ pub const Stream = struct { | ... | @@ -1924,19 +1921,9 @@ pub const Stream = struct { |
| 1924 | 1921 | ||
| 1925 | fn stream(io_r: *io.Reader, io_w: *io.Writer, limit: io.Limit) io.Reader.StreamError!usize { | 1922 | fn stream(io_r: *io.Reader, io_w: *io.Writer, limit: io.Limit) io.Reader.StreamError!usize { |
| 1926 | const r: *Reader = @fieldParentPtr("interface", io_r); | 1923 | const r: *Reader = @fieldParentPtr("interface", io_r); |
| 1927 | const data = io_w.writableVector(limit); | ||
| 1928 | var iovecs: [max_buffers_len]windows.WSABUF = undefined; | 1924 | var iovecs: [max_buffers_len]windows.WSABUF = undefined; |
| 1929 | var iovecs_i: usize = 0; | 1925 | const bufs = io_w.writableVectorWsa(&iovecs, limit); |
| 1930 | for (data) |d| { | 1926 | assert(bufs[0].len > 0); |
| 1931 | // In case Windows checks pointer address before length, we must omit | ||
| 1932 | // length-zero vectors. | ||
| 1933 | if (d.len == 0) continue; | ||
| 1934 | iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len }; | ||
| 1935 | iovecs_i += 1; | ||
| 1936 | if (iovecs_i >= iovecs.len) break; | ||
| 1937 | } | ||
| 1938 | const bufs = iovecs[0..iovecs_i]; | ||
| 1939 | if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`. | ||
| 1940 | var n: u32 = undefined; | 1927 | var n: u32 = undefined; |
| 1941 | var flags: u32 = 0; | 1928 | var flags: u32 = 0; |
| 1942 | const rc = windows.ws2_32.WSARecvFrom(r.net_stream.handle, bufs.ptr, bufs.len, &n, &flags, null, null, null, null); | 1929 | const rc = windows.ws2_32.WSARecvFrom(r.net_stream.handle, bufs.ptr, bufs.len, &n, &flags, null, null, null, null); |
| ... | @@ -1958,13 +1945,6 @@ pub const Stream = struct { | ... | @@ -1958,13 +1945,6 @@ pub const Stream = struct { |
| 1958 | if (n == 0) return error.EndOfStream; | 1945 | if (n == 0) return error.EndOfStream; |
| 1959 | return io_w.advanceVector(n); | 1946 | return io_w.advanceVector(n); |
| 1960 | } | 1947 | } |
| 1961 | |||
| 1962 | fn discard(io_r: *io.Reader, limit: io.Limit) io.Reader.Error!usize { | ||
| 1963 | const r: *Reader = @fieldParentPtr("interface", io_r); | ||
| 1964 | _ = r; | ||
| 1965 | _ = limit; | ||
| 1966 | @panic("TODO"); | ||
| 1967 | } | ||
| 1968 | }, | 1948 | }, |
| 1969 | else => struct { | 1949 | else => struct { |
| 1970 | file_reader: File.Reader, | 1950 | file_reader: File.Reader, |
lib/std/zip.zig+29-42| ... | @@ -8,6 +8,7 @@ const std = @import("std"); | ... | @@ -8,6 +8,7 @@ const std = @import("std"); |
| 8 | const File = std.fs.File; | 8 | const File = std.fs.File; |
| 9 | const is_le = builtin.target.cpu.arch.endian() == .little; | 9 | const is_le = builtin.target.cpu.arch.endian() == .little; |
| 10 | const Writer = std.io.Writer; | 10 | const Writer = std.io.Writer; |
| 11 | const Reader = std.io.Reader; | ||
| 11 | 12 | ||
| 12 | pub const CompressionMethod = enum(u16) { | 13 | pub const CompressionMethod = enum(u16) { |
| 13 | store = 0, | 14 | store = 0, |
| ... | @@ -160,61 +161,47 @@ pub const EndRecord = extern struct { | ... | @@ -160,61 +161,47 @@ pub const EndRecord = extern struct { |
| 160 | } | 161 | } |
| 161 | }; | 162 | }; |
| 162 | 163 | ||
| 163 | pub const Decompress = union { | 164 | pub const Decompress = struct { |
| 164 | inflate: std.compress.flate.Decompress, | 165 | interface: Reader, |
| 165 | store: *std.io.Reader, | 166 | state: union { |
| 166 | 167 | inflate: std.compress.flate.Decompress, | |
| 167 | fn readable( | 168 | store: *Reader, |
| 168 | d: *Decompress, | 169 | }, |
| 169 | reader: *std.io.Reader, | 170 | |
| 170 | method: CompressionMethod, | 171 | pub fn init(reader: *Reader, method: CompressionMethod, buffer: []u8) Reader { |
| 171 | buffer: []u8, | 172 | return switch (method) { |
| 172 | ) std.io.Reader { | 173 | .store => .{ |
| 173 | switch (method) { | 174 | .state = .{ .store = reader }, |
| 174 | .store => { | 175 | .interface = .{ |
| 175 | d.* = .{ .store = reader }; | 176 | .context = undefined, |
| 176 | return .{ | 177 | .vtable = &.{ .stream = streamStore }, |
| 177 | .unbuffered_reader = .{ | ||
| 178 | .context = d, | ||
| 179 | .vtable = &.{ .read = readStore }, | ||
| 180 | }, | ||
| 181 | .buffer = buffer, | 178 | .buffer = buffer, |
| 182 | .end = 0, | 179 | .end = 0, |
| 183 | .seek = 0, | 180 | .seek = 0, |
| 184 | }; | 181 | }, |
| 185 | }, | 182 | }, |
| 186 | .deflate => { | 183 | .deflate => .{ |
| 187 | d.* = .{ .inflate = .init(reader, .raw) }; | 184 | .state = .{ .inflate = .init(reader, .raw) }, |
| 188 | return .{ | 185 | .interface = .{ |
| 189 | .unbuffered_reader = .{ | 186 | .context = undefined, |
| 190 | .context = d, | 187 | .vtable = &.{ .stream = streamDeflate }, |
| 191 | .vtable = &.{ .read = readDeflate }, | ||
| 192 | }, | ||
| 193 | .buffer = buffer, | 188 | .buffer = buffer, |
| 194 | .end = 0, | 189 | .end = 0, |
| 195 | .seek = 0, | 190 | .seek = 0, |
| 196 | }; | 191 | }, |
| 197 | }, | 192 | }, |
| 198 | else => unreachable, | 193 | else => unreachable, |
| 199 | } | 194 | }; |
| 200 | } | 195 | } |
| 201 | 196 | ||
| 202 | fn readStore( | 197 | fn streamStore(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize { |
| 203 | context: ?*anyopaque, | 198 | const d: *Decompress = @fieldParentPtr("interface", r); |
| 204 | writer: *Writer, | 199 | return d.store.read(w, limit); |
| 205 | limit: std.io.Limit, | ||
| 206 | ) std.io.Reader.StreamError!usize { | ||
| 207 | const d: *Decompress = @ptrCast(@alignCast(context)); | ||
| 208 | return d.store.read(writer, limit); | ||
| 209 | } | 200 | } |
| 210 | 201 | ||
| 211 | fn readDeflate( | 202 | fn streamDeflate(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize { |
| 212 | context: ?*anyopaque, | 203 | const d: *Decompress = @fieldParentPtr("interface", r); |
| 213 | writer: *Writer, | 204 | return std.compress.flate.Decompress.read(&d.inflate, w, limit); |
| 214 | limit: std.io.Limit, | ||
| 215 | ) std.io.Reader.StreamError!usize { | ||
| 216 | const d: *Decompress = @ptrCast(@alignCast(context)); | ||
| 217 | return std.compress.flate.Decompress.read(&d.inflate, writer, limit); | ||
| 218 | } | 205 | } |
| 219 | }; | 206 | }; |
| 220 | 207 |