| author | |
| committer | |
| log | 3650cd3e8efd730fb6305bdefbbf8053c352bb0c |
| tree | 8e41c99024345b1cdb7774d5e9dcac2ee33da3d8 |
| parent | 7b417c6caf13e07d05bf798cae2f8beeaee4fe6c |
15 files changed, 160 insertions(+), 279 deletions(-)
lib/std/Build/Cache.zig+1-1| ... | @@ -663,7 +663,7 @@ pub const Manifest = struct { | ... | @@ -663,7 +663,7 @@ pub const Manifest = struct { |
| 663 | const gpa = self.cache.gpa; | 663 | const gpa = self.cache.gpa; |
| 664 | const input_file_count = self.files.entries.len; | 664 | const input_file_count = self.files.entries.len; |
| 665 | var manifest_reader = self.manifest_file.?.reader(); // Reads positionally from zero. | 665 | var manifest_reader = self.manifest_file.?.reader(); // Reads positionally from zero. |
| 666 | const limit: std.io.Reader.Limit = .limited(manifest_file_size_max); | 666 | const limit: std.io.Limit = .limited(manifest_file_size_max); |
| 667 | const file_contents = manifest_reader.interface().readRemainingAlloc(gpa, limit) catch |err| switch (err) { | 667 | const file_contents = manifest_reader.interface().readRemainingAlloc(gpa, limit) catch |err| switch (err) { |
| 668 | error.OutOfMemory => return error.OutOfMemory, | 668 | error.OutOfMemory => return error.OutOfMemory, |
| 669 | error.StreamTooLong => return error.OutOfMemory, | 669 | error.StreamTooLong => return error.OutOfMemory, |
lib/std/compress/flate/Compress.zig+1-1| ... | @@ -768,7 +768,7 @@ fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool { | ... | @@ -768,7 +768,7 @@ fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool { |
| 768 | fn read( | 768 | fn read( |
| 769 | context: ?*anyopaque, | 769 | context: ?*anyopaque, |
| 770 | bw: *std.io.BufferedWriter, | 770 | bw: *std.io.BufferedWriter, |
| 771 | limit: std.io.Reader.Limit, | 771 | limit: std.io.Limit, |
| 772 | ) std.io.Reader.RwError!usize { | 772 | ) std.io.Reader.RwError!usize { |
| 773 | const c: *Compress = @ptrCast(@alignCast(context)); | 773 | const c: *Compress = @ptrCast(@alignCast(context)); |
| 774 | switch (c.state) { | 774 | switch (c.state) { |
lib/std/compress/flate/Decompress.zig+3-3| ... | @@ -142,7 +142,7 @@ fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol { | ... | @@ -142,7 +142,7 @@ fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol { |
| 142 | pub fn read( | 142 | pub fn read( |
| 143 | context: ?*anyopaque, | 143 | context: ?*anyopaque, |
| 144 | bw: *std.io.BufferedWriter, | 144 | bw: *std.io.BufferedWriter, |
| 145 | limit: std.io.Reader.Limit, | 145 | limit: std.io.Limit, |
| 146 | ) std.io.Reader.RwError!usize { | 146 | ) std.io.Reader.RwError!usize { |
| 147 | const d: *Decompress = @alignCast(@ptrCast(context)); | 147 | const d: *Decompress = @alignCast(@ptrCast(context)); |
| 148 | return readInner(d, bw, limit) catch |err| switch (err) { | 148 | return readInner(d, bw, limit) catch |err| switch (err) { |
| ... | @@ -160,7 +160,7 @@ pub fn read( | ... | @@ -160,7 +160,7 @@ pub fn read( |
| 160 | fn readInner( | 160 | fn readInner( |
| 161 | d: *Decompress, | 161 | d: *Decompress, |
| 162 | bw: *std.io.BufferedWriter, | 162 | bw: *std.io.BufferedWriter, |
| 163 | limit: std.io.Reader.Limit, | 163 | limit: std.io.Limit, |
| 164 | ) (Error || error{ WriteFailed, EndOfStream })!usize { | 164 | ) (Error || error{ WriteFailed, EndOfStream })!usize { |
| 165 | const in = d.input; | 165 | const in = d.input; |
| 166 | sw: switch (d.state) { | 166 | sw: switch (d.state) { |
| ... | @@ -351,7 +351,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { | ... | @@ -351,7 +351,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 351 | @panic("TODO remove readVec primitive"); | 351 | @panic("TODO remove readVec primitive"); |
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { | 354 | fn discard(context: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { |
| 355 | _ = context; | 355 | _ = context; |
| 356 | _ = limit; | 356 | _ = limit; |
| 357 | // Problem here is we still need access to the output ring buffer. | 357 | // Problem here is we still need access to the output ring buffer. |
lib/std/compress/zstd/Decompress.zig+12-11| ... | @@ -2,6 +2,7 @@ const Decompress = @This(); | ... | @@ -2,6 +2,7 @@ const Decompress = @This(); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 4 | const Reader = std.io.Reader; | 4 | const Reader = std.io.Reader; |
| 5 | const Limit = std.io.Limit; | ||
| 5 | const BufferedWriter = std.io.BufferedWriter; | 6 | const BufferedWriter = std.io.BufferedWriter; |
| 6 | const BufferedReader = std.io.BufferedReader; | 7 | const BufferedReader = std.io.BufferedReader; |
| 7 | const zstd = @import("../zstd.zig"); | 8 | const zstd = @import("../zstd.zig"); |
| ... | @@ -77,7 +78,7 @@ pub fn reader(self: *Decompress) Reader { | ... | @@ -77,7 +78,7 @@ pub fn reader(self: *Decompress) Reader { |
| 77 | }; | 78 | }; |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | fn read(context: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) Reader.RwError!usize { | 81 | fn read(context: ?*anyopaque, bw: *BufferedWriter, limit: Limit) Reader.RwError!usize { |
| 81 | const d: *Decompress = @ptrCast(@alignCast(context)); | 82 | const d: *Decompress = @ptrCast(@alignCast(context)); |
| 82 | const in = d.input; | 83 | const in = d.input; |
| 83 | 84 | ||
| ... | @@ -139,7 +140,7 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void { | ... | @@ -139,7 +140,7 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void { |
| 139 | } | 140 | } |
| 140 | } | 141 | } |
| 141 | 142 | ||
| 142 | fn readInFrame(d: *Decompress, bw: *BufferedWriter, limit: Reader.Limit, state: *State.InFrame) !usize { | 143 | fn readInFrame(d: *Decompress, bw: *BufferedWriter, limit: Limit, state: *State.InFrame) !usize { |
| 143 | const in = d.input; | 144 | const in = d.input; |
| 144 | 145 | ||
| 145 | const header_bytes = try in.takeArray(3); | 146 | const header_bytes = try in.takeArray(3); |
| ... | @@ -166,7 +167,7 @@ fn readInFrame(d: *Decompress, bw: *BufferedWriter, limit: Reader.Limit, state: | ... | @@ -166,7 +167,7 @@ fn readInFrame(d: *Decompress, bw: *BufferedWriter, limit: Reader.Limit, state: |
| 166 | var literals_buffer: [zstd.block_size_max]u8 = undefined; | 167 | var literals_buffer: [zstd.block_size_max]u8 = undefined; |
| 167 | var sequence_buffer: [zstd.block_size_max]u8 = undefined; | 168 | var sequence_buffer: [zstd.block_size_max]u8 = undefined; |
| 168 | var decode: Frame.Zstandard.Decode = .init(&literal_fse_buffer, &match_fse_buffer, &offset_fse_buffer); | 169 | var decode: Frame.Zstandard.Decode = .init(&literal_fse_buffer, &match_fse_buffer, &offset_fse_buffer); |
| 169 | var remaining: Reader.Limit = .limited(block_size); | 170 | var remaining: Limit = .limited(block_size); |
| 170 | const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer); | 171 | const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer); |
| 171 | const sequences_header = try SequencesSection.Header.decode(in, &remaining); | 172 | const sequences_header = try SequencesSection.Header.decode(in, &remaining); |
| 172 | 173 | ||
| ... | @@ -446,7 +447,7 @@ pub const Frame = struct { | ... | @@ -446,7 +447,7 @@ pub const Frame = struct { |
| 446 | pub fn prepare( | 447 | pub fn prepare( |
| 447 | self: *Decode, | 448 | self: *Decode, |
| 448 | in: *BufferedReader, | 449 | in: *BufferedReader, |
| 449 | remaining: *Reader.Limit, | 450 | remaining: *Limit, |
| 450 | literals: LiteralsSection, | 451 | literals: LiteralsSection, |
| 451 | sequences_header: SequencesSection.Header, | 452 | sequences_header: SequencesSection.Header, |
| 452 | ) PrepareError!void { | 453 | ) PrepareError!void { |
| ... | @@ -536,7 +537,7 @@ pub const Frame = struct { | ... | @@ -536,7 +537,7 @@ pub const Frame = struct { |
| 536 | fn updateFseTable( | 537 | fn updateFseTable( |
| 537 | self: *Decode, | 538 | self: *Decode, |
| 538 | in: *BufferedReader, | 539 | in: *BufferedReader, |
| 539 | remaining: *Reader.Limit, | 540 | remaining: *Limit, |
| 540 | comptime choice: DataType, | 541 | comptime choice: DataType, |
| 541 | mode: SequencesSection.Header.Mode, | 542 | mode: SequencesSection.Header.Mode, |
| 542 | ) !void { | 543 | ) !void { |
| ... | @@ -857,7 +858,7 @@ pub const LiteralsSection = struct { | ... | @@ -857,7 +858,7 @@ pub const LiteralsSection = struct { |
| 857 | compressed_size: ?u18, | 858 | compressed_size: ?u18, |
| 858 | 859 | ||
| 859 | /// Decode a literals section header. | 860 | /// Decode a literals section header. |
| 860 | pub fn decode(in: *BufferedReader, remaining: *Reader.Limit) !Header { | 861 | pub fn decode(in: *BufferedReader, remaining: *Limit) !Header { |
| 861 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | 862 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; |
| 862 | const byte0 = try in.takeByte(); | 863 | const byte0 = try in.takeByte(); |
| 863 | const block_type: BlockType = @enumFromInt(byte0 & 0b11); | 864 | const block_type: BlockType = @enumFromInt(byte0 & 0b11); |
| ... | @@ -964,7 +965,7 @@ pub const LiteralsSection = struct { | ... | @@ -964,7 +965,7 @@ pub const LiteralsSection = struct { |
| 964 | MissingStartBit, | 965 | MissingStartBit, |
| 965 | }; | 966 | }; |
| 966 | 967 | ||
| 967 | pub fn decode(in: *BufferedReader, remaining: *Reader.Limit) HuffmanTree.DecodeError!HuffmanTree { | 968 | pub fn decode(in: *BufferedReader, remaining: *Limit) HuffmanTree.DecodeError!HuffmanTree { |
| 968 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | 969 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; |
| 969 | const header = try in.takeByte(); | 970 | const header = try in.takeByte(); |
| 970 | if (header < 128) { | 971 | if (header < 128) { |
| ... | @@ -976,7 +977,7 @@ pub const LiteralsSection = struct { | ... | @@ -976,7 +977,7 @@ pub const LiteralsSection = struct { |
| 976 | 977 | ||
| 977 | fn decodeDirect( | 978 | fn decodeDirect( |
| 978 | in: *BufferedReader, | 979 | in: *BufferedReader, |
| 979 | remaining: *Reader.Limit, | 980 | remaining: *Limit, |
| 980 | encoded_symbol_count: usize, | 981 | encoded_symbol_count: usize, |
| 981 | ) HuffmanTree.DecodeError!HuffmanTree { | 982 | ) HuffmanTree.DecodeError!HuffmanTree { |
| 982 | var weights: [256]u4 = undefined; | 983 | var weights: [256]u4 = undefined; |
| ... | @@ -993,7 +994,7 @@ pub const LiteralsSection = struct { | ... | @@ -993,7 +994,7 @@ pub const LiteralsSection = struct { |
| 993 | 994 | ||
| 994 | fn decodeFse( | 995 | fn decodeFse( |
| 995 | in: *BufferedReader, | 996 | in: *BufferedReader, |
| 996 | remaining: *Reader.Limit, | 997 | remaining: *Limit, |
| 997 | compressed_size: usize, | 998 | compressed_size: usize, |
| 998 | ) HuffmanTree.DecodeError!HuffmanTree { | 999 | ) HuffmanTree.DecodeError!HuffmanTree { |
| 999 | var weights: [256]u4 = undefined; | 1000 | var weights: [256]u4 = undefined; |
| ... | @@ -1161,7 +1162,7 @@ pub const LiteralsSection = struct { | ... | @@ -1161,7 +1162,7 @@ pub const LiteralsSection = struct { |
| 1161 | MissingStartBit, | 1162 | MissingStartBit, |
| 1162 | }; | 1163 | }; |
| 1163 | 1164 | ||
| 1164 | pub fn decode(in: *BufferedReader, remaining: *Reader.Limit, buffer: []u8) DecodeError!LiteralsSection { | 1165 | pub fn decode(in: *BufferedReader, remaining: *Limit, buffer: []u8) DecodeError!LiteralsSection { |
| 1165 | const header = try Header.decode(in, remaining); | 1166 | const header = try Header.decode(in, remaining); |
| 1166 | switch (header.block_type) { | 1167 | switch (header.block_type) { |
| 1167 | .raw => { | 1168 | .raw => { |
| ... | @@ -1232,7 +1233,7 @@ pub const SequencesSection = struct { | ... | @@ -1232,7 +1233,7 @@ pub const SequencesSection = struct { |
| 1232 | ReadFailed, | 1233 | ReadFailed, |
| 1233 | }; | 1234 | }; |
| 1234 | 1235 | ||
| 1235 | pub fn decode(in: *BufferedReader, remaining: *Reader.Limit) DecodeError!Header { | 1236 | pub fn decode(in: *BufferedReader, remaining: *Limit) DecodeError!Header { |
| 1236 | var sequence_count: u24 = undefined; | 1237 | var sequence_count: u24 = undefined; |
| 1237 | 1238 | ||
| 1238 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | 1239 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; |
lib/std/crypto/tls/Client.zig+1-1| ... | @@ -1043,7 +1043,7 @@ pub fn eof(c: Client) bool { | ... | @@ -1043,7 +1043,7 @@ pub fn eof(c: Client) bool { |
| 1043 | return c.received_close_notify; | 1043 | return c.received_close_notify; |
| 1044 | } | 1044 | } |
| 1045 | 1045 | ||
| 1046 | fn read(context: ?*anyopaque, bw: *std.io.BufferedWriter, limit: Reader.Limit) Reader.RwError!usize { | 1046 | fn read(context: ?*anyopaque, bw: *std.io.BufferedWriter, limit: std.io.Limit) Reader.RwError!usize { |
| 1047 | const c: *Client = @ptrCast(@alignCast(context)); | 1047 | const c: *Client = @ptrCast(@alignCast(context)); |
| 1048 | if (c.eof()) return error.EndOfStream; | 1048 | if (c.eof()) return error.EndOfStream; |
| 1049 | const input = c.input; | 1049 | const input = c.input; |
lib/std/fifo.zig+2-2| ... | @@ -247,7 +247,7 @@ pub fn LinearFifo( | ... | @@ -247,7 +247,7 @@ pub fn LinearFifo( |
| 247 | fn readerRead( | 247 | fn readerRead( |
| 248 | ctx: ?*anyopaque, | 248 | ctx: ?*anyopaque, |
| 249 | bw: *std.io.BufferedWriter, | 249 | bw: *std.io.BufferedWriter, |
| 250 | limit: std.io.Reader.Limit, | 250 | limit: std.io.Limit, |
| 251 | ) std.io.Reader.RwError!usize { | 251 | ) std.io.Reader.RwError!usize { |
| 252 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | 252 | const fifo: *Self = @alignCast(@ptrCast(ctx)); |
| 253 | _ = fifo; | 253 | _ = fifo; |
| ... | @@ -261,7 +261,7 @@ pub fn LinearFifo( | ... | @@ -261,7 +261,7 @@ pub fn LinearFifo( |
| 261 | _ = data; | 261 | _ = data; |
| 262 | @panic("TODO"); | 262 | @panic("TODO"); |
| 263 | } | 263 | } |
| 264 | fn readerDiscard(ctx: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { | 264 | fn readerDiscard(ctx: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { |
| 265 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | 265 | const fifo: *Self = @alignCast(@ptrCast(ctx)); |
| 266 | _ = fifo; | 266 | _ = fifo; |
| 267 | _ = limit; | 267 | _ = limit; |
lib/std/fs/Dir.zig+3-3| ... | @@ -1963,7 +1963,7 @@ pub fn readFileAlloc( | ... | @@ -1963,7 +1963,7 @@ pub fn readFileAlloc( |
| 1963 | /// * The array list's length is increased by exactly one byte past `limit`. | 1963 | /// * The array list's length is increased by exactly one byte past `limit`. |
| 1964 | /// * The file seek position is advanced by exactly one byte past `limit`. | 1964 | /// * The file seek position is advanced by exactly one byte past `limit`. |
| 1965 | /// * `error.StreamTooLong` is returned. | 1965 | /// * `error.StreamTooLong` is returned. |
| 1966 | limit: std.io.Reader.Limit, | 1966 | limit: std.io.Limit, |
| 1967 | ) ReadFileAllocError![]u8 { | 1967 | ) ReadFileAllocError![]u8 { |
| 1968 | return dir.readFileAllocOptions(file_path, gpa, limit, null, .of(u8), null); | 1968 | return dir.readFileAllocOptions(file_path, gpa, limit, null, .of(u8), null); |
| 1969 | } | 1969 | } |
| ... | @@ -1982,7 +1982,7 @@ pub fn readFileAllocOptions( | ... | @@ -1982,7 +1982,7 @@ pub fn readFileAllocOptions( |
| 1982 | /// * The array list's length is increased by exactly one byte past `limit`. | 1982 | /// * The array list's length is increased by exactly one byte past `limit`. |
| 1983 | /// * The file seek position is advanced by exactly one byte past `limit`. | 1983 | /// * The file seek position is advanced by exactly one byte past `limit`. |
| 1984 | /// * `error.StreamTooLong` is returned. | 1984 | /// * `error.StreamTooLong` is returned. |
| 1985 | limit: std.io.Reader.Limit, | 1985 | limit: std.io.Limit, |
| 1986 | /// If specified, the initial buffer size is calculated using this value, | 1986 | /// If specified, the initial buffer size is calculated using this value, |
| 1987 | /// otherwise the effective file size is used instead. | 1987 | /// otherwise the effective file size is used instead. |
| 1988 | size_hint: ?usize, | 1988 | size_hint: ?usize, |
| ... | @@ -2020,7 +2020,7 @@ pub fn readFileIntoArrayList( | ... | @@ -2020,7 +2020,7 @@ pub fn readFileIntoArrayList( |
| 2020 | /// On other platforms, an opaque sequence of bytes with no particular encoding. | 2020 | /// On other platforms, an opaque sequence of bytes with no particular encoding. |
| 2021 | file_path: []const u8, | 2021 | file_path: []const u8, |
| 2022 | gpa: Allocator, | 2022 | gpa: Allocator, |
| 2023 | limit: std.io.Reader.Limit, | 2023 | limit: std.io.Limit, |
| 2024 | /// If specified, the initial buffer size is calculated using this value, | 2024 | /// If specified, the initial buffer size is calculated using this value, |
| 2025 | /// otherwise the effective file size is used instead. | 2025 | /// otherwise the effective file size is used instead. |
| 2026 | size_hint: ?usize, | 2026 | size_hint: ?usize, |
lib/std/fs/File.zig+109-198| ... | @@ -922,12 +922,13 @@ pub const Reader = struct { | ... | @@ -922,12 +922,13 @@ pub const Reader = struct { |
| 922 | positional, | 922 | positional, |
| 923 | streaming_reading, | 923 | streaming_reading, |
| 924 | positional_reading, | 924 | positional_reading, |
| 925 | failure, | ||
| 925 | 926 | ||
| 926 | pub fn toStreaming(m: @This()) @This() { | 927 | pub fn toStreaming(m: @This()) @This() { |
| 927 | return switch (m) { | 928 | return switch (m) { |
| 928 | .positional => .streaming, | 929 | .positional, .streaming => .streaming, |
| 929 | .positional_reading => .streaming_reading, | 930 | .positional_reading, .streaming_reading => .streaming_reading, |
| 930 | else => unreachable, | 931 | .failure => .failure, |
| 931 | }; | 932 | }; |
| 932 | } | 933 | } |
| 933 | }; | 934 | }; |
| ... | @@ -936,8 +937,7 @@ pub const Reader = struct { | ... | @@ -936,8 +937,7 @@ pub const Reader = struct { |
| 936 | return .{ | 937 | return .{ |
| 937 | .context = r, | 938 | .context = r, |
| 938 | .vtable = &.{ | 939 | .vtable = &.{ |
| 939 | .read = Reader.read, | 940 | .read = Reader.stream, |
| 940 | .readVec = Reader.readVec, | ||
| 941 | .discard = Reader.discard, | 941 | .discard = Reader.discard, |
| 942 | }, | 942 | }, |
| 943 | }; | 943 | }; |
| ... | @@ -963,12 +963,14 @@ pub const Reader = struct { | ... | @@ -963,12 +963,14 @@ pub const Reader = struct { |
| 963 | pub fn seekBy(r: *Reader, offset: i64) SeekError!void { | 963 | pub fn seekBy(r: *Reader, offset: i64) SeekError!void { |
| 964 | switch (r.mode) { | 964 | switch (r.mode) { |
| 965 | .positional, .positional_reading => { | 965 | .positional, .positional_reading => { |
| 966 | r.pos += offset; | 966 | // TODO: make += operator allow any integer types |
| 967 | r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset); | ||
| 967 | }, | 968 | }, |
| 968 | .streaming, .streaming_reading => { | 969 | .streaming, .streaming_reading => { |
| 969 | const seek_err = r.seek_err orelse e: { | 970 | const seek_err = r.seek_err orelse e: { |
| 970 | if (posix.lseek_CUR(r.file.handle, offset)) |_| { | 971 | if (posix.lseek_CUR(r.file.handle, offset)) |_| { |
| 971 | r.pos += offset; | 972 | // TODO: make += operator allow any integer types |
| 973 | r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset); | ||
| 972 | return; | 974 | return; |
| 973 | } else |err| { | 975 | } else |err| { |
| 974 | r.seek_err = err; | 976 | r.seek_err = err; |
| ... | @@ -983,6 +985,7 @@ pub const Reader = struct { | ... | @@ -983,6 +985,7 @@ pub const Reader = struct { |
| 983 | remaining -= n; | 985 | remaining -= n; |
| 984 | } | 986 | } |
| 985 | }, | 987 | }, |
| 988 | .failure => return error.Unseekable, | ||
| 986 | } | 989 | } |
| 987 | } | 990 | } |
| 988 | 991 | ||
| ... | @@ -1006,188 +1009,42 @@ pub const Reader = struct { | ... | @@ -1006,188 +1009,42 @@ pub const Reader = struct { |
| 1006 | /// vectors through the underlying read calls as possible. | 1009 | /// vectors through the underlying read calls as possible. |
| 1007 | const max_buffers_len = 16; | 1010 | const max_buffers_len = 16; |
| 1008 | 1011 | ||
| 1009 | fn read( | 1012 | fn stream( |
| 1010 | context: ?*anyopaque, | 1013 | context: ?*anyopaque, |
| 1011 | bw: *BufferedWriter, | 1014 | bw: *BufferedWriter, |
| 1012 | limit: std.io.Reader.Limit, | 1015 | limit: std.io.Limit, |
| 1013 | ) std.io.Reader.RwError!usize { | 1016 | ) std.io.Reader.StreamError!usize { |
| 1014 | const r: *Reader = @ptrCast(@alignCast(context)); | 1017 | const r: *Reader = @ptrCast(@alignCast(context)); |
| 1015 | const file = r.file; | 1018 | return bw.writeFile(r, limit, &.{}, 0) catch |write_file_error| switch (write_file_error) { |
| 1016 | const pos = r.pos; | 1019 | error.ReadFailed => return error.ReadFailed, |
| 1017 | switch (r.mode) { | 1020 | error.WriteFailed => return error.WriteFailed, |
| 1018 | .positional => { | 1021 | error.Unimplemented => switch (r.mode) { |
| 1019 | const size = r.size orelse { | 1022 | .positional => { |
| 1020 | if (file.getEndPos()) |size| { | 1023 | r.mode = .positional_reading; |
| 1021 | r.size = size; | ||
| 1022 | } else |err| { | ||
| 1023 | r.size_err = err; | ||
| 1024 | r.mode = .streaming; | ||
| 1025 | } | ||
| 1026 | return 0; | 1024 | return 0; |
| 1027 | }; | 1025 | }, |
| 1028 | const new_limit = limit.min(.limited(size - pos)); | 1026 | .streaming => { |
| 1029 | const n = bw.writeFile(file, .init(pos), new_limit, &.{}, 0) catch |err| switch (err) { | 1027 | r.mode = .streaming_reading; |
| 1030 | error.WriteFailed => return error.WriteFailed, | 1028 | return 0; |
| 1031 | error.Unseekable => { | 1029 | }, |
| 1032 | r.mode = .streaming; | 1030 | .positional_reading => { |
| 1033 | if (pos != 0) @panic("TODO need to seek here"); | 1031 | const dest = limit.slice(try bw.writableSliceGreedy(1)); |
| 1034 | return 0; | 1032 | const n = try readPositional(r, dest); |
| 1035 | }, | 1033 | bw.advance(n); |
| 1036 | error.Unimplemented => { | ||
| 1037 | r.mode = .positional_reading; | ||
| 1038 | return 0; | ||
| 1039 | }, | ||
| 1040 | else => |e| { | ||
| 1041 | r.err = e; | ||
| 1042 | return error.ReadFailed; | ||
| 1043 | }, | ||
| 1044 | }; | ||
| 1045 | r.pos = pos + n; | ||
| 1046 | return n; | ||
| 1047 | }, | ||
| 1048 | .streaming => { | ||
| 1049 | const n = bw.writeFile(file, .none, limit, &.{}, 0) catch |err| switch (err) { | ||
| 1050 | error.WriteFailed => return error.WriteFailed, | ||
| 1051 | error.Unseekable => unreachable, // Passing `Offset.none`. | ||
| 1052 | error.Unimplemented => { | ||
| 1053 | r.mode = .streaming_reading; | ||
| 1054 | return 0; | ||
| 1055 | }, | ||
| 1056 | else => |e| { | ||
| 1057 | r.err = e; | ||
| 1058 | return error.ReadFailed; | ||
| 1059 | }, | ||
| 1060 | }; | ||
| 1061 | r.pos = pos + n; | ||
| 1062 | return n; | ||
| 1063 | }, | ||
| 1064 | .positional_reading => { | ||
| 1065 | const dest = limit.slice(try bw.writableSliceGreedy(1)); | ||
| 1066 | const n = file.pread(dest, pos) catch |err| switch (err) { | ||
| 1067 | error.Unseekable => { | ||
| 1068 | r.mode = .streaming_reading; | ||
| 1069 | if (pos != 0) @panic("TODO need to seek here"); | ||
| 1070 | return 0; | ||
| 1071 | }, | ||
| 1072 | else => |e| { | ||
| 1073 | r.err = e; | ||
| 1074 | return error.ReadFailed; | ||
| 1075 | }, | ||
| 1076 | }; | ||
| 1077 | if (n == 0) return error.EndOfStream; | ||
| 1078 | r.pos = pos + n; | ||
| 1079 | bw.advance(n); | ||
| 1080 | return n; | ||
| 1081 | }, | ||
| 1082 | .streaming_reading => { | ||
| 1083 | const dest = limit.slice(try bw.writableSliceGreedy(1)); | ||
| 1084 | const n = file.read(dest) catch |err| { | ||
| 1085 | r.err = err; | ||
| 1086 | return error.ReadFailed; | ||
| 1087 | }; | ||
| 1088 | if (n == 0) return error.EndOfStream; | ||
| 1089 | r.pos = pos + n; | ||
| 1090 | bw.advance(n); | ||
| 1091 | return n; | ||
| 1092 | }, | ||
| 1093 | } | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { | ||
| 1097 | const r: *Reader = @ptrCast(@alignCast(context)); | ||
| 1098 | const handle = r.file.handle; | ||
| 1099 | const pos = r.pos; | ||
| 1100 | |||
| 1101 | switch (r.mode) { | ||
| 1102 | .positional, .positional_reading => { | ||
| 1103 | if (is_windows) { | ||
| 1104 | // Unfortunately, `ReadFileScatter` cannot be used since it requires | ||
| 1105 | // page alignment, so we are stuck using only the first slice. | ||
| 1106 | // Avoid empty slices to prevent false positive end detections. | ||
| 1107 | var i: usize = 0; | ||
| 1108 | while (true) : (i += 1) { | ||
| 1109 | if (i >= data.len) return .{}; | ||
| 1110 | if (data[i].len > 0) break; | ||
| 1111 | } | ||
| 1112 | const n = windows.ReadFile(handle, data[i], pos) catch |err| { | ||
| 1113 | r.err = err; | ||
| 1114 | return error.ReadFailed; | ||
| 1115 | }; | ||
| 1116 | if (n == 0) return error.EndOfFile; | ||
| 1117 | r.pos = pos + n; | ||
| 1118 | return n; | 1034 | return n; |
| 1119 | } | 1035 | }, |
| 1120 | 1036 | .streaming_reading => { | |
| 1121 | var iovecs: [max_buffers_len]std.posix.iovec = undefined; | 1037 | const dest = limit.slice(try bw.writableSliceGreedy(1)); |
| 1122 | var iovecs_i: usize = 0; | 1038 | const n = try readStreaming(r, dest); |
| 1123 | for (data) |d| { | 1039 | bw.advance(n); |
| 1124 | // Since the OS checks pointer address before length, we must omit | ||
| 1125 | // length-zero vectors. | ||
| 1126 | if (d.len == 0) continue; | ||
| 1127 | iovecs[iovecs_i] = .{ .base = d.ptr, .len = d.len }; | ||
| 1128 | iovecs_i += 1; | ||
| 1129 | if (iovecs_i >= iovecs.len) break; | ||
| 1130 | } | ||
| 1131 | const send_vecs = iovecs[0..iovecs_i]; | ||
| 1132 | if (send_vecs.len == 0) return 0; // Prevent false positive end detection on empty `data`. | ||
| 1133 | const n = posix.preadv(handle, send_vecs, pos) catch |err| switch (err) { | ||
| 1134 | error.Unseekable => { | ||
| 1135 | r.mode = r.mode.toStreaming(); | ||
| 1136 | assert(pos == 0); | ||
| 1137 | return 0; | ||
| 1138 | }, | ||
| 1139 | else => |e| { | ||
| 1140 | r.err = e; | ||
| 1141 | return error.ReadFailed; | ||
| 1142 | }, | ||
| 1143 | }; | ||
| 1144 | if (n == 0) return error.EndOfStream; | ||
| 1145 | r.pos = pos + n; | ||
| 1146 | return n; | ||
| 1147 | }, | ||
| 1148 | .streaming, .streaming_reading => { | ||
| 1149 | if (is_windows) { | ||
| 1150 | // Unfortunately, `ReadFileScatter` cannot be used since it requires | ||
| 1151 | // page alignment, so we are stuck using only the first slice. | ||
| 1152 | // Avoid empty slices to prevent false positive end detections. | ||
| 1153 | var i: usize = 0; | ||
| 1154 | while (true) : (i += 1) { | ||
| 1155 | if (i >= data.len) return .{}; | ||
| 1156 | if (data[i].len > 0) break; | ||
| 1157 | } | ||
| 1158 | const n = windows.ReadFile(handle, data[i], null) catch |err| { | ||
| 1159 | r.err = err; | ||
| 1160 | return error.ReadFailed; | ||
| 1161 | }; | ||
| 1162 | if (n == 0) return error.EndOfFile; | ||
| 1163 | r.pos = pos + n; | ||
| 1164 | return n; | 1040 | return n; |
| 1165 | } | 1041 | }, |
| 1166 | 1042 | .failure => return error.ReadFailed, | |
| 1167 | var iovecs: [max_buffers_len]std.posix.iovec = undefined; | ||
| 1168 | var iovecs_i: usize = 0; | ||
| 1169 | for (data) |d| { | ||
| 1170 | // Since the OS checks pointer address before length, we must omit | ||
| 1171 | // length-zero vectors. | ||
| 1172 | if (d.len == 0) continue; | ||
| 1173 | iovecs[iovecs_i] = .{ .base = d.ptr, .len = d.len }; | ||
| 1174 | iovecs_i += 1; | ||
| 1175 | if (iovecs_i >= iovecs.len) break; | ||
| 1176 | } | ||
| 1177 | const send_vecs = iovecs[0..iovecs_i]; | ||
| 1178 | if (send_vecs.len == 0) return 0; // Prevent false positive end detection on empty `data`. | ||
| 1179 | const n = posix.readv(handle, send_vecs) catch |err| { | ||
| 1180 | r.err = err; | ||
| 1181 | return error.ReadFailed; | ||
| 1182 | }; | ||
| 1183 | if (n == 0) return error.EndOfStream; | ||
| 1184 | r.pos = pos + n; | ||
| 1185 | return n; | ||
| 1186 | }, | 1043 | }, |
| 1187 | } | 1044 | }; |
| 1188 | } | 1045 | } |
| 1189 | 1046 | ||
| 1190 | fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { | 1047 | fn discard(context: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { |
| 1191 | const r: *Reader = @ptrCast(@alignCast(context)); | 1048 | const r: *Reader = @ptrCast(@alignCast(context)); |
| 1192 | const file = r.file; | 1049 | const file = r.file; |
| 1193 | const pos = r.pos; | 1050 | const pos = r.pos; |
| ... | @@ -1258,6 +1115,44 @@ pub const Reader = struct { | ... | @@ -1258,6 +1115,44 @@ pub const Reader = struct { |
| 1258 | }, | 1115 | }, |
| 1259 | } | 1116 | } |
| 1260 | } | 1117 | } |
| 1118 | |||
| 1119 | pub fn readPositional(r: *Reader, dest: []u8) std.io.Reader.Error!usize { | ||
| 1120 | const n = r.file.pread(dest, r.pos) catch |err| switch (err) { | ||
| 1121 | error.Unseekable => { | ||
| 1122 | r.mode = r.mode.toStreaming(); | ||
| 1123 | if (r.pos != 0) r.seekBy(r.pos) catch { | ||
| 1124 | r.mode = .failure; | ||
| 1125 | return error.ReadFailed; | ||
| 1126 | }; | ||
| 1127 | return 0; | ||
| 1128 | }, | ||
| 1129 | else => |e| { | ||
| 1130 | r.err = e; | ||
| 1131 | return error.ReadFailed; | ||
| 1132 | }, | ||
| 1133 | }; | ||
| 1134 | if (n == 0) return error.EndOfStream; | ||
| 1135 | r.pos += n; | ||
| 1136 | return n; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | pub fn readStreaming(r: *Reader, dest: []u8) std.io.Reader.Error!usize { | ||
| 1140 | const n = r.file.read(dest) catch |err| { | ||
| 1141 | r.err = err; | ||
| 1142 | return error.ReadFailed; | ||
| 1143 | }; | ||
| 1144 | if (n == 0) return error.EndOfStream; | ||
| 1145 | r.pos += n; | ||
| 1146 | return n; | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | pub fn read(r: *Reader, dest: []u8) std.io.Reader.Error!usize { | ||
| 1150 | switch (r.mode) { | ||
| 1151 | .positional, .positional_reading => return readPositional(r, dest), | ||
| 1152 | .streaming, .streaming_reading => return readStreaming(r, dest), | ||
| 1153 | .failure => return error.ReadFailed, | ||
| 1154 | } | ||
| 1155 | } | ||
| 1261 | }; | 1156 | }; |
| 1262 | 1157 | ||
| 1263 | pub const Writer = struct { | 1158 | pub const Writer = struct { |
| ... | @@ -1266,7 +1161,6 @@ pub const Writer = struct { | ... | @@ -1266,7 +1161,6 @@ pub const Writer = struct { |
| 1266 | mode: Writer.Mode = .positional, | 1161 | mode: Writer.Mode = .positional, |
| 1267 | pos: u64 = 0, | 1162 | pos: u64 = 0, |
| 1268 | sendfile_err: ?SendfileError = null, | 1163 | sendfile_err: ?SendfileError = null, |
| 1269 | read_err: ?ReadError = null, | ||
| 1270 | seek_err: ?SeekError = null, | 1164 | seek_err: ?SeekError = null, |
| 1271 | 1165 | ||
| 1272 | pub const Mode = Reader.Mode; | 1166 | pub const Mode = Reader.Mode; |
| ... | @@ -1359,15 +1253,14 @@ pub const Writer = struct { | ... | @@ -1359,15 +1253,14 @@ pub const Writer = struct { |
| 1359 | 1253 | ||
| 1360 | pub fn writeFile( | 1254 | pub fn writeFile( |
| 1361 | context: ?*anyopaque, | 1255 | context: ?*anyopaque, |
| 1362 | in_file: std.fs.File, | 1256 | file_reader: *Reader, |
| 1363 | in_offset: std.io.Writer.Offset, | 1257 | limit: std.io.Limit, |
| 1364 | in_limit: std.io.Limit, | ||
| 1365 | headers_and_trailers: []const []const u8, | 1258 | headers_and_trailers: []const []const u8, |
| 1366 | headers_len: usize, | 1259 | headers_len: usize, |
| 1367 | ) std.io.Writer.FileError!usize { | 1260 | ) std.io.Writer.FileError!usize { |
| 1368 | const w: *Writer = @ptrCast(@alignCast(context)); | 1261 | const w: *Writer = @ptrCast(@alignCast(context)); |
| 1369 | const out_fd = w.file.handle; | 1262 | const out_fd = w.file.handle; |
| 1370 | const in_fd = in_file.handle; | 1263 | const in_fd = file_reader.file.handle; |
| 1371 | // TODO try using copy_file_range on Linux | 1264 | // TODO try using copy_file_range on Linux |
| 1372 | // TODO try using copy_file_range on FreeBSD | 1265 | // TODO try using copy_file_range on FreeBSD |
| 1373 | // TODO try using sendfile on macOS | 1266 | // TODO try using sendfile on macOS |
| ... | @@ -1379,23 +1272,41 @@ pub const Writer = struct { | ... | @@ -1379,23 +1272,41 @@ pub const Writer = struct { |
| 1379 | // support a streaming read from in_file. | 1272 | // support a streaming read from in_file. |
| 1380 | if (headers_len > 0) return writeSplat(context, headers_and_trailers[0..headers_len], 1); | 1273 | if (headers_len > 0) return writeSplat(context, headers_and_trailers[0..headers_len], 1); |
| 1381 | const max_count = 0x7ffff000; // Avoid EINVAL. | 1274 | const max_count = 0x7ffff000; // Avoid EINVAL. |
| 1382 | const smaller_len = in_limit.minInt(max_count); | ||
| 1383 | var off: std.os.linux.off_t = undefined; | 1275 | var off: std.os.linux.off_t = undefined; |
| 1384 | const off_ptr: ?*std.os.linux.off_t = if (in_offset.toInt()) |offset| b: { | 1276 | const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) { |
| 1385 | off = std.math.cast(std.os.linux.off_t, offset) orelse | 1277 | .positional => o: { |
| 1386 | return writeSplat(context, headers_and_trailers, 1); | 1278 | const size = file_reader.size orelse { |
| 1387 | break :b &off; | 1279 | if (file_reader.file.getEndPos()) |size| { |
| 1388 | } else null; | 1280 | file_reader.size = size; |
| 1389 | const n = std.os.linux.wrapped.sendfile(out_fd, in_fd, off_ptr, smaller_len) catch |err| switch (err) { | 1281 | } else |err| { |
| 1390 | // Errors that imply sendfile should be avoided on the next write. | 1282 | file_reader.size_err = err; |
| 1391 | error.UnsupportedOperation, | 1283 | file_reader.mode = .streaming; |
| 1392 | error.Unexpected, | 1284 | } |
| 1393 | => |e| { | 1285 | return 0; |
| 1286 | }; | ||
| 1287 | off = std.math.cast(std.os.linux.off_t, file_reader.pos) orelse | ||
| 1288 | return writeSplat(context, headers_and_trailers, 1); | ||
| 1289 | break :o .{ &off, @min(@intFromEnum(limit), size - file_reader.pos, max_count) }; | ||
| 1290 | }, | ||
| 1291 | .streaming => .{ null, limit.minInt(max_count) }, | ||
| 1292 | .streaming_reading, .positional_reading => break :sf, | ||
| 1293 | .failure => return error.ReadFailed, | ||
| 1294 | }; | ||
| 1295 | const n = std.os.linux.wrapped.sendfile(out_fd, in_fd, off_ptr, count) catch |err| switch (err) { | ||
| 1296 | error.Unseekable => { | ||
| 1297 | file_reader.mode = file_reader.mode.toStreaming(); | ||
| 1298 | if (file_reader.pos != 0) file_reader.seekBy(@intCast(file_reader.pos)) catch { | ||
| 1299 | file_reader.mode = .failure; | ||
| 1300 | return error.ReadFailed; | ||
| 1301 | }; | ||
| 1302 | return 0; | ||
| 1303 | }, | ||
| 1304 | else => |e| { | ||
| 1394 | w.sendfile_err = e; | 1305 | w.sendfile_err = e; |
| 1395 | break :sf; | 1306 | return 0; |
| 1396 | }, | 1307 | }, |
| 1397 | else => |e| return e, | ||
| 1398 | }; | 1308 | }; |
| 1309 | file_reader.pos += n; | ||
| 1399 | w.pos += n; | 1310 | w.pos += n; |
| 1400 | return n; | 1311 | return n; |
| 1401 | } | 1312 | } |
lib/std/http/Client.zig+1-1| ... | @@ -1631,7 +1631,7 @@ pub const FetchOptions = struct { | ... | @@ -1631,7 +1631,7 @@ pub const FetchOptions = struct { |
| 1631 | list: *std.ArrayListUnmanaged(u8), | 1631 | list: *std.ArrayListUnmanaged(u8), |
| 1632 | /// If null then only the existing capacity will be used. | 1632 | /// If null then only the existing capacity will be used. |
| 1633 | allocator: ?Allocator = null, | 1633 | allocator: ?Allocator = null, |
| 1634 | append_limit: std.io.Reader.Limit = .unlimited, | 1634 | append_limit: std.io.Limit = .unlimited, |
| 1635 | }; | 1635 | }; |
| 1636 | }; | 1636 | }; |
| 1637 | 1637 |
lib/std/io/AllocatingWriter.zig+16-28| ... | @@ -160,13 +160,12 @@ fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std. | ... | @@ -160,13 +160,12 @@ fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std. |
| 160 | 160 | ||
| 161 | fn writeFile( | 161 | fn writeFile( |
| 162 | context: ?*anyopaque, | 162 | context: ?*anyopaque, |
| 163 | file: std.fs.File, | 163 | file_reader: *std.fs.File.Reader, |
| 164 | offset: std.io.Writer.Offset, | ||
| 165 | limit: std.io.Writer.Limit, | 164 | limit: std.io.Writer.Limit, |
| 166 | headers_and_trailers_full: []const []const u8, | 165 | headers_and_trailers_full: []const []const u8, |
| 167 | headers_len_full: usize, | 166 | headers_len_full: usize, |
| 168 | ) std.io.Writer.FileError!usize { | 167 | ) std.io.Writer.FileError!usize { |
| 169 | if (std.fs.File.Handle == void) unreachable; | 168 | if (std.fs.File.Handle == void) return error.Unimplemented; |
| 170 | const aw: *AllocatingWriter = @alignCast(@ptrCast(context)); | 169 | const aw: *AllocatingWriter = @alignCast(@ptrCast(context)); |
| 171 | const gpa = aw.allocator; | 170 | const gpa = aw.allocator; |
| 172 | var list = aw.toArrayList(); | 171 | var list = aw.toArrayList(); |
| ... | @@ -178,35 +177,24 @@ fn writeFile( | ... | @@ -178,35 +177,24 @@ fn writeFile( |
| 178 | break :b .{ headers_and_trailers_full[1..], headers_len_full - 1 }; | 177 | break :b .{ headers_and_trailers_full[1..], headers_len_full - 1 }; |
| 179 | } else .{ headers_and_trailers_full, headers_len_full }; | 178 | } else .{ headers_and_trailers_full, headers_len_full }; |
| 180 | const trailers = headers_and_trailers[headers_len..]; | 179 | const trailers = headers_and_trailers[headers_len..]; |
| 181 | const pos = offset.toInt() orelse @panic("TODO treat file as stream"); | 180 | const pos = file_reader.pos; |
| 182 | const limit_int = limit.toInt() orelse { | 181 | |
| 183 | var new_capacity: usize = list.capacity + std.atomic.cache_line; | 182 | const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line; |
| 184 | for (headers_and_trailers) |bytes| new_capacity += bytes.len; | 183 | var new_capacity: usize = list.capacity + limit.minInt(additional); |
| 185 | list.ensureTotalCapacity(gpa, new_capacity) catch return error.WriteFailed; | ||
| 186 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 187 | const dest = list.items.ptr[list.items.len..list.capacity]; | ||
| 188 | const n = try file.pread(dest, pos); | ||
| 189 | if (n == 0) { | ||
| 190 | new_capacity = list.capacity; | ||
| 191 | for (trailers) |bytes| new_capacity += bytes.len; | ||
| 192 | list.ensureTotalCapacity(gpa, new_capacity) catch return error.WriteFailed; | ||
| 193 | for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 194 | return list.items.len - start_len; | ||
| 195 | } | ||
| 196 | list.items.len += n; | ||
| 197 | return list.items.len - start_len; | ||
| 198 | }; | ||
| 199 | var new_capacity: usize = list.capacity + limit_int; | ||
| 200 | for (headers_and_trailers) |bytes| new_capacity += bytes.len; | 184 | for (headers_and_trailers) |bytes| new_capacity += bytes.len; |
| 201 | list.ensureTotalCapacity(gpa, new_capacity) catch return error.WriteFailed; | 185 | list.ensureTotalCapacity(gpa, new_capacity) catch return error.WriteFailed; |
| 202 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); | 186 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); |
| 203 | const dest = list.items.ptr[list.items.len..][0..limit_int]; | 187 | const dest = limit.slice(list.items.ptr[list.items.len..list.capacity]); |
| 204 | const n = try file.pread(dest, pos); | 188 | const n = try file_reader.read(dest); |
| 205 | list.items.len += n; | 189 | const is_end = if (file_reader.getSize()) |size| n >= size - pos else n == 0; |
| 206 | if (n < dest.len) { | 190 | if (is_end) { |
| 207 | return list.items.len - start_len; | 191 | new_capacity = list.capacity; |
| 192 | for (trailers) |bytes| new_capacity += bytes.len; | ||
| 193 | list.ensureTotalCapacity(gpa, new_capacity) catch return error.WriteFailed; | ||
| 194 | for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 195 | } else { | ||
| 196 | list.items.len += n; | ||
| 208 | } | 197 | } |
| 209 | for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes); | ||
| 210 | return list.items.len - start_len; | 198 | return list.items.len - start_len; |
| 211 | } | 199 | } |
| 212 | 200 |
lib/std/io/Reader.zig+1-1| ... | @@ -128,7 +128,7 @@ pub const LimitedAllocError = Allocator.Error || ShortError || error{StreamTooLo | ... | @@ -128,7 +128,7 @@ pub const LimitedAllocError = Allocator.Error || ShortError || error{StreamTooLo |
| 128 | /// See also: | 128 | /// See also: |
| 129 | /// * `readRemainingArrayList` | 129 | /// * `readRemainingArrayList` |
| 130 | /// * `BufferedReader.readRemainingArrayList` | 130 | /// * `BufferedReader.readRemainingArrayList` |
| 131 | pub fn readRemainingAlloc(r: Reader, gpa: Allocator, limit: Reader.Limit) LimitedAllocError![]u8 { | 131 | pub fn readRemainingAlloc(r: Reader, gpa: Allocator, limit: Limit) LimitedAllocError![]u8 { |
| 132 | var buffer: ArrayList(u8) = .empty; | 132 | var buffer: ArrayList(u8) = .empty; |
| 133 | defer buffer.deinit(gpa); | 133 | defer buffer.deinit(gpa); |
| 134 | try readRemainingArrayList(r, gpa, null, &buffer, limit, 1); | 134 | try readRemainingArrayList(r, gpa, null, &buffer, limit, 1); |
lib/std/io/Reader/Limited.zig+4-3| ... | @@ -3,9 +3,10 @@ const Limited = @This(); | ... | @@ -3,9 +3,10 @@ const Limited = @This(); |
| 3 | const std = @import("../../std.zig"); | 3 | const std = @import("../../std.zig"); |
| 4 | const Reader = std.io.Reader; | 4 | const Reader = std.io.Reader; |
| 5 | const BufferedWriter = std.io.BufferedWriter; | 5 | const BufferedWriter = std.io.BufferedWriter; |
| 6 | const Limit = std.io.Limit; | ||
| 6 | 7 | ||
| 7 | unlimited_reader: Reader, | 8 | unlimited_reader: Reader, |
| 8 | remaining: Reader.Limit, | 9 | remaining: Limit, |
| 9 | 10 | ||
| 10 | pub fn reader(l: *Limited) Reader { | 11 | pub fn reader(l: *Limited) Reader { |
| 11 | return .{ | 12 | return .{ |
| ... | @@ -18,7 +19,7 @@ pub fn reader(l: *Limited) Reader { | ... | @@ -18,7 +19,7 @@ pub fn reader(l: *Limited) Reader { |
| 18 | }; | 19 | }; |
| 19 | } | 20 | } |
| 20 | 21 | ||
| 21 | fn passthruRead(context: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) Reader.RwError!usize { | 22 | fn passthruRead(context: ?*anyopaque, bw: *BufferedWriter, limit: Limit) Reader.RwError!usize { |
| 22 | const l: *Limited = @alignCast(@ptrCast(context)); | 23 | const l: *Limited = @alignCast(@ptrCast(context)); |
| 23 | const combined_limit = limit.min(l.remaining); | 24 | const combined_limit = limit.min(l.remaining); |
| 24 | const n = try l.unlimited_reader.read(bw, combined_limit); | 25 | const n = try l.unlimited_reader.read(bw, combined_limit); |
| ... | @@ -26,7 +27,7 @@ fn passthruRead(context: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) | ... | @@ -26,7 +27,7 @@ fn passthruRead(context: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) |
| 26 | return n; | 27 | return n; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | fn passthruDiscard(context: ?*anyopaque, limit: Reader.Limit) Reader.Error!usize { | 30 | fn passthruDiscard(context: ?*anyopaque, limit: Limit) Reader.Error!usize { |
| 30 | const l: *Limited = @alignCast(@ptrCast(context)); | 31 | const l: *Limited = @alignCast(@ptrCast(context)); |
| 31 | const combined_limit = limit.min(l.remaining); | 32 | const combined_limit = limit.min(l.remaining); |
| 32 | const n = try l.unlimited_reader.discard(combined_limit); | 33 | const n = try l.unlimited_reader.discard(combined_limit); |
lib/std/net.zig+2-2| ... | @@ -1916,7 +1916,7 @@ pub const Stream = struct { | ... | @@ -1916,7 +1916,7 @@ pub const Stream = struct { |
| 1916 | fn read( | 1916 | fn read( |
| 1917 | context: ?*anyopaque, | 1917 | context: ?*anyopaque, |
| 1918 | bw: *std.io.BufferedWriter, | 1918 | bw: *std.io.BufferedWriter, |
| 1919 | limit: std.io.Reader.Limit, | 1919 | limit: std.io.Limit, |
| 1920 | ) std.io.Reader.Error!usize { | 1920 | ) std.io.Reader.Error!usize { |
| 1921 | const buf = limit.slice(try bw.writableSliceGreedy(1)); | 1921 | const buf = limit.slice(try bw.writableSliceGreedy(1)); |
| 1922 | const n = try readVec(context, &.{buf}); | 1922 | const n = try readVec(context, &.{buf}); |
| ... | @@ -1958,7 +1958,7 @@ pub const Stream = struct { | ... | @@ -1958,7 +1958,7 @@ pub const Stream = struct { |
| 1958 | return .{ .len = n, .end = n == 0 }; | 1958 | return .{ .len = n, .end = n == 0 }; |
| 1959 | } | 1959 | } |
| 1960 | 1960 | ||
| 1961 | fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { | 1961 | fn discard(context: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { |
| 1962 | _ = context; | 1962 | _ = context; |
| 1963 | _ = limit; | 1963 | _ = limit; |
| 1964 | @panic("TODO"); | 1964 | @panic("TODO"); |
lib/std/tar.zig+2-2| ... | @@ -358,7 +358,7 @@ pub const Iterator = struct { | ... | @@ -358,7 +358,7 @@ pub const Iterator = struct { |
| 358 | }; | 358 | }; |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | fn read(context: ?*anyopaque, bw: *std.io.BufferedWriter, limit: std.io.Reader.Limit) std.io.Reader.RwError!usize { | 361 | fn read(context: ?*anyopaque, bw: *std.io.BufferedWriter, limit: std.io.Limit) std.io.Reader.RwError!usize { |
| 362 | const file: *File = @ptrCast(@alignCast(context)); | 362 | const file: *File = @ptrCast(@alignCast(context)); |
| 363 | if (file.unread_bytes.* == 0) return error.EndOfStream; | 363 | if (file.unread_bytes.* == 0) return error.EndOfStream; |
| 364 | const n = try file.parent_reader.read(bw, limit.min(.limited(file.unread_bytes.*))); | 364 | const n = try file.parent_reader.read(bw, limit.min(.limited(file.unread_bytes.*))); |
| ... | @@ -374,7 +374,7 @@ pub const Iterator = struct { | ... | @@ -374,7 +374,7 @@ pub const Iterator = struct { |
| 374 | return n; | 374 | return n; |
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { | 377 | fn discard(context: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { |
| 378 | const file: *File = @ptrCast(@alignCast(context)); | 378 | const file: *File = @ptrCast(@alignCast(context)); |
| 379 | const n = limit.minInt(file.unread_bytes.*); | 379 | const n = limit.minInt(file.unread_bytes.*); |
| 380 | file.unread_bytes.* -= n; | 380 | file.unread_bytes.* -= n; |
lib/std/zip.zig+2-22| ... | @@ -175,11 +175,7 @@ pub const Decompress = union { | ... | @@ -175,11 +175,7 @@ pub const Decompress = union { |
| 175 | return .{ | 175 | return .{ |
| 176 | .unbuffered_reader = .{ | 176 | .unbuffered_reader = .{ |
| 177 | .context = d, | 177 | .context = d, |
| 178 | .vtable = &.{ | 178 | .vtable = &.{ .read = readStore }, |
| 179 | .read = readStore, | ||
| 180 | .readVec = readVecUnimplemented, | ||
| 181 | .discard = discardUnimplemented, | ||
| 182 | }, | ||
| 183 | }, | 179 | }, |
| 184 | .buffer = buffer, | 180 | .buffer = buffer, |
| 185 | .end = 0, | 181 | .end = 0, |
| ... | @@ -191,11 +187,7 @@ pub const Decompress = union { | ... | @@ -191,11 +187,7 @@ pub const Decompress = union { |
| 191 | return .{ | 187 | return .{ |
| 192 | .unbuffered_reader = .{ | 188 | .unbuffered_reader = .{ |
| 193 | .context = d, | 189 | .context = d, |
| 194 | .vtable = &.{ | 190 | .vtable = &.{ .read = readDeflate }, |
| 195 | .read = readDeflate, | ||
| 196 | .readVec = readVecUnimplemented, | ||
| 197 | .discard = discardUnimplemented, | ||
| 198 | }, | ||
| 199 | }, | 191 | }, |
| 200 | .buffer = buffer, | 192 | .buffer = buffer, |
| 201 | .end = 0, | 193 | .end = 0, |
| ... | @@ -223,18 +215,6 @@ pub const Decompress = union { | ... | @@ -223,18 +215,6 @@ pub const Decompress = union { |
| 223 | const d: *Decompress = @ptrCast(@alignCast(context)); | 215 | const d: *Decompress = @ptrCast(@alignCast(context)); |
| 224 | return std.compress.flate.Decompress.read(&d.inflate, writer, limit); | 216 | return std.compress.flate.Decompress.read(&d.inflate, writer, limit); |
| 225 | } | 217 | } |
| 226 | |||
| 227 | fn readVecUnimplemented(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { | ||
| 228 | _ = context; | ||
| 229 | _ = data; | ||
| 230 | @panic("TODO remove readVec primitive"); | ||
| 231 | } | ||
| 232 | |||
| 233 | fn discardUnimplemented(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { | ||
| 234 | _ = context; | ||
| 235 | _ = limit; | ||
| 236 | @panic("TODO allow discard to be null"); | ||
| 237 | } | ||
| 238 | }; | 218 | }; |
| 239 | 219 | ||
| 240 | fn isBadFilename(filename: []const u8) bool { | 220 | fn isBadFilename(filename: []const u8) bool { |