| author | |
| committer | |
| log | cf7a28febbbe877003d8d4f9a13ceb94698c1e3e |
| tree | 73f0874da561173692d69cccd25cc83de308f809 |
| parent | a9773944dc2b930facd66350dcbe87178aacf487 |
simplifies and fixes things
addresses a subset of #246085 files changed, 313 insertions(+), 292 deletions(-)
lib/std/Io/Reader.zig+205-142| ... | ... | @@ -43,8 +43,8 @@ pub const VTable = struct { |
| 43 | 43 | /// |
| 44 | 44 | /// In addition to, or instead of writing to `w`, the implementation may |
| 45 | 45 | /// choose to store data in `buffer`, modifying `seek` and `end` |
| 46 | /// accordingly. Stream implementations are encouraged to take advantage of | |
| 47 | /// this if simplifies the logic. | |
| 46 | /// accordingly. Implementations are encouraged to take advantage of | |
| 47 | /// this if it simplifies the logic. | |
| 48 | 48 | stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize, |
| 49 | 49 | |
| 50 | 50 | /// Consumes bytes from the internally tracked stream position without |
| ... | ... | @@ -68,6 +68,21 @@ pub const VTable = struct { |
| 68 | 68 | /// This function is only called when `buffer` is empty. |
| 69 | 69 | discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard, |
| 70 | 70 | |
| 71 | /// Returns number of bytes written to `data`. | |
| 72 | /// | |
| 73 | /// `data` may not have nonzero length. | |
| 74 | /// | |
| 75 | /// `data` may not contain an alias to `Reader.buffer`. | |
| 76 | /// | |
| 77 | /// Implementations may ignore `data`, writing directly to `Reader.buffer`, | |
| 78 | /// modifying `seek` and `end` accordingly, and returning 0 from this | |
| 79 | /// function. Implementations are encouraged to take advantage of this if | |
| 80 | /// it simplifies the logic. | |
| 81 | /// | |
| 82 | /// The default implementation calls `stream` with either `data[0]` or | |
| 83 | /// `Reader.buffer`, whichever is bigger. | |
| 84 | readVec: *const fn (r: *Reader, data: []const []u8) Error!usize = defaultReadVec, | |
| 85 | ||
| 71 | 86 | /// Ensures `capacity` more data can be buffered without rebasing. |
| 72 | 87 | /// |
| 73 | 88 | /// Asserts `capacity` is within buffer capacity, or that the stream ends |
| ... | ... | @@ -138,6 +153,7 @@ pub fn fixed(buffer: []const u8) Reader { |
| 138 | 153 | .vtable = &.{ |
| 139 | 154 | .stream = endingStream, |
| 140 | 155 | .discard = endingDiscard, |
| 156 | .readVec = endingReadVec, | |
| 141 | 157 | .rebase = endingRebase, |
| 142 | 158 | }, |
| 143 | 159 | // This cast is safe because all potential writes to it will instead |
| ... | ... | @@ -170,18 +186,18 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize { |
| 170 | 186 | } |
| 171 | 187 | break :l .limited(n - buffered_len); |
| 172 | 188 | } else .unlimited; |
| 173 | r.seek = 0; | |
| 174 | r.end = 0; | |
| 189 | r.seek = r.end; | |
| 175 | 190 | const n = try r.vtable.discard(r, remaining); |
| 176 | 191 | assert(n <= @intFromEnum(remaining)); |
| 177 | 192 | return buffered_len + n; |
| 178 | 193 | } |
| 179 | 194 | |
| 180 | 195 | pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize { |
| 181 | assert(r.seek == 0); | |
| 182 | assert(r.end == 0); | |
| 183 | var dw: Writer.Discarding = .init(r.buffer); | |
| 184 | const n = r.stream(&dw.writer, limit) catch |err| switch (err) { | |
| 196 | assert(r.seek == r.end); | |
| 197 | r.seek = 0; | |
| 198 | r.end = 0; | |
| 199 | var d: Writer.Discarding = .init(r.buffer); | |
| 200 | const n = r.stream(&d.writer, limit) catch |err| switch (err) { | |
| 185 | 201 | error.WriteFailed => unreachable, |
| 186 | 202 | error.ReadFailed => return error.ReadFailed, |
| 187 | 203 | error.EndOfStream => return error.EndOfStream, |
| ... | ... | @@ -294,7 +310,8 @@ pub fn appendRemaining( |
| 294 | 310 | list: *std.ArrayListAlignedUnmanaged(u8, alignment), |
| 295 | 311 | limit: Limit, |
| 296 | 312 | ) LimitedAllocError!void { |
| 297 | if (limit != .unlimited) assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data. | |
| 313 | if (limit == .unlimited) return appendRemainingUnlimited(r, gpa, alignment, list, 1); | |
| 314 | assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data. | |
| 298 | 315 | const buffer_contents = r.buffer[r.seek..r.end]; |
| 299 | 316 | const copy_len = limit.minInt(buffer_contents.len); |
| 300 | 317 | try list.appendSlice(gpa, r.buffer[0..copy_len]); |
| ... | ... | @@ -303,32 +320,67 @@ pub fn appendRemaining( |
| 303 | 320 | r.seek = 0; |
| 304 | 321 | r.end = 0; |
| 305 | 322 | var remaining = @intFromEnum(limit) - copy_len; |
| 323 | // From here, we leave `buffer` empty, appending directly to `list`. | |
| 324 | var writer: Writer = .{ | |
| 325 | .buffer = undefined, | |
| 326 | .end = undefined, | |
| 327 | .vtable = &.{ .drain = Writer.fixedDrain }, | |
| 328 | }; | |
| 306 | 329 | while (true) { |
| 307 | try list.ensureUnusedCapacity(gpa, 1); | |
| 330 | try list.ensureUnusedCapacity(gpa, 2); | |
| 308 | 331 | const cap = list.unusedCapacitySlice(); |
| 309 | const dest = cap[0..@min(cap.len, remaining)]; | |
| 310 | if (remaining - dest.len == 0) { | |
| 311 | // Additionally provides `buffer` to detect end. | |
| 312 | const new_remaining = readVecInner(r, &.{}, dest, remaining) catch |err| switch (err) { | |
| 313 | error.EndOfStream => { | |
| 314 | if (r.bufferedLen() != 0) return error.StreamTooLong; | |
| 315 | return; | |
| 316 | }, | |
| 317 | error.ReadFailed => return error.ReadFailed, | |
| 318 | }; | |
| 319 | list.items.len += remaining - new_remaining; | |
| 320 | remaining = new_remaining; | |
| 321 | } else { | |
| 322 | // Leave `buffer` empty, appending directly to `list`. | |
| 323 | var dest_w: Writer = .fixed(dest); | |
| 324 | const n = r.vtable.stream(r, &dest_w, .limited(dest.len)) catch |err| switch (err) { | |
| 325 | error.WriteFailed => unreachable, // Prevented by the limit. | |
| 326 | error.EndOfStream => return, | |
| 327 | error.ReadFailed => return error.ReadFailed, | |
| 328 | }; | |
| 329 | list.items.len += n; | |
| 330 | remaining -= n; | |
| 332 | const dest = cap[0..@min(cap.len, remaining + 1)]; | |
| 333 | writer.buffer = list.allocatedSlice(); | |
| 334 | writer.end = list.items.len; | |
| 335 | const n = r.vtable.stream(r, &writer, .limited(dest.len)) catch |err| switch (err) { | |
| 336 | error.WriteFailed => unreachable, // Prevented by the limit. | |
| 337 | error.EndOfStream => return, | |
| 338 | error.ReadFailed => return error.ReadFailed, | |
| 339 | }; | |
| 340 | list.items.len += n; | |
| 341 | if (n > remaining) { | |
| 342 | // Move the byte to `Reader.buffer` so it is not lost. | |
| 343 | assert(n - remaining == 1); | |
| 344 | assert(r.end == 0); | |
| 345 | r.buffer[0] = list.items[list.items.len - 1]; | |
| 346 | list.items.len -= 1; | |
| 347 | r.end = 1; | |
| 348 | return; | |
| 331 | 349 | } |
| 350 | remaining -= n; | |
| 351 | } | |
| 352 | } | |
| 353 | ||
| 354 | pub const UnlimitedAllocError = Allocator.Error || ShortError; | |
| 355 | ||
| 356 | pub fn appendRemainingUnlimited( | |
| 357 | r: *Reader, | |
| 358 | gpa: Allocator, | |
| 359 | comptime alignment: ?std.mem.Alignment, | |
| 360 | list: *std.ArrayListAlignedUnmanaged(u8, alignment), | |
| 361 | bump: usize, | |
| 362 | ) UnlimitedAllocError!void { | |
| 363 | const buffer_contents = r.buffer[r.seek..r.end]; | |
| 364 | try list.ensureUnusedCapacity(gpa, buffer_contents.len + bump); | |
| 365 | list.appendSliceAssumeCapacity(buffer_contents); | |
| 366 | r.seek = 0; | |
| 367 | r.end = 0; | |
| 368 | // From here, we leave `buffer` empty, appending directly to `list`. | |
| 369 | var writer: Writer = .{ | |
| 370 | .buffer = undefined, | |
| 371 | .end = undefined, | |
| 372 | .vtable = &.{ .drain = Writer.fixedDrain }, | |
| 373 | }; | |
| 374 | while (true) { | |
| 375 | try list.ensureUnusedCapacity(gpa, bump); | |
| 376 | writer.buffer = list.allocatedSlice(); | |
| 377 | writer.end = list.items.len; | |
| 378 | const n = r.vtable.stream(r, &writer, .limited(list.unusedCapacitySlice().len)) catch |err| switch (err) { | |
| 379 | error.WriteFailed => unreachable, // Prevented by the limit. | |
| 380 | error.EndOfStream => return, | |
| 381 | error.ReadFailed => return error.ReadFailed, | |
| 382 | }; | |
| 383 | list.items.len += n; | |
| 332 | 384 | } |
| 333 | 385 | } |
| 334 | 386 | |
| ... | ... | @@ -340,95 +392,64 @@ pub fn appendRemaining( |
| 340 | 392 | /// |
| 341 | 393 | /// The reader's internal logical seek position moves forward in accordance |
| 342 | 394 | /// with the number of bytes returned from this function. |
| 343 | pub fn readVec(r: *Reader, data: []const []u8) Error!usize { | |
| 344 | return readVecLimit(r, data, .unlimited); | |
| 345 | } | |
| 346 | ||
| 347 | /// Equivalent to `readVec` but reads at most `limit` bytes. | |
| 348 | /// | |
| 349 | /// This ultimately will lower to a call to `stream`, but it must ensure | |
| 350 | /// that the buffer used has at least as much capacity, in case that function | |
| 351 | /// depends on a minimum buffer capacity. It also ensures that if the `stream` | |
| 352 | /// implementation calls `Writer.writableVector`, it will get this data slice | |
| 353 | /// along with the buffer at the end. | |
| 354 | pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize { | |
| 355 | comptime assert(@intFromEnum(Limit.unlimited) == std.math.maxInt(usize)); | |
| 356 | var remaining = @intFromEnum(limit); | |
| 395 | pub fn readVec(r: *Reader, data: [][]u8) Error!usize { | |
| 396 | var seek = r.seek; | |
| 357 | 397 | for (data, 0..) |buf, i| { |
| 358 | const buffer_contents = r.buffer[r.seek..r.end]; | |
| 359 | const copy_len = @min(buffer_contents.len, buf.len, remaining); | |
| 360 | @memcpy(buf[0..copy_len], buffer_contents[0..copy_len]); | |
| 361 | r.seek += copy_len; | |
| 362 | remaining -= copy_len; | |
| 363 | if (remaining == 0) break; | |
| 398 | const contents = r.buffer[seek..r.end]; | |
| 399 | const copy_len = @min(contents.len, buf.len); | |
| 400 | @memcpy(buf[0..copy_len], contents[0..copy_len]); | |
| 401 | seek += copy_len; | |
| 364 | 402 | if (buf.len - copy_len == 0) continue; |
| 365 | 403 | |
| 366 | // All of `buffer` has been copied to `data`. We now set up a structure | |
| 367 | // that enables the `Writer.writableVector` API, while also ensuring | |
| 368 | // API that directly operates on the `Writable.buffer` has its minimum | |
| 369 | // buffer capacity requirements met. | |
| 370 | r.seek = 0; | |
| 371 | r.end = 0; | |
| 372 | remaining = try readVecInner(r, data[i + 1 ..], buf[copy_len..], remaining); | |
| 373 | break; | |
| 404 | // All of `buffer` has been copied to `data`. | |
| 405 | const n = seek - r.seek; | |
| 406 | r.seek = seek; | |
| 407 | data[i] = buf[copy_len..]; | |
| 408 | defer data[i] = buf; | |
| 409 | return n + try r.vtable.readVec(r, data[i..]); | |
| 374 | 410 | } |
| 375 | return @intFromEnum(limit) - remaining; | |
| 411 | const n = seek - r.seek; | |
| 412 | r.seek = seek; | |
| 413 | return n; | |
| 376 | 414 | } |
| 377 | 415 | |
| 378 | fn readVecInner(r: *Reader, middle: []const []u8, first: []u8, remaining: usize) Error!usize { | |
| 379 | var wrapper: Writer.VectorWrapper = .{ | |
| 380 | .it = .{ | |
| 381 | .first = first, | |
| 382 | .middle = middle, | |
| 383 | .last = r.buffer, | |
| 384 | }, | |
| 385 | .writer = .{ | |
| 386 | .buffer = if (first.len >= r.buffer.len) first else r.buffer, | |
| 387 | .vtable = Writer.VectorWrapper.vtable, | |
| 388 | }, | |
| 416 | /// Writes to `Reader.buffer` or `data`, whichever has larger capacity. | |
| 417 | pub fn defaultReadVec(r: *Reader, data: []const []u8) Error!usize { | |
| 418 | assert(r.seek == r.end); | |
| 419 | r.seek = 0; | |
| 420 | r.end = 0; | |
| 421 | const first = data[0]; | |
| 422 | const direct = first.len >= r.buffer.len; | |
| 423 | var writer: Writer = .{ | |
| 424 | .buffer = if (direct) first else r.buffer, | |
| 425 | .end = 0, | |
| 426 | .vtable = &.{ .drain = Writer.fixedDrain }, | |
| 389 | 427 | }; |
| 390 | // If the limit may pass beyond user buffer into Reader buffer, use | |
| 391 | // unlimited, allowing the Reader buffer to fill. | |
| 392 | const limit: Limit = l: { | |
| 393 | var n: usize = first.len; | |
| 394 | for (middle) |m| n += m.len; | |
| 395 | break :l if (remaining >= n) .unlimited else .limited(remaining); | |
| 428 | const limit: Limit = .limited(writer.buffer.len - writer.end); | |
| 429 | const n = r.vtable.stream(r, &writer, limit) catch |err| switch (err) { | |
| 430 | error.WriteFailed => unreachable, | |
| 431 | else => |e| return e, | |
| 396 | 432 | }; |
| 397 | var n = r.vtable.stream(r, &wrapper.writer, limit) catch |err| switch (err) { | |
| 398 | error.WriteFailed => { | |
| 399 | assert(!wrapper.used); | |
| 400 | if (wrapper.writer.buffer.ptr == first.ptr) { | |
| 401 | return remaining - wrapper.writer.end; | |
| 402 | } else { | |
| 403 | assert(wrapper.writer.end <= r.buffer.len); | |
| 404 | r.end = wrapper.writer.end; | |
| 405 | return remaining; | |
| 406 | } | |
| 407 | }, | |
| 433 | if (direct) return n; | |
| 434 | r.end += n; | |
| 435 | return 0; | |
| 436 | } | |
| 437 | ||
| 438 | /// Always writes to `Reader.buffer` and returns 0. | |
| 439 | pub fn indirectReadVec(r: *Reader, data: []const []u8) Error!usize { | |
| 440 | _ = data; | |
| 441 | assert(r.seek == r.end); | |
| 442 | var writer: Writer = .{ | |
| 443 | .buffer = r.buffer, | |
| 444 | .end = r.end, | |
| 445 | .vtable = &.{ .drain = Writer.fixedDrain }, | |
| 446 | }; | |
| 447 | const limit: Limit = .limited(writer.buffer.len - writer.end); | |
| 448 | r.end += r.vtable.stream(r, &writer, limit) catch |err| switch (err) { | |
| 449 | error.WriteFailed => unreachable, | |
| 408 | 450 | else => |e| return e, |
| 409 | 451 | }; |
| 410 | if (!wrapper.used) { | |
| 411 | if (wrapper.writer.buffer.ptr == first.ptr) { | |
| 412 | return remaining - n; | |
| 413 | } else { | |
| 414 | assert(n <= r.buffer.len); | |
| 415 | r.end = n; | |
| 416 | return remaining; | |
| 417 | } | |
| 418 | } | |
| 419 | if (n < first.len) return remaining - n; | |
| 420 | var result = remaining - first.len; | |
| 421 | n -= first.len; | |
| 422 | for (middle) |mid| { | |
| 423 | if (n < mid.len) { | |
| 424 | return result - n; | |
| 425 | } | |
| 426 | result -= mid.len; | |
| 427 | n -= mid.len; | |
| 428 | } | |
| 429 | assert(n <= r.buffer.len); | |
| 430 | r.end = n; | |
| 431 | return result; | |
| 452 | return 0; | |
| 432 | 453 | } |
| 433 | 454 | |
| 434 | 455 | pub fn buffered(r: *Reader) []u8 { |
| ... | ... | @@ -642,29 +663,24 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void { |
| 642 | 663 | /// See also: |
| 643 | 664 | /// * `readSliceAll` |
| 644 | 665 | pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize { |
| 645 | var i: usize = 0; | |
| 666 | const contents = r.buffer[r.seek..r.end]; | |
| 667 | const copy_len = @min(buffer.len, contents.len); | |
| 668 | @memcpy(buffer[0..copy_len], contents[0..copy_len]); | |
| 669 | r.seek += copy_len; | |
| 670 | if (buffer.len - copy_len == 0) { | |
| 671 | @branchHint(.likely); | |
| 672 | return buffer.len; | |
| 673 | } | |
| 674 | var i: usize = copy_len; | |
| 675 | var data: [1][]u8 = undefined; | |
| 646 | 676 | while (true) { |
| 647 | const buffer_contents = r.buffer[r.seek..r.end]; | |
| 648 | const dest = buffer[i..]; | |
| 649 | const copy_len = @min(dest.len, buffer_contents.len); | |
| 650 | @memcpy(dest[0..copy_len], buffer_contents[0..copy_len]); | |
| 651 | if (dest.len - copy_len == 0) { | |
| 652 | @branchHint(.likely); | |
| 653 | r.seek += copy_len; | |
| 654 | return buffer.len; | |
| 655 | } | |
| 656 | i += copy_len; | |
| 657 | r.end = 0; | |
| 658 | r.seek = 0; | |
| 659 | const remaining = buffer[i..]; | |
| 660 | const new_remaining_len = readVecInner(r, &.{}, remaining, remaining.len) catch |err| switch (err) { | |
| 677 | data[0] = buffer[i..]; | |
| 678 | i += readVec(r, &data) catch |err| switch (err) { | |
| 661 | 679 | error.EndOfStream => return i, |
| 662 | 680 | error.ReadFailed => return error.ReadFailed, |
| 663 | 681 | }; |
| 664 | if (new_remaining_len == 0) return buffer.len; | |
| 665 | i += remaining.len - new_remaining_len; | |
| 682 | if (buffer.len - i == 0) return buffer.len; | |
| 666 | 683 | } |
| 667 | return buffer.len; | |
| 668 | 684 | } |
| 669 | 685 | |
| 670 | 686 | /// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing |
| ... | ... | @@ -1632,19 +1648,6 @@ test readVec { |
| 1632 | 1648 | try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]); |
| 1633 | 1649 | } |
| 1634 | 1650 | |
| 1635 | test readVecLimit { | |
| 1636 | var r: Reader = .fixed(std.ascii.letters); | |
| 1637 | var flat_buffer: [52]u8 = undefined; | |
| 1638 | var bufs: [2][]u8 = .{ | |
| 1639 | flat_buffer[0..26], | |
| 1640 | flat_buffer[26..], | |
| 1641 | }; | |
| 1642 | // Short reads are possible with this function but not with fixed. | |
| 1643 | try testing.expectEqual(50, try r.readVecLimit(&bufs, .limited(50))); | |
| 1644 | try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]); | |
| 1645 | try testing.expectEqualStrings(std.ascii.letters[26..50], bufs[1][0..24]); | |
| 1646 | } | |
| 1647 | ||
| 1648 | 1651 | test "expected error.EndOfStream" { |
| 1649 | 1652 | // Unit test inspired by https://github.com/ziglang/zig/issues/17733 |
| 1650 | 1653 | var buffer: [3]u8 = undefined; |
| ... | ... | @@ -1661,6 +1664,12 @@ fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { |
| 1661 | 1664 | return error.EndOfStream; |
| 1662 | 1665 | } |
| 1663 | 1666 | |
| 1667 | fn endingReadVec(r: *Reader, data: []const []u8) Error!usize { | |
| 1668 | _ = r; | |
| 1669 | _ = data; | |
| 1670 | return error.EndOfStream; | |
| 1671 | } | |
| 1672 | ||
| 1664 | 1673 | fn endingDiscard(r: *Reader, limit: Limit) Error!usize { |
| 1665 | 1674 | _ = r; |
| 1666 | 1675 | _ = limit; |
| ... | ... | @@ -1797,3 +1806,57 @@ pub fn Hashed(comptime Hasher: type) type { |
| 1797 | 1806 | } |
| 1798 | 1807 | }; |
| 1799 | 1808 | } |
| 1809 | ||
| 1810 | pub fn writableVectorPosix(r: *Reader, buffer: []std.posix.iovec, data: []const []u8) Error!struct { usize, usize } { | |
| 1811 | var i: usize = 0; | |
| 1812 | var n: usize = 0; | |
| 1813 | for (data) |buf| { | |
| 1814 | if (buffer.len - i == 0) return .{ i, n }; | |
| 1815 | if (buf.len != 0) { | |
| 1816 | buffer[i] = .{ .base = buf.ptr, .len = buf.len }; | |
| 1817 | i += 1; | |
| 1818 | n += buf.len; | |
| 1819 | } | |
| 1820 | } | |
| 1821 | assert(r.seek == r.end); | |
| 1822 | const buf = r.buffer; | |
| 1823 | if (buf.len != 0) { | |
| 1824 | buffer[i] = .{ .base = buf.ptr, .len = buf.len }; | |
| 1825 | i += 1; | |
| 1826 | } | |
| 1827 | return .{ i, n }; | |
| 1828 | } | |
| 1829 | ||
| 1830 | pub fn writableVectorWsa( | |
| 1831 | r: *Reader, | |
| 1832 | buffer: []std.os.windows.ws2_32.WSABUF, | |
| 1833 | data: []const []u8, | |
| 1834 | ) Error!struct { usize, usize } { | |
| 1835 | var i: usize = 0; | |
| 1836 | var n: usize = 0; | |
| 1837 | for (data) |buf| { | |
| 1838 | if (buffer.len - i == 0) return .{ i, n }; | |
| 1839 | if (buf.len == 0) continue; | |
| 1840 | if (std.math.cast(u32, buf.len)) |len| { | |
| 1841 | buffer[i] = .{ .buf = buf.ptr, .len = len }; | |
| 1842 | i += 1; | |
| 1843 | n += len; | |
| 1844 | continue; | |
| 1845 | } | |
| 1846 | buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) }; | |
| 1847 | i += 1; | |
| 1848 | n += std.math.maxInt(u32); | |
| 1849 | return .{ i, n }; | |
| 1850 | } | |
| 1851 | assert(r.seek == r.end); | |
| 1852 | const buf = r.buffer; | |
| 1853 | if (buf.len != 0) { | |
| 1854 | if (std.math.cast(u32, buf.len)) |len| { | |
| 1855 | buffer[i] = .{ .buf = buf.ptr, .len = len }; | |
| 1856 | } else { | |
| 1857 | buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) }; | |
| 1858 | } | |
| 1859 | i += 1; | |
| 1860 | } | |
| 1861 | return .{ i, n }; | |
| 1862 | } |
lib/std/Io/Writer.zig-98| ... | ... | @@ -342,97 +342,6 @@ pub fn writableSlicePreserve(w: *Writer, preserve_len: usize, len: usize) Error! |
| 342 | 342 | return big_slice[0..len]; |
| 343 | 343 | } |
| 344 | 344 | |
| 345 | pub const WritableVectorIterator = struct { | |
| 346 | first: []u8, | |
| 347 | middle: []const []u8 = &.{}, | |
| 348 | last: []u8 = &.{}, | |
| 349 | index: usize = 0, | |
| 350 | ||
| 351 | pub fn next(it: *WritableVectorIterator) ?[]u8 { | |
| 352 | while (true) { | |
| 353 | const i = it.index; | |
| 354 | it.index += 1; | |
| 355 | if (i == 0) { | |
| 356 | if (it.first.len == 0) continue; | |
| 357 | return it.first; | |
| 358 | } | |
| 359 | const middle_index = i - 1; | |
| 360 | if (middle_index < it.middle.len) { | |
| 361 | const middle = it.middle[middle_index]; | |
| 362 | if (middle.len == 0) continue; | |
| 363 | return middle; | |
| 364 | } | |
| 365 | if (middle_index == it.middle.len) { | |
| 366 | if (it.last.len == 0) continue; | |
| 367 | return it.last; | |
| 368 | } | |
| 369 | return null; | |
| 370 | } | |
| 371 | } | |
| 372 | }; | |
| 373 | ||
| 374 | pub const VectorWrapper = struct { | |
| 375 | writer: Writer, | |
| 376 | it: WritableVectorIterator, | |
| 377 | /// Tracks whether the "writable vector" API was used. | |
| 378 | used: bool = false, | |
| 379 | pub const vtable: *const VTable = &unique_vtable_allocation; | |
| 380 | /// This is intended to be constant but it must be a unique address for | |
| 381 | /// `@fieldParentPtr` to work. | |
| 382 | var unique_vtable_allocation: VTable = .{ .drain = fixedDrain }; | |
| 383 | }; | |
| 384 | ||
| 385 | pub fn writableVectorIterator(w: *Writer) Error!WritableVectorIterator { | |
| 386 | if (w.vtable == VectorWrapper.vtable) { | |
| 387 | const wrapper: *VectorWrapper = @fieldParentPtr("writer", w); | |
| 388 | wrapper.used = true; | |
| 389 | return wrapper.it; | |
| 390 | } | |
| 391 | return .{ .first = try writableSliceGreedy(w, 1) }; | |
| 392 | } | |
| 393 | ||
| 394 | pub fn writableVectorPosix(w: *Writer, buffer: []std.posix.iovec, limit: Limit) Error![]std.posix.iovec { | |
| 395 | var it = try writableVectorIterator(w); | |
| 396 | var i: usize = 0; | |
| 397 | var remaining = limit; | |
| 398 | while (it.next()) |full_buffer| { | |
| 399 | if (!remaining.nonzero()) break; | |
| 400 | if (buffer.len - i == 0) break; | |
| 401 | const buf = remaining.slice(full_buffer); | |
| 402 | if (buf.len == 0) continue; | |
| 403 | buffer[i] = .{ .base = buf.ptr, .len = buf.len }; | |
| 404 | i += 1; | |
| 405 | remaining = remaining.subtract(buf.len).?; | |
| 406 | } | |
| 407 | return buffer[0..i]; | |
| 408 | } | |
| 409 | ||
| 410 | pub fn writableVectorWsa( | |
| 411 | w: *Writer, | |
| 412 | buffer: []std.os.windows.ws2_32.WSABUF, | |
| 413 | limit: Limit, | |
| 414 | ) Error![]std.os.windows.ws2_32.WSABUF { | |
| 415 | var it = try writableVectorIterator(w); | |
| 416 | var i: usize = 0; | |
| 417 | var remaining = limit; | |
| 418 | while (it.next()) |full_buffer| { | |
| 419 | if (!remaining.nonzero()) break; | |
| 420 | if (buffer.len - i == 0) break; | |
| 421 | const buf = remaining.slice(full_buffer); | |
| 422 | if (buf.len == 0) continue; | |
| 423 | if (std.math.cast(u32, buf.len)) |len| { | |
| 424 | buffer[i] = .{ .buf = buf.ptr, .len = len }; | |
| 425 | i += 1; | |
| 426 | remaining = remaining.subtract(len).?; | |
| 427 | continue; | |
| 428 | } | |
| 429 | buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) }; | |
| 430 | i += 1; | |
| 431 | break; | |
| 432 | } | |
| 433 | return buffer[0..i]; | |
| 434 | } | |
| 435 | ||
| 436 | 345 | pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void { |
| 437 | 346 | _ = try writableSliceGreedy(w, n); |
| 438 | 347 | } |
| ... | ... | @@ -451,13 +360,6 @@ pub fn advance(w: *Writer, n: usize) void { |
| 451 | 360 | w.end = new_end; |
| 452 | 361 | } |
| 453 | 362 | |
| 454 | /// After calling `writableVector`, this function tracks how many bytes were | |
| 455 | /// written to it. | |
| 456 | pub fn advanceVector(w: *Writer, n: usize) usize { | |
| 457 | if (w.vtable != VectorWrapper.vtable) advance(w, n); | |
| 458 | return n; | |
| 459 | } | |
| 460 | ||
| 461 | 363 | /// The `data` parameter is mutable because this function needs to mutate the |
| 462 | 364 | /// fields in order to handle partial writes from `VTable.writeSplat`. |
| 463 | 365 | pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void { |
lib/std/compress/zstd/Decompress.zig+17-3| ... | ... | @@ -88,6 +88,8 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress { |
| 88 | 88 | .vtable = &.{ |
| 89 | 89 | .stream = stream, |
| 90 | 90 | .rebase = rebase, |
| 91 | .discard = discard, | |
| 92 | .readVec = Reader.indirectReadVec, | |
| 91 | 93 | }, |
| 92 | 94 | .buffer = buffer, |
| 93 | 95 | .seek = 0, |
| ... | ... | @@ -100,11 +102,23 @@ fn rebase(r: *Reader, capacity: usize) Reader.RebaseError!void { |
| 100 | 102 | const d: *Decompress = @alignCast(@fieldParentPtr("reader", r)); |
| 101 | 103 | assert(capacity <= r.buffer.len - d.window_len); |
| 102 | 104 | assert(r.end + capacity > r.buffer.len); |
| 103 | const discard = r.end - d.window_len; | |
| 104 | const keep = r.buffer[discard..r.end]; | |
| 105 | const discard_n = r.end - d.window_len; | |
| 106 | const keep = r.buffer[discard_n..r.end]; | |
| 105 | 107 | @memmove(r.buffer[0..keep.len], keep); |
| 106 | 108 | r.end = keep.len; |
| 107 | r.seek -= discard; | |
| 109 | r.seek -= discard_n; | |
| 110 | } | |
| 111 | ||
| 112 | fn discard(r: *Reader, limit: Limit) Reader.Error!usize { | |
| 113 | r.rebase(zstd.block_size_max) catch unreachable; | |
| 114 | var d: Writer.Discarding = .init(r.buffer); | |
| 115 | const n = r.stream(&d.writer, limit) catch |err| switch (err) { | |
| 116 | error.WriteFailed => unreachable, | |
| 117 | error.ReadFailed => return error.ReadFailed, | |
| 118 | error.EndOfStream => return error.EndOfStream, | |
| 119 | }; | |
| 120 | assert(n <= @intFromEnum(limit)); | |
| 121 | return n; | |
| 108 | 122 | } |
| 109 | 123 | |
| 110 | 124 | fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { |
lib/std/fs/File.zig+57-31| ... | ... | @@ -1129,7 +1129,7 @@ pub fn seekableStream(file: File) SeekableStream { |
| 1129 | 1129 | /// * Whether reading should be done via fd-to-fd syscalls (e.g. `sendfile`) |
| 1130 | 1130 | /// versus plain variants (e.g. `read`). |
| 1131 | 1131 | /// |
| 1132 | /// Fulfills the `std.io.Reader` interface. | |
| 1132 | /// Fulfills the `std.Io.Reader` interface. | |
| 1133 | 1133 | pub const Reader = struct { |
| 1134 | 1134 | file: File, |
| 1135 | 1135 | err: ?ReadError = null, |
| ... | ... | @@ -1140,7 +1140,7 @@ pub const Reader = struct { |
| 1140 | 1140 | size: ?u64 = null, |
| 1141 | 1141 | size_err: ?GetEndPosError = null, |
| 1142 | 1142 | seek_err: ?Reader.SeekError = null, |
| 1143 | interface: std.io.Reader, | |
| 1143 | interface: std.Io.Reader, | |
| 1144 | 1144 | |
| 1145 | 1145 | pub const SeekError = File.SeekError || error{ |
| 1146 | 1146 | /// Seeking fell back to reading, and reached the end before the requested seek position. |
| ... | ... | @@ -1177,11 +1177,12 @@ pub const Reader = struct { |
| 1177 | 1177 | } |
| 1178 | 1178 | }; |
| 1179 | 1179 | |
| 1180 | pub fn initInterface(buffer: []u8) std.io.Reader { | |
| 1180 | pub fn initInterface(buffer: []u8) std.Io.Reader { | |
| 1181 | 1181 | return .{ |
| 1182 | 1182 | .vtable = &.{ |
| 1183 | 1183 | .stream = Reader.stream, |
| 1184 | 1184 | .discard = Reader.discard, |
| 1185 | .readVec = Reader.readVec, | |
| 1185 | 1186 | }, |
| 1186 | 1187 | .buffer = buffer, |
| 1187 | 1188 | .seek = 0, |
| ... | ... | @@ -1294,7 +1295,7 @@ pub const Reader = struct { |
| 1294 | 1295 | /// vectors through the underlying read calls as possible. |
| 1295 | 1296 | const max_buffers_len = 16; |
| 1296 | 1297 | |
| 1297 | fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { | |
| 1298 | fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { | |
| 1298 | 1299 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader)); |
| 1299 | 1300 | switch (r.mode) { |
| 1300 | 1301 | .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) { |
| ... | ... | @@ -1305,16 +1306,33 @@ pub const Reader = struct { |
| 1305 | 1306 | else => |e| return e, |
| 1306 | 1307 | }, |
| 1307 | 1308 | .positional_reading => { |
| 1309 | const dest = limit.slice(try w.writableSliceGreedy(1)); | |
| 1310 | const n = try readPositional(r, dest); | |
| 1311 | w.advance(n); | |
| 1312 | return n; | |
| 1313 | }, | |
| 1314 | .streaming_reading => { | |
| 1315 | const dest = limit.slice(try w.writableSliceGreedy(1)); | |
| 1316 | const n = try readStreaming(r, dest); | |
| 1317 | w.advance(n); | |
| 1318 | return n; | |
| 1319 | }, | |
| 1320 | .failure => return error.ReadFailed, | |
| 1321 | } | |
| 1322 | } | |
| 1323 | ||
| 1324 | fn readVec(io_reader: *std.Io.Reader, data: []const []u8) std.Io.Reader.Error!usize { | |
| 1325 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader)); | |
| 1326 | switch (r.mode) { | |
| 1327 | .positional, .positional_reading => { | |
| 1308 | 1328 | if (is_windows) { |
| 1309 | 1329 | // Unfortunately, `ReadFileScatter` cannot be used since it |
| 1310 | 1330 | // requires page alignment. |
| 1311 | const dest = limit.slice(try w.writableSliceGreedy(1)); | |
| 1312 | const n = try readPositional(r, dest); | |
| 1313 | w.advance(n); | |
| 1314 | return n; | |
| 1331 | return readPositional(r, data[0]); | |
| 1315 | 1332 | } |
| 1316 | 1333 | var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; |
| 1317 | const dest = try w.writableVectorPosix(&iovecs_buffer, limit); | |
| 1334 | const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data); | |
| 1335 | const dest = iovecs_buffer[0..dest_n]; | |
| 1318 | 1336 | assert(dest[0].len > 0); |
| 1319 | 1337 | const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) { |
| 1320 | 1338 | error.Unseekable => { |
| ... | ... | @@ -1339,19 +1357,22 @@ pub const Reader = struct { |
| 1339 | 1357 | return error.EndOfStream; |
| 1340 | 1358 | } |
| 1341 | 1359 | r.pos += n; |
| 1342 | return w.advanceVector(n); | |
| 1360 | if (n > data_size) { | |
| 1361 | io_reader.seek = 0; | |
| 1362 | io_reader.end = n - data_size; | |
| 1363 | return data_size; | |
| 1364 | } | |
| 1365 | return n; | |
| 1343 | 1366 | }, |
| 1344 | .streaming_reading => { | |
| 1367 | .streaming, .streaming_reading => { | |
| 1345 | 1368 | if (is_windows) { |
| 1346 | 1369 | // Unfortunately, `ReadFileScatter` cannot be used since it |
| 1347 | 1370 | // requires page alignment. |
| 1348 | const dest = limit.slice(try w.writableSliceGreedy(1)); | |
| 1349 | const n = try readStreaming(r, dest); | |
| 1350 | w.advance(n); | |
| 1351 | return n; | |
| 1371 | return readStreaming(r, data[0]); | |
| 1352 | 1372 | } |
| 1353 | 1373 | var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; |
| 1354 | const dest = try w.writableVectorPosix(&iovecs_buffer, limit); | |
| 1374 | const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data); | |
| 1375 | const dest = iovecs_buffer[0..dest_n]; | |
| 1355 | 1376 | assert(dest[0].len > 0); |
| 1356 | 1377 | const n = posix.readv(r.file.handle, dest) catch |err| { |
| 1357 | 1378 | r.err = err; |
| ... | ... | @@ -1362,13 +1383,18 @@ pub const Reader = struct { |
| 1362 | 1383 | return error.EndOfStream; |
| 1363 | 1384 | } |
| 1364 | 1385 | r.pos += n; |
| 1365 | return w.advanceVector(n); | |
| 1386 | if (n > data_size) { | |
| 1387 | io_reader.seek = 0; | |
| 1388 | io_reader.end = n - data_size; | |
| 1389 | return data_size; | |
| 1390 | } | |
| 1391 | return n; | |
| 1366 | 1392 | }, |
| 1367 | 1393 | .failure => return error.ReadFailed, |
| 1368 | 1394 | } |
| 1369 | 1395 | } |
| 1370 | 1396 | |
| 1371 | fn discard(io_reader: *std.io.Reader, limit: std.io.Limit) std.io.Reader.Error!usize { | |
| 1397 | fn discard(io_reader: *std.Io.Reader, limit: std.Io.Limit) std.Io.Reader.Error!usize { | |
| 1372 | 1398 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader)); |
| 1373 | 1399 | const file = r.file; |
| 1374 | 1400 | const pos = r.pos; |
| ... | ... | @@ -1447,7 +1473,7 @@ pub const Reader = struct { |
| 1447 | 1473 | } |
| 1448 | 1474 | } |
| 1449 | 1475 | |
| 1450 | pub fn readPositional(r: *Reader, dest: []u8) std.io.Reader.Error!usize { | |
| 1476 | pub fn readPositional(r: *Reader, dest: []u8) std.Io.Reader.Error!usize { | |
| 1451 | 1477 | const n = r.file.pread(dest, r.pos) catch |err| switch (err) { |
| 1452 | 1478 | error.Unseekable => { |
| 1453 | 1479 | r.mode = r.mode.toStreaming(); |
| ... | ... | @@ -1474,7 +1500,7 @@ pub const Reader = struct { |
| 1474 | 1500 | return n; |
| 1475 | 1501 | } |
| 1476 | 1502 | |
| 1477 | pub fn readStreaming(r: *Reader, dest: []u8) std.io.Reader.Error!usize { | |
| 1503 | pub fn readStreaming(r: *Reader, dest: []u8) std.Io.Reader.Error!usize { | |
| 1478 | 1504 | const n = r.file.read(dest) catch |err| { |
| 1479 | 1505 | r.err = err; |
| 1480 | 1506 | return error.ReadFailed; |
| ... | ... | @@ -1487,7 +1513,7 @@ pub const Reader = struct { |
| 1487 | 1513 | return n; |
| 1488 | 1514 | } |
| 1489 | 1515 | |
| 1490 | pub fn read(r: *Reader, dest: []u8) std.io.Reader.Error!usize { | |
| 1516 | pub fn read(r: *Reader, dest: []u8) std.Io.Reader.Error!usize { | |
| 1491 | 1517 | switch (r.mode) { |
| 1492 | 1518 | .positional, .positional_reading => return readPositional(r, dest), |
| 1493 | 1519 | .streaming, .streaming_reading => return readStreaming(r, dest), |
| ... | ... | @@ -1513,7 +1539,7 @@ pub const Writer = struct { |
| 1513 | 1539 | copy_file_range_err: ?CopyFileRangeError = null, |
| 1514 | 1540 | fcopyfile_err: ?FcopyfileError = null, |
| 1515 | 1541 | seek_err: ?SeekError = null, |
| 1516 | interface: std.io.Writer, | |
| 1542 | interface: std.Io.Writer, | |
| 1517 | 1543 | |
| 1518 | 1544 | pub const Mode = Reader.Mode; |
| 1519 | 1545 | |
| ... | ... | @@ -1550,13 +1576,13 @@ pub const Writer = struct { |
| 1550 | 1576 | }; |
| 1551 | 1577 | } |
| 1552 | 1578 | |
| 1553 | pub fn initInterface(buffer: []u8) std.io.Writer { | |
| 1579 | pub fn initInterface(buffer: []u8) std.Io.Writer { | |
| 1554 | 1580 | return .{ |
| 1555 | 1581 | .vtable = &.{ |
| 1556 | 1582 | .drain = drain, |
| 1557 | 1583 | .sendFile = switch (builtin.zig_backend) { |
| 1558 | 1584 | else => sendFile, |
| 1559 | .stage2_aarch64 => std.io.Writer.unimplementedSendFile, | |
| 1585 | .stage2_aarch64 => std.Io.Writer.unimplementedSendFile, | |
| 1560 | 1586 | }, |
| 1561 | 1587 | }, |
| 1562 | 1588 | .buffer = buffer, |
| ... | ... | @@ -1574,7 +1600,7 @@ pub const Writer = struct { |
| 1574 | 1600 | }; |
| 1575 | 1601 | } |
| 1576 | 1602 | |
| 1577 | pub fn drain(io_w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { | |
| 1603 | pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { | |
| 1578 | 1604 | const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); |
| 1579 | 1605 | const handle = w.file.handle; |
| 1580 | 1606 | const buffered = io_w.buffered(); |
| ... | ... | @@ -1724,10 +1750,10 @@ pub const Writer = struct { |
| 1724 | 1750 | } |
| 1725 | 1751 | |
| 1726 | 1752 | pub fn sendFile( |
| 1727 | io_w: *std.io.Writer, | |
| 1753 | io_w: *std.Io.Writer, | |
| 1728 | 1754 | file_reader: *Reader, |
| 1729 | limit: std.io.Limit, | |
| 1730 | ) std.io.Writer.FileError!usize { | |
| 1755 | limit: std.Io.Limit, | |
| 1756 | ) std.Io.Writer.FileError!usize { | |
| 1731 | 1757 | const reader_buffered = file_reader.interface.buffered(); |
| 1732 | 1758 | if (reader_buffered.len >= @intFromEnum(limit)) |
| 1733 | 1759 | return sendFileBuffered(io_w, file_reader, reader_buffered); |
| ... | ... | @@ -1989,10 +2015,10 @@ pub const Writer = struct { |
| 1989 | 2015 | } |
| 1990 | 2016 | |
| 1991 | 2017 | fn sendFileBuffered( |
| 1992 | io_w: *std.io.Writer, | |
| 2018 | io_w: *std.Io.Writer, | |
| 1993 | 2019 | file_reader: *Reader, |
| 1994 | 2020 | reader_buffered: []const u8, |
| 1995 | ) std.io.Writer.FileError!usize { | |
| 2021 | ) std.Io.Writer.FileError!usize { | |
| 1996 | 2022 | const n = try drain(io_w, &.{reader_buffered}, 1); |
| 1997 | 2023 | file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed; |
| 1998 | 2024 | return n; |
| ... | ... | @@ -2015,7 +2041,7 @@ pub const Writer = struct { |
| 2015 | 2041 | } |
| 2016 | 2042 | } |
| 2017 | 2043 | |
| 2018 | pub const EndError = SetEndPosError || std.io.Writer.Error; | |
| 2044 | pub const EndError = SetEndPosError || std.Io.Writer.Error; | |
| 2019 | 2045 | |
| 2020 | 2046 | /// Flushes any buffered data and sets the end position of the file. |
| 2021 | 2047 | /// |
lib/std/net.zig+34-18| ... | ... | @@ -7,7 +7,7 @@ const net = @This(); |
| 7 | 7 | const mem = std.mem; |
| 8 | 8 | const posix = std.posix; |
| 9 | 9 | const fs = std.fs; |
| 10 | const io = std.io; | |
| 10 | const Io = std.Io; | |
| 11 | 11 | const native_endian = builtin.target.cpu.arch.endian(); |
| 12 | 12 | const native_os = builtin.os.tag; |
| 13 | 13 | const windows = std.os.windows; |
| ... | ... | @@ -165,7 +165,7 @@ pub const Address = extern union { |
| 165 | 165 | } |
| 166 | 166 | } |
| 167 | 167 | |
| 168 | pub fn format(self: Address, w: *std.io.Writer) std.io.Writer.Error!void { | |
| 168 | pub fn format(self: Address, w: *Io.Writer) Io.Writer.Error!void { | |
| 169 | 169 | switch (self.any.family) { |
| 170 | 170 | posix.AF.INET => try self.in.format(w), |
| 171 | 171 | posix.AF.INET6 => try self.in6.format(w), |
| ... | ... | @@ -342,7 +342,7 @@ pub const Ip4Address = extern struct { |
| 342 | 342 | self.sa.port = mem.nativeToBig(u16, port); |
| 343 | 343 | } |
| 344 | 344 | |
| 345 | pub fn format(self: Ip4Address, w: *std.io.Writer) std.io.Writer.Error!void { | |
| 345 | pub fn format(self: Ip4Address, w: *Io.Writer) Io.Writer.Error!void { | |
| 346 | 346 | const bytes: *const [4]u8 = @ptrCast(&self.sa.addr); |
| 347 | 347 | try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], self.getPort() }); |
| 348 | 348 | } |
| ... | ... | @@ -633,7 +633,7 @@ pub const Ip6Address = extern struct { |
| 633 | 633 | self.sa.port = mem.nativeToBig(u16, port); |
| 634 | 634 | } |
| 635 | 635 | |
| 636 | pub fn format(self: Ip6Address, w: *std.io.Writer) std.io.Writer.Error!void { | |
| 636 | pub fn format(self: Ip6Address, w: *Io.Writer) Io.Writer.Error!void { | |
| 637 | 637 | const port = mem.bigToNative(u16, self.sa.port); |
| 638 | 638 | if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) { |
| 639 | 639 | try w.print("[::ffff:{d}.{d}.{d}.{d}]:{d}", .{ |
| ... | ... | @@ -1348,7 +1348,7 @@ fn parseHosts( |
| 1348 | 1348 | name: []const u8, |
| 1349 | 1349 | family: posix.sa_family_t, |
| 1350 | 1350 | port: u16, |
| 1351 | br: *io.Reader, | |
| 1351 | br: *Io.Reader, | |
| 1352 | 1352 | ) error{ OutOfMemory, ReadFailed }!void { |
| 1353 | 1353 | while (true) { |
| 1354 | 1354 | const line = br.takeDelimiterExclusive('\n') catch |err| switch (err) { |
| ... | ... | @@ -1402,7 +1402,7 @@ test parseHosts { |
| 1402 | 1402 | // TODO parsing addresses should not have OS dependencies |
| 1403 | 1403 | return error.SkipZigTest; |
| 1404 | 1404 | } |
| 1405 | var reader: std.io.Reader = .fixed( | |
| 1405 | var reader: Io.Reader = .fixed( | |
| 1406 | 1406 | \\127.0.0.1 localhost |
| 1407 | 1407 | \\::1 localhost |
| 1408 | 1408 | \\127.0.0.2 abcd |
| ... | ... | @@ -1583,7 +1583,7 @@ const ResolvConf = struct { |
| 1583 | 1583 | const Directive = enum { options, nameserver, domain, search }; |
| 1584 | 1584 | const Option = enum { ndots, attempts, timeout }; |
| 1585 | 1585 | |
| 1586 | fn parse(rc: *ResolvConf, reader: *io.Reader) !void { | |
| 1586 | fn parse(rc: *ResolvConf, reader: *Io.Reader) !void { | |
| 1587 | 1587 | const gpa = rc.gpa; |
| 1588 | 1588 | while (reader.takeSentinel('\n')) |line_with_comment| { |
| 1589 | 1589 | const line = line: { |
| ... | ... | @@ -1894,7 +1894,7 @@ pub const Stream = struct { |
| 1894 | 1894 | pub const Reader = switch (native_os) { |
| 1895 | 1895 | .windows => struct { |
| 1896 | 1896 | /// Use `interface` for portable code. |
| 1897 | interface_state: io.Reader, | |
| 1897 | interface_state: Io.Reader, | |
| 1898 | 1898 | /// Use `getStream` for portable code. |
| 1899 | 1899 | net_stream: Stream, |
| 1900 | 1900 | /// Use `getError` for portable code. |
| ... | ... | @@ -1910,14 +1910,17 @@ pub const Stream = struct { |
| 1910 | 1910 | return r.error_state; |
| 1911 | 1911 | } |
| 1912 | 1912 | |
| 1913 | pub fn interface(r: *Reader) *io.Reader { | |
| 1913 | pub fn interface(r: *Reader) *Io.Reader { | |
| 1914 | 1914 | return &r.interface_state; |
| 1915 | 1915 | } |
| 1916 | 1916 | |
| 1917 | 1917 | pub fn init(net_stream: Stream, buffer: []u8) Reader { |
| 1918 | 1918 | return .{ |
| 1919 | 1919 | .interface_state = .{ |
| 1920 | .vtable = &.{ .stream = stream }, | |
| 1920 | .vtable = &.{ | |
| 1921 | .stream = stream, | |
| 1922 | .readVec = readVec, | |
| 1923 | }, | |
| 1921 | 1924 | .buffer = buffer, |
| 1922 | 1925 | .seek = 0, |
| 1923 | 1926 | .end = 0, |
| ... | ... | @@ -1927,16 +1930,29 @@ pub const Stream = struct { |
| 1927 | 1930 | }; |
| 1928 | 1931 | } |
| 1929 | 1932 | |
| 1930 | fn stream(io_r: *io.Reader, io_w: *io.Writer, limit: io.Limit) io.Reader.StreamError!usize { | |
| 1933 | fn stream(io_r: *Io.Reader, io_w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize { | |
| 1934 | const dest = limit.slice(try io_w.writableSliceGreedy(1)); | |
| 1935 | const n = try readVec(io_r, &.{dest}); | |
| 1936 | io_w.advance(n); | |
| 1937 | return n; | |
| 1938 | } | |
| 1939 | ||
| 1940 | fn readVec(io_r: *std.Io.Reader, data: []const []u8) Io.Reader.Error!usize { | |
| 1931 | 1941 | const r: *Reader = @alignCast(@fieldParentPtr("interface_state", io_r)); |
| 1932 | 1942 | var iovecs: [max_buffers_len]windows.ws2_32.WSABUF = undefined; |
| 1933 | const bufs = try io_w.writableVectorWsa(&iovecs, limit); | |
| 1943 | const bufs_n, const data_size = try io_r.writableVectorWsa(&iovecs, data); | |
| 1944 | const bufs = iovecs[0..bufs_n]; | |
| 1934 | 1945 | assert(bufs[0].len != 0); |
| 1935 | 1946 | const n = streamBufs(r, bufs) catch |err| { |
| 1936 | 1947 | r.error_state = err; |
| 1937 | 1948 | return error.ReadFailed; |
| 1938 | 1949 | }; |
| 1939 | 1950 | if (n == 0) return error.EndOfStream; |
| 1951 | if (n > data_size) { | |
| 1952 | io_r.seek = 0; | |
| 1953 | io_r.end = n - data_size; | |
| 1954 | return data_size; | |
| 1955 | } | |
| 1940 | 1956 | return n; |
| 1941 | 1957 | } |
| 1942 | 1958 | |
| ... | ... | @@ -1968,7 +1984,7 @@ pub const Stream = struct { |
| 1968 | 1984 | |
| 1969 | 1985 | pub const Error = ReadError; |
| 1970 | 1986 | |
| 1971 | pub fn interface(r: *Reader) *io.Reader { | |
| 1987 | pub fn interface(r: *Reader) *Io.Reader { | |
| 1972 | 1988 | return &r.file_reader.interface; |
| 1973 | 1989 | } |
| 1974 | 1990 | |
| ... | ... | @@ -1996,7 +2012,7 @@ pub const Stream = struct { |
| 1996 | 2012 | pub const Writer = switch (native_os) { |
| 1997 | 2013 | .windows => struct { |
| 1998 | 2014 | /// This field is present on all systems. |
| 1999 | interface: io.Writer, | |
| 2015 | interface: Io.Writer, | |
| 2000 | 2016 | /// Use `getStream` for cross-platform support. |
| 2001 | 2017 | stream: Stream, |
| 2002 | 2018 | /// This field is present on all systems. |
| ... | ... | @@ -2034,7 +2050,7 @@ pub const Stream = struct { |
| 2034 | 2050 | } |
| 2035 | 2051 | } |
| 2036 | 2052 | |
| 2037 | fn drain(io_w: *io.Writer, data: []const []const u8, splat: usize) io.Writer.Error!usize { | |
| 2053 | fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize { | |
| 2038 | 2054 | const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); |
| 2039 | 2055 | const buffered = io_w.buffered(); |
| 2040 | 2056 | comptime assert(native_os == .windows); |
| ... | ... | @@ -2106,7 +2122,7 @@ pub const Stream = struct { |
| 2106 | 2122 | }, |
| 2107 | 2123 | else => struct { |
| 2108 | 2124 | /// This field is present on all systems. |
| 2109 | interface: io.Writer, | |
| 2125 | interface: Io.Writer, | |
| 2110 | 2126 | |
| 2111 | 2127 | err: ?Error = null, |
| 2112 | 2128 | file_writer: File.Writer, |
| ... | ... | @@ -2138,7 +2154,7 @@ pub const Stream = struct { |
| 2138 | 2154 | i.* += 1; |
| 2139 | 2155 | } |
| 2140 | 2156 | |
| 2141 | fn drain(io_w: *io.Writer, data: []const []const u8, splat: usize) io.Writer.Error!usize { | |
| 2157 | fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize { | |
| 2142 | 2158 | const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); |
| 2143 | 2159 | const buffered = io_w.buffered(); |
| 2144 | 2160 | var iovecs: [max_buffers_len]posix.iovec_const = undefined; |
| ... | ... | @@ -2190,7 +2206,7 @@ pub const Stream = struct { |
| 2190 | 2206 | }); |
| 2191 | 2207 | } |
| 2192 | 2208 | |
| 2193 | fn sendFile(io_w: *io.Writer, file_reader: *File.Reader, limit: io.Limit) io.Writer.FileError!usize { | |
| 2209 | fn sendFile(io_w: *Io.Writer, file_reader: *File.Reader, limit: Io.Limit) Io.Writer.FileError!usize { | |
| 2194 | 2210 | const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); |
| 2195 | 2211 | const n = try w.file_writer.interface.sendFileHeader(io_w.buffered(), file_reader, limit); |
| 2196 | 2212 | return io_w.consume(n); |