| ... | @@ -70,13 +70,14 @@ pub const VTable = struct { | ... | @@ -70,13 +70,14 @@ pub const VTable = struct { |
| 70 | | 70 | |
| 71 | /// Returns number of bytes written to `data`. | 71 | /// Returns number of bytes written to `data`. |
| 72 | /// | 72 | /// |
| 73 | /// `data` may not have nonzero length. | 73 | /// `data` must have nonzero length. `data[0]` may have zero length, in |
| | 74 | /// which case the implementation must write to `Reader.buffer`. |
| 74 | /// | 75 | /// |
| 75 | /// `data` may not contain an alias to `Reader.buffer`. | 76 | /// `data` may not contain an alias to `Reader.buffer`. |
| 76 | /// | 77 | /// |
| 77 | /// `data` is mutable because the implementation may to temporarily modify | 78 | /// `data` is mutable because the implementation may temporarily modify the |
| 78 | /// the fields in order to handle partial reads. Implementations must | 79 | /// fields in order to handle partial reads. Implementations must restore |
| 79 | /// restore the original value before returning. | 80 | /// the original value before returning. |
| 80 | /// | 81 | /// |
| 81 | /// Implementations may ignore `data`, writing directly to `Reader.buffer`, | 82 | /// Implementations may ignore `data`, writing directly to `Reader.buffer`, |
| 82 | /// modifying `seek` and `end` accordingly, and returning 0 from this | 83 | /// modifying `seek` and `end` accordingly, and returning 0 from this |
| ... | @@ -421,23 +422,29 @@ pub fn readVec(r: *Reader, data: [][]u8) Error!usize { | ... | @@ -421,23 +422,29 @@ pub fn readVec(r: *Reader, data: [][]u8) Error!usize { |
| 421 | | 422 | |
| 422 | /// Writes to `Reader.buffer` or `data`, whichever has larger capacity. | 423 | /// Writes to `Reader.buffer` or `data`, whichever has larger capacity. |
| 423 | pub fn defaultReadVec(r: *Reader, data: [][]u8) Error!usize { | 424 | pub fn defaultReadVec(r: *Reader, data: [][]u8) Error!usize { |
| 424 | assert(r.seek == r.end); | | |
| 425 | r.seek = 0; | | |
| 426 | r.end = 0; | | |
| 427 | const first = data[0]; | 425 | const first = data[0]; |
| 428 | const direct = first.len >= r.buffer.len; | 426 | if (r.seek == r.end and first.len >= r.buffer.len) { |
| | 427 | var writer: Writer = .{ |
| | 428 | .buffer = first, |
| | 429 | .end = 0, |
| | 430 | .vtable = &.{ .drain = Writer.fixedDrain }, |
| | 431 | }; |
| | 432 | const limit: Limit = .limited(writer.buffer.len - writer.end); |
| | 433 | return r.vtable.stream(r, &writer, limit) catch |err| switch (err) { |
| | 434 | error.WriteFailed => unreachable, |
| | 435 | else => |e| return e, |
| | 436 | }; |
| | 437 | } |
| 429 | var writer: Writer = .{ | 438 | var writer: Writer = .{ |
| 430 | .buffer = if (direct) first else r.buffer, | 439 | .buffer = r.buffer, |
| 431 | .end = 0, | 440 | .end = r.end, |
| 432 | .vtable = &.{ .drain = Writer.fixedDrain }, | 441 | .vtable = &.{ .drain = Writer.fixedDrain }, |
| 433 | }; | 442 | }; |
| 434 | const limit: Limit = .limited(writer.buffer.len - writer.end); | 443 | const limit: Limit = .limited(writer.buffer.len - writer.end); |
| 435 | const n = r.vtable.stream(r, &writer, limit) catch |err| switch (err) { | 444 | r.end += r.vtable.stream(r, &writer, limit) catch |err| switch (err) { |
| 436 | error.WriteFailed => unreachable, | 445 | error.WriteFailed => unreachable, |
| 437 | else => |e| return e, | 446 | else => |e| return e, |
| 438 | }; | 447 | }; |
| 439 | if (direct) return n; | | |
| 440 | r.end += n; | | |
| 441 | return 0; | 448 | return 0; |
| 442 | } | 449 | } |
| 443 | | 450 | |
| ... | @@ -1059,17 +1066,8 @@ pub fn fill(r: *Reader, n: usize) Error!void { | ... | @@ -1059,17 +1066,8 @@ pub fn fill(r: *Reader, n: usize) Error!void { |
| 1059 | /// increasing by a factor of 5 or more. | 1066 | /// increasing by a factor of 5 or more. |
| 1060 | fn fillUnbuffered(r: *Reader, n: usize) Error!void { | 1067 | fn fillUnbuffered(r: *Reader, n: usize) Error!void { |
| 1061 | try rebase(r, n); | 1068 | try rebase(r, n); |
| 1062 | var writer: Writer = .{ | 1069 | var bufs: [1][]u8 = .{""}; |
| 1063 | .buffer = r.buffer, | 1070 | while (r.end < r.seek + n) _ = try r.vtable.readVec(r, &bufs); |
| 1064 | .vtable = &.{ .drain = Writer.fixedDrain }, | | |
| 1065 | }; | | |
| 1066 | while (r.end < r.seek + n) { | | |
| 1067 | writer.end = r.end; | | |
| 1068 | r.end += r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) { | | |
| 1069 | error.WriteFailed => unreachable, | | |
| 1070 | error.ReadFailed, error.EndOfStream => |e| return e, | | |
| 1071 | }; | | |
| 1072 | } | | |
| 1073 | } | 1071 | } |
| 1074 | | 1072 | |
| 1075 | /// Without advancing the seek position, does exactly one underlying read, filling the buffer as | 1073 | /// Without advancing the seek position, does exactly one underlying read, filling the buffer as |
| ... | @@ -1079,15 +1077,8 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { | ... | @@ -1079,15 +1077,8 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { |
| 1079 | /// Asserts buffer capacity is at least 1. | 1077 | /// Asserts buffer capacity is at least 1. |
| 1080 | pub fn fillMore(r: *Reader) Error!void { | 1078 | pub fn fillMore(r: *Reader) Error!void { |
| 1081 | try rebase(r, 1); | 1079 | try rebase(r, 1); |
| 1082 | var writer: Writer = .{ | 1080 | var bufs: [1][]u8 = .{""}; |
| 1083 | .buffer = r.buffer, | 1081 | _ = try r.vtable.readVec(r, &bufs); |
| 1084 | .end = r.end, | | |
| 1085 | .vtable = &.{ .drain = Writer.fixedDrain }, | | |
| 1086 | }; | | |
| 1087 | r.end += r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) { | | |
| 1088 | error.WriteFailed => unreachable, | | |
| 1089 | else => |e| return e, | | |
| 1090 | }; | | |
| 1091 | } | 1082 | } |
| 1092 | | 1083 | |
| 1093 | /// Returns the next byte from the stream or returns `error.EndOfStream`. | 1084 | /// Returns the next byte from the stream or returns `error.EndOfStream`. |
| ... | @@ -1796,18 +1787,26 @@ pub fn Hashed(comptime Hasher: type) type { | ... | @@ -1796,18 +1787,26 @@ pub fn Hashed(comptime Hasher: type) type { |
| 1796 | | 1787 | |
| 1797 | fn readVec(r: *Reader, data: [][]u8) Error!usize { | 1788 | fn readVec(r: *Reader, data: [][]u8) Error!usize { |
| 1798 | const this: *@This() = @alignCast(@fieldParentPtr("reader", r)); | 1789 | const this: *@This() = @alignCast(@fieldParentPtr("reader", r)); |
| 1799 | const n = try this.in.readVec(data); | 1790 | var vecs: [8][]u8 = undefined; // Arbitrarily chosen amount. |
| | 1791 | const dest_n, const data_size = try r.writableVector(&vecs, data); |
| | 1792 | const dest = vecs[0..dest_n]; |
| | 1793 | const n = try this.in.readVec(dest); |
| 1800 | var remaining: usize = n; | 1794 | var remaining: usize = n; |
| 1801 | for (data) |slice| { | 1795 | for (dest) |slice| { |
| 1802 | if (remaining < slice.len) { | 1796 | if (remaining < slice.len) { |
| 1803 | this.hasher.update(slice[0..remaining]); | 1797 | this.hasher.update(slice[0..remaining]); |
| 1804 | return n; | 1798 | remaining = 0; |
| | 1799 | break; |
| 1805 | } else { | 1800 | } else { |
| 1806 | remaining -= slice.len; | 1801 | remaining -= slice.len; |
| 1807 | this.hasher.update(slice); | 1802 | this.hasher.update(slice); |
| 1808 | } | 1803 | } |
| 1809 | } | 1804 | } |
| 1810 | assert(remaining == 0); | 1805 | assert(remaining == 0); |
| | 1806 | if (n > data_size) { |
| | 1807 | r.end += n - data_size; |
| | 1808 | return data_size; |
| | 1809 | } |
| 1811 | return n; | 1810 | return n; |
| 1812 | } | 1811 | } |
| 1813 | | 1812 | |
| ... | @@ -1824,17 +1823,24 @@ pub fn Hashed(comptime Hasher: type) type { | ... | @@ -1824,17 +1823,24 @@ pub fn Hashed(comptime Hasher: type) type { |
| 1824 | pub fn writableVectorPosix(r: *Reader, buffer: []std.posix.iovec, data: []const []u8) Error!struct { usize, usize } { | 1823 | pub fn writableVectorPosix(r: *Reader, buffer: []std.posix.iovec, data: []const []u8) Error!struct { usize, usize } { |
| 1825 | var i: usize = 0; | 1824 | var i: usize = 0; |
| 1826 | var n: usize = 0; | 1825 | var n: usize = 0; |
| 1827 | for (data) |buf| { | 1826 | if (r.seek == r.end) { |
| 1828 | if (buffer.len - i == 0) return .{ i, n }; | 1827 | for (data) |buf| { |
| | 1828 | if (buffer.len - i == 0) return .{ i, n }; |
| | 1829 | if (buf.len != 0) { |
| | 1830 | buffer[i] = .{ .base = buf.ptr, .len = buf.len }; |
| | 1831 | i += 1; |
| | 1832 | n += buf.len; |
| | 1833 | } |
| | 1834 | } |
| | 1835 | const buf = r.buffer; |
| 1829 | if (buf.len != 0) { | 1836 | if (buf.len != 0) { |
| | 1837 | r.seek = 0; |
| | 1838 | r.end = 0; |
| 1830 | buffer[i] = .{ .base = buf.ptr, .len = buf.len }; | 1839 | buffer[i] = .{ .base = buf.ptr, .len = buf.len }; |
| 1831 | i += 1; | 1840 | i += 1; |
| 1832 | n += buf.len; | | |
| 1833 | } | 1841 | } |
| 1834 | } | 1842 | } else { |
| 1835 | assert(r.seek == r.end); | 1843 | const buf = r.buffer[r.end..]; |
| 1836 | const buf = r.buffer; | | |
| 1837 | if (buf.len != 0) { | | |
| 1838 | buffer[i] = .{ .base = buf.ptr, .len = buf.len }; | 1844 | buffer[i] = .{ .base = buf.ptr, .len = buf.len }; |
| 1839 | i += 1; | 1845 | i += 1; |
| 1840 | } | 1846 | } |
| ... | @@ -1848,28 +1854,62 @@ pub fn writableVectorWsa( | ... | @@ -1848,28 +1854,62 @@ pub fn writableVectorWsa( |
| 1848 | ) Error!struct { usize, usize } { | 1854 | ) Error!struct { usize, usize } { |
| 1849 | var i: usize = 0; | 1855 | var i: usize = 0; |
| 1850 | var n: usize = 0; | 1856 | var n: usize = 0; |
| 1851 | for (data) |buf| { | 1857 | if (r.seek == r.end) { |
| 1852 | if (buffer.len - i == 0) return .{ i, n }; | 1858 | for (data) |buf| { |
| 1853 | if (buf.len == 0) continue; | 1859 | if (buffer.len - i == 0) return .{ i, n }; |
| 1854 | if (std.math.cast(u32, buf.len)) |len| { | 1860 | if (buf.len == 0) continue; |
| 1855 | buffer[i] = .{ .buf = buf.ptr, .len = len }; | 1861 | if (std.math.cast(u32, buf.len)) |len| { |
| | 1862 | buffer[i] = .{ .buf = buf.ptr, .len = len }; |
| | 1863 | i += 1; |
| | 1864 | n += len; |
| | 1865 | continue; |
| | 1866 | } |
| | 1867 | buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) }; |
| | 1868 | i += 1; |
| | 1869 | n += std.math.maxInt(u32); |
| | 1870 | return .{ i, n }; |
| | 1871 | } |
| | 1872 | const buf = r.buffer; |
| | 1873 | if (buf.len != 0) { |
| | 1874 | r.seek = 0; |
| | 1875 | r.end = 0; |
| | 1876 | if (std.math.cast(u32, buf.len)) |len| { |
| | 1877 | buffer[i] = .{ .buf = buf.ptr, .len = len }; |
| | 1878 | } else { |
| | 1879 | buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) }; |
| | 1880 | } |
| 1856 | i += 1; | 1881 | i += 1; |
| 1857 | n += len; | | |
| 1858 | continue; | | |
| 1859 | } | 1882 | } |
| 1860 | buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) }; | 1883 | } else { |
| | 1884 | buffer[i] = .{ |
| | 1885 | .buf = r.buffer.ptr + r.end, |
| | 1886 | .len = @min(std.math.maxInt(u32), r.buffer.len - r.end), |
| | 1887 | }; |
| 1861 | i += 1; | 1888 | i += 1; |
| 1862 | n += std.math.maxInt(u32); | | |
| 1863 | return .{ i, n }; | | |
| 1864 | } | 1889 | } |
| 1865 | assert(r.seek == r.end); | 1890 | return .{ i, n }; |
| 1866 | const buf = r.buffer; | 1891 | } |
| 1867 | if (buf.len != 0) { | 1892 | |
| 1868 | if (std.math.cast(u32, buf.len)) |len| { | 1893 | pub fn writableVector(r: *Reader, buffer: [][]u8, data: []const []u8) Error!struct { usize, usize } { |
| 1869 | buffer[i] = .{ .buf = buf.ptr, .len = len }; | 1894 | var i: usize = 0; |
| 1870 | } else { | 1895 | var n: usize = 0; |
| 1871 | buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) }; | 1896 | if (r.seek == r.end) { |
| | 1897 | for (data) |buf| { |
| | 1898 | if (buffer.len - i == 0) return .{ i, n }; |
| | 1899 | if (buf.len != 0) { |
| | 1900 | buffer[i] = buf; |
| | 1901 | i += 1; |
| | 1902 | n += buf.len; |
| | 1903 | } |
| | 1904 | } |
| | 1905 | if (r.buffer.len != 0) { |
| | 1906 | r.seek = 0; |
| | 1907 | r.end = 0; |
| | 1908 | buffer[i] = r.buffer; |
| | 1909 | i += 1; |
| 1872 | } | 1910 | } |
| | 1911 | } else { |
| | 1912 | buffer[i] = r.buffer[r.end..]; |
| 1873 | i += 1; | 1913 | i += 1; |
| 1874 | } | 1914 | } |
| 1875 | return .{ i, n }; | 1915 | return .{ i, n }; |