| ... | ... | @@ -14,12 +14,6 @@ vtable: *const VTable, |
| 14 | 14 | buffer: []u8, |
| 15 | 15 | /// In `buffer` before this are buffered bytes, after this is `undefined`. |
| 16 | 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 | 18 | pub const VTable = struct { |
| 25 | 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 | 111 | Unimplemented, |
| 118 | 112 | }; |
| 119 | 113 | |
| 120 | | /// Writes to `buffer` and returns `error.WriteFailed` when it is full. Unless |
| 121 | | /// modified externally, `count` will always equal `end`. |
| 114 | /// Writes to `buffer` and returns `error.WriteFailed` when it is full. |
| 122 | 115 | pub fn fixed(buffer: []u8) Writer { |
| 123 | 116 | return .{ |
| 124 | 117 | .vtable = &.{ .drain = fixedDrain }, |
| ... | ... | @@ -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 | 133 | /// Returns the contents not yet drained. |
| 151 | 134 | pub fn buffered(w: *const Writer) []u8 { |
| 152 | 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 | 161 | assert(data.len > 0); |
| 179 | 162 | const buffer = w.buffer; |
| 180 | 163 | const count = countSplat(data, splat); |
| 181 | | if (w.end + count > buffer.len) { |
| 182 | | const n = try w.vtable.drain(w, data, splat); |
| 183 | | w.count += n; |
| 184 | | return n; |
| 185 | | } |
| 186 | | w.count += count; |
| 164 | if (w.end + count > buffer.len) return w.vtable.drain(w, data, splat); |
| 187 | 165 | for (data) |bytes| { |
| 188 | 166 | @memcpy(buffer[w.end..][0..bytes.len], bytes); |
| 189 | 167 | w.end += bytes.len; |
| ... | ... | @@ -236,7 +214,6 @@ pub fn writeSplatHeader( |
| 236 | 214 | if (new_end <= w.buffer.len) { |
| 237 | 215 | @memcpy(w.buffer[w.end..][0..header.len], header); |
| 238 | 216 | w.end = new_end; |
| 239 | | w.count += header.len; |
| 240 | 217 | return header.len + try writeSplat(w, data, splat); |
| 241 | 218 | } |
| 242 | 219 | var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size. |
| ... | ... | @@ -249,9 +226,7 @@ pub fn writeSplatHeader( |
| 249 | 226 | if (vecs.len - i == 0) break; |
| 250 | 227 | } |
| 251 | 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); |
| 253 | | w.count += n; |
| 254 | | return n; |
| 229 | return w.vtable.drain(w, vecs[0..i], new_splat); |
| 255 | 230 | } |
| 256 | 231 | |
| 257 | 232 | /// Equivalent to `writeSplatHeader` but writes at most `limit` bytes. |
| ... | ... | @@ -429,7 +404,6 @@ pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void { |
| 429 | 404 | |
| 430 | 405 | pub fn undo(w: *Writer, n: usize) void { |
| 431 | 406 | w.end -= n; |
| 432 | | w.count -= n; |
| 433 | 407 | } |
| 434 | 408 | |
| 435 | 409 | /// After calling `writableSliceGreedy`, this function tracks how many bytes |
| ... | ... | @@ -440,13 +414,11 @@ pub fn advance(w: *Writer, n: usize) void { |
| 440 | 414 | const new_end = w.end + n; |
| 441 | 415 | assert(new_end <= w.buffer.len); |
| 442 | 416 | w.end = new_end; |
| 443 | | w.count += n; |
| 444 | 417 | } |
| 445 | 418 | |
| 446 | 419 | /// After calling `writableVector`, this function tracks how many bytes were |
| 447 | 420 | /// written to it. |
| 448 | 421 | pub fn advanceVector(w: *Writer, n: usize) usize { |
| 449 | | w.count += n; |
| 450 | 422 | return consume(w, n); |
| 451 | 423 | } |
| 452 | 424 | |
| ... | ... | @@ -504,12 +476,9 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize { |
| 504 | 476 | @branchHint(.likely); |
| 505 | 477 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); |
| 506 | 478 | w.end += bytes.len; |
| 507 | | w.count += bytes.len; |
| 508 | 479 | return bytes.len; |
| 509 | 480 | } |
| 510 | | const n = try w.vtable.drain(w, &.{bytes}, 1); |
| 511 | | w.count += n; |
| 512 | | return n; |
| 481 | return w.vtable.drain(w, &.{bytes}, 1); |
| 513 | 482 | } |
| 514 | 483 | |
| 515 | 484 | /// Asserts `buffer` capacity exceeds `preserve_length`. |
| ... | ... | @@ -519,7 +488,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro |
| 519 | 488 | @branchHint(.likely); |
| 520 | 489 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); |
| 521 | 490 | w.end += bytes.len; |
| 522 | | w.count += bytes.len; |
| 523 | 491 | return bytes.len; |
| 524 | 492 | } |
| 525 | 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 | 495 | w.end = temp_end; |
| 528 | 496 | defer w.end += preserved.len; |
| 529 | 497 | const n = try w.vtable.drain(w, &.{bytes}, 1); |
| 530 | | w.count += n; |
| 531 | 498 | assert(w.end <= temp_end + preserved.len); |
| 532 | 499 | @memmove(w.buffer[w.end..][0..preserved.len], preserved); |
| 533 | 500 | return n; |
| ... | ... | @@ -560,15 +527,11 @@ pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void |
| 560 | 527 | pub fn writeByte(w: *Writer, byte: u8) Error!void { |
| 561 | 528 | while (w.buffer.len - w.end == 0) { |
| 562 | 529 | const n = try w.vtable.drain(w, &.{&.{byte}}, 1); |
| 563 | | if (n > 0) { |
| 564 | | w.count += 1; |
| 565 | | return; |
| 566 | | } |
| 530 | if (n > 0) return; |
| 567 | 531 | } else { |
| 568 | 532 | @branchHint(.likely); |
| 569 | 533 | w.buffer[w.end] = byte; |
| 570 | 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 | 544 | @branchHint(.likely); |
| 582 | 545 | w.buffer[w.end] = byte; |
| 583 | 546 | w.end += 1; |
| 584 | | w.count += 1; |
| 585 | 547 | } |
| 586 | 548 | } |
| 587 | 549 | |
| ... | ... | @@ -690,12 +652,10 @@ pub fn sendFileHeader( |
| 690 | 652 | if (new_end <= w.buffer.len) { |
| 691 | 653 | @memcpy(w.buffer[w.end..][0..header.len], header); |
| 692 | 654 | w.end = new_end; |
| 693 | | w.count += header.len; |
| 694 | 655 | return header.len + try w.vtable.sendFile(w, file_reader, limit); |
| 695 | 656 | } |
| 696 | 657 | const buffered_contents = limit.slice(file_reader.interface.buffered()); |
| 697 | 658 | const n = try w.vtable.drain(w, &.{ header, buffered_contents }, 1); |
| 698 | | w.count += n; |
| 699 | 659 | file_reader.interface.toss(n - header.len); |
| 700 | 660 | return n; |
| 701 | 661 | } |
| ... | ... | @@ -1950,29 +1910,52 @@ pub fn failingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) File |
| 1950 | 1910 | return error.WriteFailed; |
| 1951 | 1911 | } |
| 1952 | 1912 | |
| 1953 | | pub fn discardingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { |
| 1954 | | const slice = data[0 .. data.len - 1]; |
| 1955 | | const pattern = data[slice.len..]; |
| 1956 | | var written: usize = pattern.len * splat; |
| 1957 | | for (slice) |bytes| written += bytes.len; |
| 1958 | | w.end = 0; |
| 1959 | | return written; |
| 1960 | | } |
| 1913 | pub const Discarding = struct { |
| 1914 | count: u64, |
| 1915 | writer: Writer, |
| 1961 | 1916 | |
| 1962 | | pub fn discardingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { |
| 1963 | | if (File.Handle == void) return error.Unimplemented; |
| 1964 | | w.end = 0; |
| 1965 | | if (file_reader.getSize()) |size| { |
| 1966 | | const n = limit.minInt64(size - file_reader.pos); |
| 1967 | | file_reader.seekBy(@intCast(n)) catch return error.Unimplemented; |
| 1917 | pub fn init(buffer: []u8) Discarding { |
| 1918 | return .{ |
| 1919 | .count = 0, |
| 1920 | .writer = .{ |
| 1921 | .vtable = &.{ |
| 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 | 1937 | w.end = 0; |
| 1969 | | return n; |
| 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; |
| 1938 | return written; |
| 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 | 1960 | /// Removes the first `n` bytes from `buffer` by shifting buffer contents, |
| 1978 | 1961 | /// returning how many bytes are left after consuming the entire buffer, or |
| ... | ... | @@ -2219,9 +2202,7 @@ pub const Allocating = struct { |
| 2219 | 2202 | } |
| 2220 | 2203 | |
| 2221 | 2204 | pub fn shrinkRetainingCapacity(a: *Allocating, new_len: usize) void { |
| 2222 | | const shrink_by = a.writer.end - new_len; |
| 2223 | 2205 | a.writer.end = new_len; |
| 2224 | | a.writer.count -= shrink_by; |
| 2225 | 2206 | } |
| 2226 | 2207 | |
| 2227 | 2208 | pub fn clearRetainingCapacity(a: *Allocating) void { |