| ... | ... | @@ -67,6 +67,18 @@ pub const VTable = struct { |
| 67 | 67 | /// |
| 68 | 68 | /// This function is only called when `buffer` is empty. |
| 69 | 69 | discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard, |
| 70 | |
| 71 | /// Ensures `capacity` more data can be buffered without rebasing. |
| 72 | /// |
| 73 | /// Asserts `capacity` is within buffer capacity, or that the stream ends |
| 74 | /// within `capacity` bytes. |
| 75 | /// |
| 76 | /// Only called when `capacity` cannot fit into the unused capacity of |
| 77 | /// `buffer`. |
| 78 | /// |
| 79 | /// The default implementation moves buffered data to the start of |
| 80 | /// `buffer`, setting `seek` to zero, and cannot fail. |
| 81 | rebase: *const fn (r: *Reader, capacity: usize) RebaseError!void = defaultRebase, |
| 70 | 82 | }; |
| 71 | 83 | |
| 72 | 84 | pub const StreamError = error{ |
| ... | ... | @@ -97,6 +109,10 @@ pub const ShortError = error{ |
| 97 | 109 | ReadFailed, |
| 98 | 110 | }; |
| 99 | 111 | |
| 112 | pub const RebaseError = error{ |
| 113 | EndOfStream, |
| 114 | }; |
| 115 | |
| 100 | 116 | pub const failing: Reader = .{ |
| 101 | 117 | .vtable = &.{ |
| 102 | 118 | .stream = failingStream, |
| ... | ... | @@ -122,6 +138,7 @@ pub fn fixed(buffer: []const u8) Reader { |
| 122 | 138 | .vtable = &.{ |
| 123 | 139 | .stream = endingStream, |
| 124 | 140 | .discard = endingDiscard, |
| 141 | .rebase = endingRebase, |
| 125 | 142 | }, |
| 126 | 143 | // This cast is safe because all potential writes to it will instead |
| 127 | 144 | // return `error.EndOfStream`. |
| ... | ... | @@ -780,11 +797,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 780 | 797 | @branchHint(.likely); |
| 781 | 798 | return buffer[seek .. end + 1]; |
| 782 | 799 | } |
| 783 | | if (r.vtable.stream == &endingStream) { |
| 784 | | // Protect the `@constCast` of `fixed`. |
| 785 | | return error.EndOfStream; |
| 786 | | } |
| 787 | | r.rebase(); |
| 800 | // TODO take a parameter for max search length rather than relying on buffer capacity |
| 801 | try rebase(r, r.buffer.len); |
| 788 | 802 | while (r.buffer.len - r.end != 0) { |
| 789 | 803 | const end_cap = r.buffer[r.end..]; |
| 790 | 804 | var writer: Writer = .fixed(end_cap); |
| ... | ... | @@ -1050,11 +1064,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { |
| 1050 | 1064 | }; |
| 1051 | 1065 | if (r.seek + n <= r.end) return; |
| 1052 | 1066 | }; |
| 1053 | | if (r.vtable.stream == &endingStream) { |
| 1054 | | // Protect the `@constCast` of `fixed`. |
| 1055 | | return error.EndOfStream; |
| 1056 | | } |
| 1057 | | rebaseCapacity(r, n); |
| 1067 | try rebase(r, n); |
| 1058 | 1068 | var writer: Writer = .{ |
| 1059 | 1069 | .buffer = r.buffer, |
| 1060 | 1070 | .vtable = &.{ .drain = Writer.fixedDrain }, |
| ... | ... | @@ -1074,7 +1084,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { |
| 1074 | 1084 | /// |
| 1075 | 1085 | /// Asserts buffer capacity is at least 1. |
| 1076 | 1086 | pub fn fillMore(r: *Reader) Error!void { |
| 1077 | | rebaseCapacity(r, 1); |
| 1087 | try rebase(r, 1); |
| 1078 | 1088 | var writer: Writer = .{ |
| 1079 | 1089 | .buffer = r.buffer, |
| 1080 | 1090 | .end = r.end, |
| ... | ... | @@ -1251,7 +1261,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { |
| 1251 | 1261 | |
| 1252 | 1262 | pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void { |
| 1253 | 1263 | if (n <= r.buffer.len) return; |
| 1254 | | if (r.seek > 0) rebase(r); |
| 1264 | if (r.seek > 0) rebase(r, r.buffer.len); |
| 1255 | 1265 | var list: ArrayList(u8) = .{ |
| 1256 | 1266 | .items = r.buffer[0..r.end], |
| 1257 | 1267 | .capacity = r.buffer.len, |
| ... | ... | @@ -1297,37 +1307,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu |
| 1297 | 1307 | } |
| 1298 | 1308 | } |
| 1299 | 1309 | |
| 1300 | | /// Left-aligns data such that `r.seek` becomes zero. |
| 1301 | | /// |
| 1302 | | /// If `r.seek` is not already zero then `buffer` is mutated, making it illegal |
| 1303 | | /// to call this function with a const-casted `buffer`, such as in the case of |
| 1304 | | /// `fixed`. This issue can be avoided: |
| 1305 | | /// * in implementations, by attempting a read before a rebase, in which |
| 1306 | | /// case the read will return `error.EndOfStream`, preventing the rebase. |
| 1307 | | /// * in usage, by copying into a mutable buffer before initializing `fixed`. |
| 1308 | | pub fn rebase(r: *Reader) void { |
| 1309 | | if (r.seek == 0) return; |
| 1310 | /// Ensures `capacity` more data can be buffered without rebasing. |
| 1311 | pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1312 | if (r.end + capacity <= r.buffer.len) return; |
| 1313 | return r.vtable.rebase(r, capacity); |
| 1314 | } |
| 1315 | |
| 1316 | pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1317 | if (r.end <= r.buffer.len - capacity) return; |
| 1310 | 1318 | const data = r.buffer[r.seek..r.end]; |
| 1311 | 1319 | @memmove(r.buffer[0..data.len], data); |
| 1312 | 1320 | r.seek = 0; |
| 1313 | 1321 | r.end = data.len; |
| 1314 | 1322 | } |
| 1315 | 1323 | |
| 1316 | | /// Ensures `capacity` more data can be buffered without rebasing, by rebasing |
| 1317 | | /// if necessary. |
| 1318 | | /// |
| 1319 | | /// Asserts `capacity` is within the buffer capacity. |
| 1320 | | /// |
| 1321 | | /// If the rebase occurs then `buffer` is mutated, making it illegal to call |
| 1322 | | /// this function with a const-casted `buffer`, such as in the case of `fixed`. |
| 1323 | | /// This issue can be avoided: |
| 1324 | | /// * in implementations, by attempting a read before a rebase, in which |
| 1325 | | /// case the read will return `error.EndOfStream`, preventing the rebase. |
| 1326 | | /// * in usage, by copying into a mutable buffer before initializing `fixed`. |
| 1327 | | pub fn rebaseCapacity(r: *Reader, capacity: usize) void { |
| 1328 | | if (r.end > r.buffer.len - capacity) rebase(r); |
| 1329 | | } |
| 1330 | | |
| 1331 | 1324 | /// Advances the stream and decreases the size of the storage buffer by `n`, |
| 1332 | 1325 | /// returning the range of bytes no longer accessible by `r`. |
| 1333 | 1326 | /// |
| ... | ... | @@ -1683,6 +1676,12 @@ fn endingDiscard(r: *Reader, limit: Limit) Error!usize { |
| 1683 | 1676 | return error.EndOfStream; |
| 1684 | 1677 | } |
| 1685 | 1678 | |
| 1679 | fn endingRebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1680 | _ = r; |
| 1681 | _ = capacity; |
| 1682 | return error.EndOfStream; |
| 1683 | } |
| 1684 | |
| 1686 | 1685 | fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { |
| 1687 | 1686 | _ = r; |
| 1688 | 1687 | _ = w; |