| ... | @@ -14,12 +14,6 @@ vtable: *const VTable, | ... | @@ -14,12 +14,6 @@ vtable: *const VTable, |
| 14 | buffer: []u8, | 14 | buffer: []u8, |
| 15 | /// In `buffer` before this are buffered bytes, after this is `undefined`. | 15 | /// In `buffer` before this are buffered bytes, after this is `undefined`. |
| 16 | end: usize = 0, | 16 | end: usize = 0, |
| 17 | /// Tracks total number of bytes written to this `Writer`. This value | | |
| 18 | /// only increases. In the case of fixed mode, this value always equals `end`. | | |
| 19 | /// | | |
| 20 | /// This value is maintained by the interface; `VTable` function | | |
| 21 | /// implementations need not modify it. | | |
| 22 | count: usize = 0, | | |
| 23 | | 17 | |
| 24 | pub const VTable = struct { | 18 | pub const VTable = struct { |
| 25 | /// Sends bytes to the logical sink. A write will only be sent here if it | 19 | /// Sends bytes to the logical sink. A write will only be sent here if it |
| ... | @@ -117,8 +111,7 @@ pub const FileError = error{ | ... | @@ -117,8 +111,7 @@ pub const FileError = error{ |
| 117 | Unimplemented, | 111 | Unimplemented, |
| 118 | }; | 112 | }; |
| 119 | | 113 | |
| 120 | /// Writes to `buffer` and returns `error.WriteFailed` when it is full. Unless | 114 | /// Writes to `buffer` and returns `error.WriteFailed` when it is full. |
| 121 | /// modified externally, `count` will always equal `end`. | | |
| 122 | pub fn fixed(buffer: []u8) Writer { | 115 | pub fn fixed(buffer: []u8) Writer { |
| 123 | return .{ | 116 | return .{ |
| 124 | .vtable = &.{ .drain = fixedDrain }, | 117 | .vtable = &.{ .drain = fixedDrain }, |
| ... | @@ -137,16 +130,6 @@ pub const failing: Writer = .{ | ... | @@ -137,16 +130,6 @@ pub const failing: Writer = .{ |
| 137 | }, | 130 | }, |
| 138 | }; | 131 | }; |
| 139 | | 132 | |
| 140 | pub fn discarding(buffer: []u8) Writer { | | |
| 141 | return .{ | | |
| 142 | .vtable = &.{ | | |
| 143 | .drain = discardingDrain, | | |
| 144 | .sendFile = discardingSendFile, | | |
| 145 | }, | | |
| 146 | .buffer = buffer, | | |
| 147 | }; | | |
| 148 | } | | |
| 149 | | | |
| 150 | /// Returns the contents not yet drained. | 133 | /// Returns the contents not yet drained. |
| 151 | pub fn buffered(w: *const Writer) []u8 { | 134 | pub fn buffered(w: *const Writer) []u8 { |
| 152 | return w.buffer[0..w.end]; | 135 | return w.buffer[0..w.end]; |
| ... | @@ -178,12 +161,7 @@ pub fn writeSplat(w: *Writer, data: []const []const u8, splat: usize) Error!usiz | ... | @@ -178,12 +161,7 @@ pub fn writeSplat(w: *Writer, data: []const []const u8, splat: usize) Error!usiz |
| 178 | assert(data.len > 0); | 161 | assert(data.len > 0); |
| 179 | const buffer = w.buffer; | 162 | const buffer = w.buffer; |
| 180 | const count = countSplat(data, splat); | 163 | const count = countSplat(data, splat); |
| 181 | if (w.end + count > buffer.len) { | 164 | if (w.end + count > buffer.len) return w.vtable.drain(w, data, splat); |
| 182 | const n = try w.vtable.drain(w, data, splat); | | |
| 183 | w.count += n; | | |
| 184 | return n; | | |
| 185 | } | | |
| 186 | w.count += count; | | |
| 187 | for (data) |bytes| { | 165 | for (data) |bytes| { |
| 188 | @memcpy(buffer[w.end..][0..bytes.len], bytes); | 166 | @memcpy(buffer[w.end..][0..bytes.len], bytes); |
| 189 | w.end += bytes.len; | 167 | w.end += bytes.len; |
| ... | @@ -236,7 +214,6 @@ pub fn writeSplatHeader( | ... | @@ -236,7 +214,6 @@ pub fn writeSplatHeader( |
| 236 | if (new_end <= w.buffer.len) { | 214 | if (new_end <= w.buffer.len) { |
| 237 | @memcpy(w.buffer[w.end..][0..header.len], header); | 215 | @memcpy(w.buffer[w.end..][0..header.len], header); |
| 238 | w.end = new_end; | 216 | w.end = new_end; |
| 239 | w.count += header.len; | | |
| 240 | return header.len + try writeSplat(w, data, splat); | 217 | return header.len + try writeSplat(w, data, splat); |
| 241 | } | 218 | } |
| 242 | var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size. | 219 | var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size. |
| ... | @@ -249,9 +226,7 @@ pub fn writeSplatHeader( | ... | @@ -249,9 +226,7 @@ pub fn writeSplatHeader( |
| 249 | if (vecs.len - i == 0) break; | 226 | if (vecs.len - i == 0) break; |
| 250 | } | 227 | } |
| 251 | const new_splat = if (vecs[i - 1].ptr == data[data.len - 1].ptr) splat else 1; | 228 | const new_splat = if (vecs[i - 1].ptr == data[data.len - 1].ptr) splat else 1; |
| 252 | const n = try w.vtable.drain(w, vecs[0..i], new_splat); | 229 | return w.vtable.drain(w, vecs[0..i], new_splat); |
| 253 | w.count += n; | | |
| 254 | return n; | | |
| 255 | } | 230 | } |
| 256 | | 231 | |
| 257 | /// Equivalent to `writeSplatHeader` but writes at most `limit` bytes. | 232 | /// Equivalent to `writeSplatHeader` but writes at most `limit` bytes. |
| ... | @@ -429,7 +404,6 @@ pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void { | ... | @@ -429,7 +404,6 @@ pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void { |
| 429 | | 404 | |
| 430 | pub fn undo(w: *Writer, n: usize) void { | 405 | pub fn undo(w: *Writer, n: usize) void { |
| 431 | w.end -= n; | 406 | w.end -= n; |
| 432 | w.count -= n; | | |
| 433 | } | 407 | } |
| 434 | | 408 | |
| 435 | /// After calling `writableSliceGreedy`, this function tracks how many bytes | 409 | /// After calling `writableSliceGreedy`, this function tracks how many bytes |
| ... | @@ -440,13 +414,11 @@ pub fn advance(w: *Writer, n: usize) void { | ... | @@ -440,13 +414,11 @@ pub fn advance(w: *Writer, n: usize) void { |
| 440 | const new_end = w.end + n; | 414 | const new_end = w.end + n; |
| 441 | assert(new_end <= w.buffer.len); | 415 | assert(new_end <= w.buffer.len); |
| 442 | w.end = new_end; | 416 | w.end = new_end; |
| 443 | w.count += n; | | |
| 444 | } | 417 | } |
| 445 | | 418 | |
| 446 | /// After calling `writableVector`, this function tracks how many bytes were | 419 | /// After calling `writableVector`, this function tracks how many bytes were |
| 447 | /// written to it. | 420 | /// written to it. |
| 448 | pub fn advanceVector(w: *Writer, n: usize) usize { | 421 | pub fn advanceVector(w: *Writer, n: usize) usize { |
| 449 | w.count += n; | | |
| 450 | return consume(w, n); | 422 | return consume(w, n); |
| 451 | } | 423 | } |
| 452 | | 424 | |
| ... | @@ -504,12 +476,9 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize { | ... | @@ -504,12 +476,9 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize { |
| 504 | @branchHint(.likely); | 476 | @branchHint(.likely); |
| 505 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); | 477 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); |
| 506 | w.end += bytes.len; | 478 | w.end += bytes.len; |
| 507 | w.count += bytes.len; | | |
| 508 | return bytes.len; | 479 | return bytes.len; |
| 509 | } | 480 | } |
| 510 | const n = try w.vtable.drain(w, &.{bytes}, 1); | 481 | return w.vtable.drain(w, &.{bytes}, 1); |
| 511 | w.count += n; | | |
| 512 | return n; | | |
| 513 | } | 482 | } |
| 514 | | 483 | |
| 515 | /// Asserts `buffer` capacity exceeds `preserve_length`. | 484 | /// Asserts `buffer` capacity exceeds `preserve_length`. |
| ... | @@ -519,7 +488,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro | ... | @@ -519,7 +488,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro |
| 519 | @branchHint(.likely); | 488 | @branchHint(.likely); |
| 520 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); | 489 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); |
| 521 | w.end += bytes.len; | 490 | w.end += bytes.len; |
| 522 | w.count += bytes.len; | | |
| 523 | return bytes.len; | 491 | return bytes.len; |
| 524 | } | 492 | } |
| 525 | const temp_end = w.end -| preserve_length; | 493 | const temp_end = w.end -| preserve_length; |
| ... | @@ -527,7 +495,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro | ... | @@ -527,7 +495,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro |
| 527 | w.end = temp_end; | 495 | w.end = temp_end; |
| 528 | defer w.end += preserved.len; | 496 | defer w.end += preserved.len; |
| 529 | const n = try w.vtable.drain(w, &.{bytes}, 1); | 497 | const n = try w.vtable.drain(w, &.{bytes}, 1); |
| 530 | w.count += n; | | |
| 531 | assert(w.end <= temp_end + preserved.len); | 498 | assert(w.end <= temp_end + preserved.len); |
| 532 | @memmove(w.buffer[w.end..][0..preserved.len], preserved); | 499 | @memmove(w.buffer[w.end..][0..preserved.len], preserved); |
| 533 | return n; | 500 | return n; |
| ... | @@ -560,15 +527,11 @@ pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void | ... | @@ -560,15 +527,11 @@ pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void |
| 560 | pub fn writeByte(w: *Writer, byte: u8) Error!void { | 527 | pub fn writeByte(w: *Writer, byte: u8) Error!void { |
| 561 | while (w.buffer.len - w.end == 0) { | 528 | while (w.buffer.len - w.end == 0) { |
| 562 | const n = try w.vtable.drain(w, &.{&.{byte}}, 1); | 529 | const n = try w.vtable.drain(w, &.{&.{byte}}, 1); |
| 563 | if (n > 0) { | 530 | if (n > 0) return; |
| 564 | w.count += 1; | | |
| 565 | return; | | |
| 566 | } | | |
| 567 | } else { | 531 | } else { |
| 568 | @branchHint(.likely); | 532 | @branchHint(.likely); |
| 569 | w.buffer[w.end] = byte; | 533 | w.buffer[w.end] = byte; |
| 570 | w.end += 1; | 534 | w.end += 1; |
| 571 | w.count += 1; | | |
| 572 | } | 535 | } |
| 573 | } | 536 | } |
| 574 | | 537 | |
| ... | @@ -581,7 +544,6 @@ pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!voi | ... | @@ -581,7 +544,6 @@ pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!voi |
| 581 | @branchHint(.likely); | 544 | @branchHint(.likely); |
| 582 | w.buffer[w.end] = byte; | 545 | w.buffer[w.end] = byte; |
| 583 | w.end += 1; | 546 | w.end += 1; |
| 584 | w.count += 1; | | |
| 585 | } | 547 | } |
| 586 | } | 548 | } |
| 587 | | 549 | |
| ... | @@ -690,12 +652,10 @@ pub fn sendFileHeader( | ... | @@ -690,12 +652,10 @@ pub fn sendFileHeader( |
| 690 | if (new_end <= w.buffer.len) { | 652 | if (new_end <= w.buffer.len) { |
| 691 | @memcpy(w.buffer[w.end..][0..header.len], header); | 653 | @memcpy(w.buffer[w.end..][0..header.len], header); |
| 692 | w.end = new_end; | 654 | w.end = new_end; |
| 693 | w.count += header.len; | | |
| 694 | return header.len + try w.vtable.sendFile(w, file_reader, limit); | 655 | return header.len + try w.vtable.sendFile(w, file_reader, limit); |
| 695 | } | 656 | } |
| 696 | const buffered_contents = limit.slice(file_reader.interface.buffered()); | 657 | const buffered_contents = limit.slice(file_reader.interface.buffered()); |
| 697 | const n = try w.vtable.drain(w, &.{ header, buffered_contents }, 1); | 658 | const n = try w.vtable.drain(w, &.{ header, buffered_contents }, 1); |
| 698 | w.count += n; | | |
| 699 | file_reader.interface.toss(n - header.len); | 659 | file_reader.interface.toss(n - header.len); |
| 700 | return n; | 660 | return n; |
| 701 | } | 661 | } |
| ... | @@ -1950,29 +1910,52 @@ pub fn failingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) File | ... | @@ -1950,29 +1910,52 @@ pub fn failingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) File |
| 1950 | return error.WriteFailed; | 1910 | return error.WriteFailed; |
| 1951 | } | 1911 | } |
| 1952 | | 1912 | |
| 1953 | pub fn discardingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { | 1913 | pub const Discarding = struct { |
| 1954 | const slice = data[0 .. data.len - 1]; | 1914 | count: u64, |
| 1955 | const pattern = data[slice.len..]; | 1915 | writer: Writer, |
| 1956 | var written: usize = pattern.len * splat; | | |
| 1957 | for (slice) |bytes| written += bytes.len; | | |
| 1958 | w.end = 0; | | |
| 1959 | return written; | | |
| 1960 | } | | |
| 1961 | | 1916 | |
| 1962 | pub fn discardingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { | 1917 | pub fn init(buffer: []u8) Discarding { |
| 1963 | if (File.Handle == void) return error.Unimplemented; | 1918 | return .{ |
| 1964 | w.end = 0; | 1919 | .count = 0, |
| 1965 | if (file_reader.getSize()) |size| { | 1920 | .writer = .{ |
| 1966 | const n = limit.minInt64(size - file_reader.pos); | 1921 | .vtable = &.{ |
| 1967 | file_reader.seekBy(@intCast(n)) catch return error.Unimplemented; | 1922 | .drain = Discarding.drain, |
| | 1923 | .sendFile = Discarding.sendFile, |
| | 1924 | }, |
| | 1925 | .buffer = buffer, |
| | 1926 | }, |
| | 1927 | }; |
| | 1928 | } |
| | 1929 | |
| | 1930 | pub fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { |
| | 1931 | const d: *Discarding = @alignCast(@fieldParentPtr("writer", w)); |
| | 1932 | const slice = data[0 .. data.len - 1]; |
| | 1933 | const pattern = data[slice.len..]; |
| | 1934 | var written: usize = pattern.len * splat; |
| | 1935 | for (slice) |bytes| written += bytes.len; |
| | 1936 | d.count += w.end + written; |
| 1968 | w.end = 0; | 1937 | w.end = 0; |
| 1969 | return n; | 1938 | return written; |
| 1970 | } else |_| { | | |
| 1971 | // Error is observable on `file_reader` instance, and it is better to | | |
| 1972 | // treat the file as a pipe. | | |
| 1973 | return error.Unimplemented; | | |
| 1974 | } | 1939 | } |
| 1975 | } | 1940 | |
| | 1941 | pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { |
| | 1942 | if (File.Handle == void) return error.Unimplemented; |
| | 1943 | const d: *Discarding = @alignCast(@fieldParentPtr("writer", w)); |
| | 1944 | d.count += w.end; |
| | 1945 | w.end = 0; |
| | 1946 | if (file_reader.getSize()) |size| { |
| | 1947 | const n = limit.minInt64(size - file_reader.pos); |
| | 1948 | file_reader.seekBy(@intCast(n)) catch return error.Unimplemented; |
| | 1949 | w.end = 0; |
| | 1950 | d.count += n; |
| | 1951 | return n; |
| | 1952 | } else |_| { |
| | 1953 | // Error is observable on `file_reader` instance, and it is better to |
| | 1954 | // treat the file as a pipe. |
| | 1955 | return error.Unimplemented; |
| | 1956 | } |
| | 1957 | } |
| | 1958 | }; |
| 1976 | | 1959 | |
| 1977 | /// Removes the first `n` bytes from `buffer` by shifting buffer contents, | 1960 | /// Removes the first `n` bytes from `buffer` by shifting buffer contents, |
| 1978 | /// returning how many bytes are left after consuming the entire buffer, or | 1961 | /// returning how many bytes are left after consuming the entire buffer, or |
| ... | @@ -2219,9 +2202,7 @@ pub const Allocating = struct { | ... | @@ -2219,9 +2202,7 @@ pub const Allocating = struct { |
| 2219 | } | 2202 | } |
| 2220 | | 2203 | |
| 2221 | pub fn shrinkRetainingCapacity(a: *Allocating, new_len: usize) void { | 2204 | pub fn shrinkRetainingCapacity(a: *Allocating, new_len: usize) void { |
| 2222 | const shrink_by = a.writer.end - new_len; | | |
| 2223 | a.writer.end = new_len; | 2205 | a.writer.end = new_len; |
| 2224 | a.writer.count -= shrink_by; | | |
| 2225 | } | 2206 | } |
| 2226 | | 2207 | |
| 2227 | pub fn clearRetainingCapacity(a: *Allocating) void { | 2208 | pub fn clearRetainingCapacity(a: *Allocating) void { |