1const Reader = @This();
2
3const builtin = @import("builtin");
4const native_endian = builtin.target.cpu.arch.endian();
5
6const std = @import("../std.zig");
7const Writer = std.Io.Writer;
8const Limit = std.Io.Limit;
9const assert = std.debug.assert;
10const testing = std.testing;
11const Allocator = std.mem.Allocator;
12const ArrayList = std.ArrayList;
13
14pub const Limited = @import("Reader/Limited.zig");
15
16vtable: *const VTable,
17buffer: []u8,
18/// Number of bytes which have been consumed from `buffer`.
19seek: usize,
20/// In `buffer` before this are buffered bytes, after this is `undefined`.
21end: usize,
22
23pub const VTable = struct {
24 /// Writes bytes from the internally tracked logical position to `w`.
25 ///
26 /// Returns the number of bytes written, which will be at minimum `0` and
27 /// at most `limit`. The number returned, including zero, does not indicate
28 /// end of stream.
29 ///
30 /// The reader's internal logical seek position moves forward in accordance
31 /// with the number of bytes returned from this function.
32 ///
33 /// Implementations are encouraged to utilize mandatory minimum buffer
34 /// sizes combined with short reads (returning a value less than `limit`)
35 /// in order to minimize complexity.
36 ///
37 /// Although this function is usually called when `buffer` is empty, it is
38 /// also called when it needs to be filled more due to the API user
39 /// requesting contiguous memory. In either case, the existing buffer data
40 /// should be ignored; new data written to `w`.
41 ///
42 /// In addition to, or instead of writing to `w`, the implementation may
43 /// choose to store data in `buffer`, modifying `seek` and `end`
44 /// accordingly. Implementations are encouraged to take advantage of
45 /// this if it simplifies the logic.
46 stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize,
47
48 /// Consumes bytes from the internally tracked stream position without
49 /// providing access to them.
50 ///
51 /// Returns the number of bytes discarded, which will be at minimum `0` and
52 /// at most `limit`. The number of bytes returned, including zero, does not
53 /// indicate end of stream.
54 ///
55 /// The reader's internal logical seek position moves forward in accordance
56 /// with the number of bytes returned from this function.
57 ///
58 /// Implementations are encouraged to utilize mandatory minimum buffer
59 /// sizes combined with short reads (returning a value less than `limit`)
60 /// in order to minimize complexity.
61 ///
62 /// The default implementation is is based on calling `stream`, borrowing
63 /// `buffer` to construct a temporary `Writer` and ignoring the written
64 /// data.
65 ///
66 /// This function is only called when `buffer` is empty.
67 discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard,
68
69 /// Returns number of bytes written to `data`.
70 ///
71 /// `data` must have nonzero length. `data[0]` may have zero length, in
72 /// which case the implementation must write to `Reader.buffer`.
73 ///
74 /// `data` may not contain an alias to `Reader.buffer`.
75 ///
76 /// `data` is mutable because the implementation may temporarily modify the
77 /// fields in order to handle partial reads. Implementations must restore
78 /// the original value before returning.
79 ///
80 /// Implementations may ignore `data`, writing directly to `Reader.buffer`,
81 /// modifying `seek` and `end` accordingly, and returning 0 from this
82 /// function. Implementations are encouraged to take advantage of this if
83 /// it simplifies the logic.
84 ///
85 /// The default implementation calls `stream` with either `data[0]` or
86 /// `Reader.buffer`, whichever is bigger.
87 readVec: *const fn (r: *Reader, data: [][]u8) Error!usize = defaultReadVec,
88
89 /// Ensures `capacity` data can be buffered without rebasing.
90 ///
91 /// Asserts `capacity` is within buffer capacity, or that the stream ends
92 /// within `capacity` bytes.
93 ///
94 /// Only called when `capacity` cannot be satisfied by unused capacity of
95 /// `buffer`.
96 ///
97 /// The default implementation moves buffered data to the start of
98 /// `buffer`, setting `seek` to zero, and cannot fail.
99 rebase: *const fn (r: *Reader, capacity: usize) RebaseError!void = defaultRebase,
100};
101
102pub const StreamError = error{
103 /// See the `Reader` implementation for detailed diagnostics.
104 ReadFailed,
105 /// See the `Writer` implementation for detailed diagnostics.
106 WriteFailed,
107 /// End of stream indicated from the `Reader`. This error cannot originate
108 /// from the `Writer`.
109 EndOfStream,
110};
111
112pub const Error = error{
113 /// See the `Reader` implementation for detailed diagnostics.
114 ReadFailed,
115 EndOfStream,
116};
117
118pub const StreamRemainingError = error{
119 /// See the `Reader` implementation for detailed diagnostics.
120 ReadFailed,
121 /// See the `Writer` implementation for detailed diagnostics.
122 WriteFailed,
123};
124
125pub const ShortError = error{
126 /// See the `Reader` implementation for detailed diagnostics.
127 ReadFailed,
128};
129
130pub const RebaseError = Error;
131
132pub const failing: Reader = .{
133 .vtable = &.{
134 .stream = failingStream,
135 .discard = failingDiscard,
136 },
137 .buffer = &.{},
138 .seek = 0,
139 .end = 0,
140};
141
142/// This is generally safe to `@constCast` because it has an empty buffer, so
143/// there is not really a way to accidentally attempt mutation of these fields.
144pub const ending_instance: Reader = .fixed(&.{});
145pub const ending: *Reader = @constCast(&ending_instance);
146
147pub fn limited(r: *Reader, limit: Limit, buffer: []u8) Limited {
148 return .init(r, limit, buffer);
149}
150
151/// Constructs a `Reader` such that it will read from `buffer` and then end.
152pub fn fixed(buffer: []const u8) Reader {
153 return .{
154 .vtable = &.{
155 .stream = endingStream,
156 .discard = endingDiscard,
157 .readVec = endingReadVec,
158 .rebase = endingRebase,
159 },
160 // This cast is safe because all potential writes to it will instead
161 // return `error.EndOfStream`.
162 .buffer = @constCast(buffer),
163 .end = buffer.len,
164 .seek = 0,
165 };
166}
167
168pub fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
169 const buffer = limit.slice(r.buffer[r.seek..r.end]);
170 if (buffer.len > 0) {
171 @branchHint(.likely);
172 const n = try w.write(buffer);
173 r.seek += n;
174 return n;
175 }
176 const n = try r.vtable.stream(r, w, limit);
177 assert(n <= @backingInt(limit));
178 return n;
179}
180
181pub fn discard(r: *Reader, limit: Limit) Error!usize {
182 const buffered_len = r.end - r.seek;
183 const remaining: Limit = if (limit.toInt()) |n| l: {
184 if (buffered_len >= n) {
185 r.seek += n;
186 return n;
187 }
188 break :l .limited(n - buffered_len);
189 } else .unlimited;
190 r.seek = r.end;
191 const n = try r.vtable.discard(r, remaining);
192 assert(n <= @backingInt(remaining));
193 return buffered_len + n;
194}
195
196pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
197 assert(r.seek == r.end);
198 r.seek = 0;
199 r.end = 0;
200 var d: Writer.Discarding = .init(r.buffer);
201 var n = r.stream(&d.writer, limit) catch |err| switch (err) {
202 error.WriteFailed => unreachable,
203 error.ReadFailed, error.EndOfStream => |e| return e,
204 };
205 // If `stream` wrote to `r.buffer` without going through the writer,
206 // we need to discard as much of the buffered data as possible.
207 const remaining = @backingInt(limit) - n;
208 const buffered_n_to_discard = @min(remaining, r.end - r.seek);
209 n += buffered_n_to_discard;
210 r.seek += buffered_n_to_discard;
211 assert(n <= @backingInt(limit));
212 return n;
213}
214
215/// "Pump" exactly `n` bytes from the reader to the writer.
216pub fn streamExact(r: *Reader, w: *Writer, n: usize) StreamError!void {
217 var remaining = n;
218 while (remaining != 0) remaining -= try r.stream(w, .limited(remaining));
219}
220
221/// "Pump" exactly `n` bytes from the reader to the writer.
222pub fn streamExact64(r: *Reader, w: *Writer, n: u64) StreamError!void {
223 var remaining = n;
224 while (remaining != 0) remaining -= try r.stream(w, .limited64(remaining));
225}
226
227/// "Pump" exactly `n` bytes from the reader to the writer.
228///
229/// On success, at least `preserve_len` bytes will remain buffered if there are
230/// enough buffered bytes to do so.
231/// The amount buffered by the writer after the call will only be less than
232/// `preserve_len` if `w.end + n` is less than `preserve_len` before the call.
233/// The intentionally preserved bytes will include up to `preserve_len -| n` bytes from
234/// the previously buffered bytes, plus `@min(n, preserve_len)` of the newly
235/// "pumped" bytes.
236///
237/// Asserts `Writer.buffer` capacity is at least `preserve_len`.
238/// `n` can be greater than the `Writer.buffer` capacity.
239pub fn streamExactPreserve(r: *Reader, w: *Writer, preserve_len: usize, n: usize) StreamError!void {
240 if (w.end + n <= w.buffer.len) {
241 @branchHint(.likely);
242 return streamExact(r, w, n);
243 }
244 // If `n` is large, we can ignore `preserve_len` up to a point.
245 var remaining = n;
246 while (remaining > preserve_len) {
247 assert(remaining != 0);
248 remaining -= try r.stream(w, .limited(remaining - preserve_len));
249 if (w.end + remaining <= w.buffer.len) return streamExact(r, w, remaining);
250 }
251 // Offset the amount preserved by the amount we have left to stream
252 // since the remaining bytes are always going to be part of that
253 // preservation.
254 try w.rebase(preserve_len -| remaining, remaining);
255 return streamExact(r, w, remaining);
256}
257
258/// "Pump" data from the reader to the writer, handling `error.EndOfStream` as
259/// a success case.
260///
261/// Returns total number of bytes written to `w`.
262pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {
263 var offset: usize = 0;
264 while (true) {
265 offset += r.stream(w, .unlimited) catch |err| switch (err) {
266 error.EndOfStream => return offset,
267 else => |e| return e,
268 };
269 }
270}
271
272/// Consumes the stream until the end, ignoring all the data, returning the
273/// number of bytes discarded.
274pub fn discardRemaining(r: *Reader) ShortError!usize {
275 var offset: usize = r.end - r.seek;
276 r.seek = r.end;
277 while (true) {
278 offset += r.vtable.discard(r, .unlimited) catch |err| switch (err) {
279 error.EndOfStream => return offset,
280 else => |e| return e,
281 };
282 }
283}
284
285pub const LimitedAllocError = Allocator.Error || ShortError || error{StreamTooLong};
286
287/// Transfers all bytes from the current position to the end of the stream, up
288/// to `limit`, returning them as a caller-owned allocated slice.
289///
290/// If `limit` is reached or exceeded, `error.StreamTooLong` is returned
291/// instead. In such case, the next byte that would be read will be the first
292/// one to exceed `limit`, and all preceeding bytes have been discarded.
293///
294/// See also:
295/// * `appendRemaining`
296pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocError![]u8 {
297 var buffer: ArrayList(u8) = .empty;
298 defer buffer.deinit(gpa);
299 try appendRemaining(r, gpa, &buffer, limit);
300 return buffer.toOwnedSlice(gpa);
301}
302
303pub fn allocRemainingAlignedSentinel(
304 r: *Reader,
305 gpa: Allocator,
306 limit: Limit,
307 comptime alignment: std.mem.Alignment,
308 comptime sentinel: ?u8,
309) LimitedAllocError!(if (sentinel) |s| [:s]align(alignment.toByteUnits()) u8 else []align(alignment.toByteUnits()) u8) {
310 var buffer: std.array_list.Aligned(u8, alignment) = .empty;
311 defer buffer.deinit(gpa);
312 try appendRemainingAligned(r, gpa, alignment, &buffer, limit);
313 if (sentinel) |s| {
314 return buffer.toOwnedSliceSentinel(gpa, s);
315 } else {
316 return buffer.toOwnedSlice(gpa);
317 }
318}
319
320pub const AppendExactError = Allocator.Error || Error;
321
322/// Transfers exactly `n` bytes from the reader to the `ArrayList`.
323///
324/// See also:
325/// * `appendRemaining`
326pub fn appendExact(
327 r: *Reader,
328 gpa: Allocator,
329 list: *ArrayList(u8),
330 n: usize,
331) AppendExactError!void {
332 try list.ensureUnusedCapacity(gpa, n);
333 var a = std.Io.Writer.Allocating.fromArrayList(gpa, list);
334 defer list.* = a.toArrayList();
335 streamExact(r, &a.writer, n) catch |err| switch (err) {
336 error.ReadFailed, error.EndOfStream => |e| return e,
337 error.WriteFailed => unreachable,
338 };
339}
340
341/// Transfers all bytes from the current position to the end of the stream, up
342/// to `limit`, appending them to `list`.
343///
344/// If `limit` is reached or exceeded, `error.StreamTooLong` is returned
345/// instead. In such case, the next byte that would be read will be the first
346/// one to exceed `limit`, and all preceeding bytes have been appended to
347/// `list`.
348///
349/// See also:
350/// * `allocRemaining`
351pub fn appendRemaining(
352 r: *Reader,
353 gpa: Allocator,
354 list: *ArrayList(u8),
355 limit: Limit,
356) LimitedAllocError!void {
357 return appendRemainingAligned(r, gpa, .of(u8), list, limit);
358}
359
360/// Transfers all bytes from the current position to the end of the stream, up
361/// to `limit`, appending them to `list`.
362///
363/// If `limit` is reached or exceeded, `error.StreamTooLong` is returned
364/// instead. In such case, the next byte that would be read will be the first
365/// one to exceed `limit`, and all preceeding bytes have been appended to
366/// `list`.
367///
368/// See also:
369/// * `appendRemaining`
370/// * `allocRemainingAligned`
371pub fn appendRemainingAligned(
372 r: *Reader,
373 gpa: Allocator,
374 comptime alignment: std.mem.Alignment,
375 list: *std.array_list.Aligned(u8, alignment),
376 limit: Limit,
377) LimitedAllocError!void {
378 var a = std.Io.Writer.Allocating.fromArrayListAligned(gpa, alignment, list);
379 defer list.* = a.toArrayListAligned(alignment);
380
381 var remaining = limit;
382 while (remaining != .nothing) {
383 const n = stream(r, &a.writer, remaining) catch |err| switch (err) {
384 error.EndOfStream => return,
385 error.WriteFailed => return error.OutOfMemory,
386 error.ReadFailed => |e| return e,
387 };
388 remaining = remaining.subtract(n).?;
389 }
390 return error.StreamTooLong;
391}
392
393pub const UnlimitedAllocError = Allocator.Error || ShortError;
394
395pub fn appendRemainingUnlimited(r: *Reader, gpa: Allocator, list: *ArrayList(u8)) UnlimitedAllocError!void {
396 var a: std.Io.Writer.Allocating = .initOwnedSlice(gpa, list.allocatedSlice());
397 a.writer.end = list.items.len;
398 list.* = .empty;
399 defer {
400 list.* = .{
401 .items = a.writer.buffer[0..a.writer.end],
402 .capacity = a.writer.buffer.len,
403 .pointer_stability = .{},
404 };
405 }
406 _ = streamRemaining(r, &a.writer) catch |err| switch (err) {
407 error.WriteFailed => return error.OutOfMemory,
408 error.ReadFailed => |e| return e,
409 };
410}
411
412/// Writes bytes from the internally tracked stream position to `data`.
413///
414/// Returns the number of bytes written, which will be at minimum `0` and
415/// at most the sum of each data slice length. The number of bytes read,
416/// including zero, does not indicate end of stream.
417///
418/// The reader's internal logical seek position moves forward in accordance
419/// with the number of bytes returned from this function.
420pub fn readVec(r: *Reader, data: [][]u8) Error!usize {
421 var seek = r.seek;
422 for (data, 0..) |buf, i| {
423 const contents = r.buffer[seek..r.end];
424 const copy_len = @min(contents.len, buf.len);
425 @memcpy(buf[0..copy_len], contents[0..copy_len]);
426 seek += copy_len;
427 if (buf.len - copy_len == 0) continue;
428
429 // All of `buffer` has been copied to `data`.
430 const n = seek - r.seek;
431 r.seek = seek;
432 data[i] = buf[copy_len..];
433 defer data[i] = buf;
434 return n + (r.vtable.readVec(r, data[i..]) catch |err| switch (err) {
435 error.EndOfStream => if (n == 0) return error.EndOfStream else 0,
436 error.ReadFailed => |e| return e,
437 });
438 }
439 const n = seek - r.seek;
440 r.seek = seek;
441 return n;
442}
443
444/// Writes to `Reader.buffer` or `data`, whichever has larger capacity.
445pub fn defaultReadVec(r: *Reader, data: [][]u8) Error!usize {
446 const first = data[0];
447 if (first.len >= r.buffer.len - r.end) {
448 var writer: Writer = .{
449 .buffer = first,
450 .end = 0,
451 .vtable = &.{ .drain = Writer.fixedDrain },
452 };
453 const limit: Limit = .limited(writer.buffer.len - writer.end);
454 return r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
455 error.WriteFailed => unreachable,
456 else => |e| return e,
457 };
458 }
459 var writer: Writer = .{
460 .buffer = r.buffer,
461 .end = r.end,
462 .vtable = &.{ .drain = Writer.fixedDrain },
463 };
464 const limit: Limit = .limited(writer.buffer.len - writer.end);
465 const n = r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
466 error.WriteFailed => unreachable,
467 else => |e| return e,
468 };
469 r.end += n;
470 return 0;
471}
472
473pub fn buffered(r: *Reader) []u8 {
474 return r.buffer[r.seek..r.end];
475}
476
477pub fn bufferedLen(r: *const Reader) usize {
478 return r.end - r.seek;
479}
480
481pub fn hashed(r: *Reader, hasher: anytype, buffer: []u8) Hashed(@TypeOf(hasher)) {
482 return .init(r, hasher, buffer);
483}
484
485pub fn readVecAll(r: *Reader, data: [][]u8) Error!void {
486 var index: usize = 0;
487 var truncate: usize = 0;
488 while (index < data.len) {
489 {
490 const untruncated = data[index];
491 data[index] = untruncated[truncate..];
492 defer data[index] = untruncated;
493 truncate += try r.readVec(data[index..]);
494 }
495 while (index < data.len and truncate >= data[index].len) {
496 truncate -= data[index].len;
497 index += 1;
498 }
499 }
500}
501
502/// Returns the next `n` bytes from the stream, filling the buffer as
503/// necessary.
504///
505/// Invalidates previously returned values from `peek`.
506///
507/// Asserts that the `Reader` was initialized with a buffer capacity at
508/// least as big as `n`.
509///
510/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
511/// is returned instead.
512///
513/// See also:
514/// * `toss`
515pub fn peek(r: *Reader, n: usize) Error![]u8 {
516 try r.fill(n);
517 return r.buffer[r.seek..][0..n];
518}
519
520/// Returns all the next buffered bytes, after filling the buffer to ensure it
521/// contains at least `n` bytes.
522///
523/// Invalidates previously returned values from `peek` and `peekGreedy`.
524///
525/// Asserts that the `Reader` was initialized with a buffer capacity at
526/// least as big as `n`.
527///
528/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
529/// is returned instead.
530///
531/// See also:
532/// * `peek`
533/// * `toss`
534pub fn peekGreedy(r: *Reader, n: usize) Error![]u8 {
535 try r.fill(n);
536 return r.buffer[r.seek..r.end];
537}
538
539/// Skips the next `n` bytes from the stream, advancing the seek position. This
540/// is typically and safely used after `peek`.
541///
542/// Asserts that the number of bytes buffered is at least as many as `n`.
543///
544/// The "tossed" memory remains alive until a "peek" operation occurs.
545///
546/// See also:
547/// * `peek`.
548/// * `discard`.
549pub fn toss(r: *Reader, n: usize) void {
550 r.seek += n;
551 assert(r.seek <= r.end);
552}
553
554/// Equivalent to `toss(r.bufferedLen())`.
555pub fn tossBuffered(r: *Reader) void {
556 r.seek = r.end;
557}
558
559/// Equivalent to `peek` followed by `toss`.
560///
561/// The data returned is invalidated by the next call to `take`, `peek`,
562/// `fill`, and functions with those prefixes.
563pub fn take(r: *Reader, n: usize) Error![]u8 {
564 const result = try r.peek(n);
565 r.toss(n);
566 return result;
567}
568
569/// Returns the next `n` bytes from the stream as an array, filling the buffer
570/// as necessary and advancing the seek position `n` bytes.
571///
572/// Asserts that the `Reader` was initialized with a buffer capacity at
573/// least as big as `n`.
574///
575/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
576/// is returned instead.
577///
578/// See also:
579/// * `take`
580pub fn takeArray(r: *Reader, comptime n: usize) Error!*[n]u8 {
581 return (try r.take(n))[0..n];
582}
583
584/// Returns the next `n` bytes from the stream as an array, filling the buffer
585/// as necessary, without advancing the seek position.
586///
587/// Asserts that the `Reader` was initialized with a buffer capacity at
588/// least as big as `n`.
589///
590/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
591/// is returned instead.
592///
593/// See also:
594/// * `peek`
595/// * `takeArray`
596pub fn peekArray(r: *Reader, comptime n: usize) Error!*[n]u8 {
597 return (try r.peek(n))[0..n];
598}
599
600/// Skips the next `n` bytes from the stream, advancing the seek position.
601///
602/// Unlike `toss` which is infallible, in this function `n` can be any amount.
603///
604/// Returns `error.EndOfStream` if fewer than `n` bytes could be discarded.
605///
606/// See also:
607/// * `toss`
608/// * `discardRemaining`
609/// * `discardShort`
610/// * `discard`
611pub fn discardAll(r: *Reader, n: usize) Error!void {
612 if ((try r.discardShort(n)) != n) return error.EndOfStream;
613}
614
615pub fn discardAll64(r: *Reader, n: u64) Error!void {
616 var remaining: u64 = n;
617 while (remaining > 0) {
618 const limited_remaining = std.math.cast(usize, remaining) orelse std.math.maxInt(usize);
619 try discardAll(r, limited_remaining);
620 remaining -= limited_remaining;
621 }
622}
623
624/// Skips the next `n` bytes from the stream, advancing the seek position.
625///
626/// Unlike `toss` which is infallible, in this function `n` can be any amount.
627///
628/// Returns the number of bytes discarded, which is less than `n` if and only
629/// if the stream reached the end.
630///
631/// See also:
632/// * `discardAll`
633/// * `discardRemaining`
634/// * `discard`
635pub fn discardShort(r: *Reader, n: usize) ShortError!usize {
636 const proposed_seek = r.seek + n;
637 if (proposed_seek <= r.end) {
638 @branchHint(.likely);
639 r.seek = proposed_seek;
640 return n;
641 }
642 var remaining = n - (r.end - r.seek);
643 r.seek = r.end;
644 while (true) {
645 const discard_len = r.vtable.discard(r, .limited(remaining)) catch |err| switch (err) {
646 error.EndOfStream => return n - remaining,
647 error.ReadFailed => |e| return e,
648 };
649 remaining -= discard_len;
650 if (remaining == 0) return n;
651 }
652}
653
654/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
655/// the seek position.
656///
657/// Invalidates previously returned values from `peek`.
658///
659/// If the provided buffer cannot be filled completely, `error.EndOfStream` is
660/// returned instead.
661///
662/// See also:
663/// * `peek`
664/// * `readSliceShort`
665pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
666 const n = try readSliceShort(r, buffer);
667 if (n != buffer.len) return error.EndOfStream;
668}
669
670/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
671/// the seek position.
672///
673/// Invalidates previously returned values from `peek`.
674///
675/// Returns the number of bytes read, which is less than `buffer.len` if and
676/// only if the stream reached the end.
677///
678/// See also:
679/// * `readSliceAll`
680pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
681 const contents = r.buffer[r.seek..r.end];
682 const copy_len = @min(buffer.len, contents.len);
683 @memcpy(buffer[0..copy_len], contents[0..copy_len]);
684 r.seek += copy_len;
685 if (buffer.len - copy_len == 0) {
686 @branchHint(.likely);
687 return buffer.len;
688 }
689 var i: usize = copy_len;
690 var data: [1][]u8 = undefined;
691 while (true) {
692 data[0] = buffer[i..];
693 i += readVec(r, &data) catch |err| switch (err) {
694 error.EndOfStream => return i,
695 error.ReadFailed => |e| return e,
696 };
697 if (buffer.len - i == 0) return buffer.len;
698 }
699}
700
701/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
702/// the seek position.
703///
704/// Invalidates previously returned values from `peek`.
705///
706/// If the provided buffer cannot be filled completely, `error.EndOfStream` is
707/// returned instead.
708///
709/// The function is inline to avoid the dead code in case `endian` is
710/// comptime-known and matches host endianness.
711///
712/// See also:
713/// * `readSliceAll`
714/// * `readSliceEndianAlloc`
715pub inline fn readSliceEndian(
716 r: *Reader,
717 comptime Elem: type,
718 buffer: []Elem,
719 endian: std.builtin.Endian,
720) Error!void {
721 try readSliceAll(r, @ptrCast(buffer));
722 if (native_endian != endian) std.mem.byteSwapAllElements(Elem, buffer);
723}
724
725pub const ReadAllocError = Error || Allocator.Error;
726
727/// The function is inline to avoid the dead code in case `endian` is
728/// comptime-known and matches host endianness.
729pub inline fn readSliceEndianAlloc(
730 r: *Reader,
731 allocator: Allocator,
732 comptime Elem: type,
733 len: usize,
734 endian: std.builtin.Endian,
735) ReadAllocError![]Elem {
736 const dest = try allocator.alloc(Elem, len);
737 errdefer allocator.free(dest);
738 try r.readSliceEndian(Elem, dest, endian);
739 return dest;
740}
741
742/// Shortcut for calling `readSliceAll` with a buffer provided by `allocator`.
743pub fn readAlloc(r: *Reader, allocator: Allocator, len: usize) ReadAllocError![]u8 {
744 const dest = try allocator.alloc(u8, len);
745 errdefer allocator.free(dest);
746 try readSliceAll(r, dest);
747 return dest;
748}
749
750pub const DelimiterError = error{
751 /// See the `Reader` implementation for detailed diagnostics.
752 ReadFailed,
753 /// For "inclusive" functions, stream ended before the delimiter was found.
754 /// For "exclusive" functions, stream ended and there are no more bytes to
755 /// return.
756 EndOfStream,
757 /// The delimiter was not found within a number of bytes matching the
758 /// capacity of the `Reader`.
759 StreamTooLong,
760};
761
762/// Returns a slice of the next bytes of buffered data from the stream until
763/// `sentinel` is found, advancing the seek position past the sentinel.
764///
765/// Returned slice has a sentinel.
766///
767/// Invalidates previously returned values from `peek`.
768///
769/// See also:
770/// * `peekSentinel`
771/// * `takeDelimiterExclusive`
772/// * `takeDelimiterInclusive`
773pub fn takeSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel]u8 {
774 const result = try r.peekSentinel(sentinel);
775 r.toss(result.len + 1);
776 return result;
777}
778
779/// Returns a slice of the next bytes of buffered data from the stream until
780/// `sentinel` is found, without advancing the seek position.
781///
782/// Returned slice has a sentinel; end of stream does not count as a delimiter.
783///
784/// Invalidates previously returned values from `peek`.
785///
786/// See also:
787/// * `takeSentinel`
788/// * `peekDelimiterExclusive`
789/// * `peekDelimiterInclusive`
790pub fn peekSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel]u8 {
791 const result = try r.peekDelimiterInclusive(sentinel);
792 return result[0 .. result.len - 1 :sentinel];
793}
794
795/// Returns a slice of the next bytes of buffered data from the stream until
796/// `delimiter` is found, advancing the seek position past the delimiter.
797///
798/// Returned slice includes the delimiter as the last byte.
799///
800/// Invalidates previously returned values from `peek`.
801///
802/// See also:
803/// * `takeSentinel`
804/// * `takeDelimiterExclusive`
805/// * `peekDelimiterInclusive`
806pub fn takeDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
807 const result = try r.peekDelimiterInclusive(delimiter);
808 r.toss(result.len);
809 return result;
810}
811
812/// Returns a slice of the next bytes of buffered data from the stream until
813/// `delimiter` is found, without advancing the seek position.
814///
815/// Returned slice includes the delimiter as the last byte.
816///
817/// Invalidates previously returned values from `peek`.
818///
819/// See also:
820/// * `peekSentinel`
821/// * `peekDelimiterExclusive`
822/// * `takeDelimiterInclusive`
823pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
824 {
825 const contents = r.buffer[0..r.end];
826 const seek = r.seek;
827 if (std.mem.findScalarPos(u8, contents, seek, delimiter)) |end| {
828 @branchHint(.likely);
829 return contents[seek .. end + 1];
830 }
831 }
832 while (true) {
833 const content_len = r.end - r.seek;
834 if (r.buffer.len - content_len == 0) break;
835 try fillMore(r);
836 const seek = r.seek;
837 const contents = r.buffer[0..r.end];
838 if (std.mem.findScalarPos(u8, contents, seek + content_len, delimiter)) |end| {
839 return contents[seek .. end + 1];
840 }
841 }
842 // It might or might not be end of stream. There is no more buffer space
843 // left to disambiguate. If `StreamTooLong` was added to `RebaseError` then
844 // this logic could be replaced by removing the exit condition from the
845 // above while loop. That error code would represent when `buffer` capacity
846 // is too small for an operation, replacing the current use of asserts.
847 var failing_writer = Writer.failing;
848 while (r.vtable.stream(r, &failing_writer, .limited(1))) |n| {
849 assert(n == 0);
850 } else |err| switch (err) {
851 error.WriteFailed => return error.StreamTooLong,
852 error.ReadFailed => |e| return e,
853 error.EndOfStream => |e| return e,
854 }
855}
856
857/// Returns a slice of the next bytes of buffered data from the stream until
858/// `delimiter` is found, advancing the seek position up to (but not past)
859/// the delimiter.
860///
861/// Returned slice excludes the delimiter. End-of-stream is treated equivalent
862/// to a delimiter, unless it would result in a length 0 return value, in which
863/// case `error.EndOfStream` is returned instead.
864///
865/// If the delimiter is not found within a number of bytes matching the
866/// capacity of this `Reader`, `error.StreamTooLong` is returned. In
867/// such case, the stream state is unmodified as if this function was never
868/// called.
869///
870/// Invalidates previously returned values from `peek`.
871///
872/// See also:
873/// * `takeDelimiter`
874/// * `takeDelimiterInclusive`
875/// * `peekDelimiterExclusive`
876pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
877 const result = try r.peekDelimiterExclusive(delimiter);
878 r.toss(result.len);
879 return result;
880}
881
882/// Returns a slice of the next bytes of buffered data from the stream until
883/// `delimiter` is found, advancing the seek position past the delimiter.
884///
885/// Returned slice excludes the delimiter. End-of-stream is treated equivalent
886/// to a delimiter, unless it would result in a length 0 return value, in which
887/// case `null` is returned instead.
888///
889/// If the delimiter is not found within a number of bytes matching the
890/// capacity of this `Reader`, `error.StreamTooLong` is returned. In
891/// such case, the stream state is unmodified as if this function was never
892/// called.
893///
894/// Invalidates previously returned values from `peek`.
895///
896/// See also:
897/// * `takeDelimiterInclusive`
898/// * `takeDelimiterExclusive`
899pub fn takeDelimiter(r: *Reader, delimiter: u8) error{ ReadFailed, StreamTooLong }!?[]u8 {
900 const inclusive = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {
901 error.EndOfStream => {
902 const remaining = r.buffer[r.seek..r.end];
903 if (remaining.len == 0) return null;
904 r.toss(remaining.len);
905 return remaining;
906 },
907 else => |e| return e,
908 };
909 r.toss(inclusive.len);
910 return inclusive[0 .. inclusive.len - 1];
911}
912
913/// Returns a slice of the next bytes of buffered data from the stream until
914/// `delimiter` is found, without advancing the seek position.
915///
916/// Returned slice excludes the delimiter. End-of-stream is treated equivalent
917/// to a delimiter, unless it would result in a length 0 return value, in which
918/// case `error.EndOfStream` is returned instead.
919///
920/// If the delimiter is not found within a number of bytes matching the
921/// capacity of this `Reader`, `error.StreamTooLong` is returned. In
922/// such case, the stream state is unmodified as if this function was never
923/// called.
924///
925/// Invalidates previously returned values from `peek`.
926///
927/// See also:
928/// * `peekDelimiterInclusive`
929/// * `takeDelimiterExclusive`
930pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
931 const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {
932 error.EndOfStream => {
933 const remaining = r.buffer[r.seek..r.end];
934 if (remaining.len == 0) return error.EndOfStream;
935 return remaining;
936 },
937 else => |e| return e,
938 };
939 return result[0 .. result.len - 1];
940}
941
942/// Appends to `w` contents by reading from the stream until `delimiter` is
943/// found. Does not write the delimiter itself.
944///
945/// Does not discard the delimiter from the `Reader`.
946///
947/// Returns number of bytes streamed, which may be zero, or error.EndOfStream
948/// if the delimiter was not found.
949///
950/// Asserts buffer capacity of at least one. This function performs better with
951/// larger buffers.
952///
953/// See also:
954/// * `streamDelimiterEnding`
955/// * `streamDelimiterLimit`
956pub fn streamDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize {
957 const n = streamDelimiterLimit(r, w, delimiter, .unlimited) catch |err| switch (err) {
958 error.StreamTooLong => unreachable, // unlimited is passed
959 else => |e| return e,
960 };
961 if (r.seek == r.end) return error.EndOfStream;
962 return n;
963}
964
965/// Appends to `w` contents by reading from the stream until `delimiter` is found.
966/// Does not write the delimiter itself.
967///
968/// Returns number of bytes streamed, which may be zero. If the stream reaches
969/// the end, the reader buffer will be empty when this function returns.
970/// Otherwise, it will have at least one byte buffered, starting with the
971/// delimiter.
972///
973/// Asserts buffer capacity of at least one. This function performs better with
974/// larger buffers.
975///
976/// See also:
977/// * `streamDelimiter`
978/// * `streamDelimiterLimit`
979pub fn streamDelimiterEnding(
980 r: *Reader,
981 w: *Writer,
982 delimiter: u8,
983) StreamRemainingError!usize {
984 return streamDelimiterLimit(r, w, delimiter, .unlimited) catch |err| switch (err) {
985 error.StreamTooLong => unreachable, // unlimited is passed
986 else => |e| return e,
987 };
988}
989
990pub const StreamDelimiterLimitError = error{
991 ReadFailed,
992 WriteFailed,
993 /// The delimiter was not found within the limit.
994 StreamTooLong,
995};
996
997/// Appends to `w` contents by reading from the stream until `delimiter` is found.
998/// Does not write the delimiter itself.
999///
1000/// Does not discard the delimiter from the `Reader`.
1001///
1002/// Returns number of bytes streamed, which may be zero. End of stream can be
1003/// detected by checking if the next byte in the stream is the delimiter.
1004///
1005/// Asserts buffer capacity of at least one. This function performs better with
1006/// larger buffers.
1007pub fn streamDelimiterLimit(
1008 r: *Reader,
1009 w: *Writer,
1010 delimiter: u8,
1011 limit: Limit,
1012) StreamDelimiterLimitError!usize {
1013 var remaining = @backingInt(limit);
1014 while (remaining != 0) {
1015 const available = Limit.limited(remaining).slice(r.peekGreedy(1) catch |err| switch (err) {
1016 error.ReadFailed => |e| return e,
1017 error.EndOfStream => return @backingInt(limit) - remaining,
1018 });
1019 if (std.mem.findScalar(u8, available, delimiter)) |delimiter_index| {
1020 try w.writeAll(available[0..delimiter_index]);
1021 r.toss(delimiter_index);
1022 remaining -= delimiter_index;
1023 return @backingInt(limit) - remaining;
1024 }
1025 try w.writeAll(available);
1026 r.toss(available.len);
1027 remaining -= available.len;
1028 }
1029 return error.StreamTooLong;
1030}
1031
1032/// Reads from the stream until specified byte is found, discarding all data,
1033/// including the delimiter.
1034///
1035/// Returns number of bytes discarded, or `error.EndOfStream` if the delimiter
1036/// is not found.
1037///
1038/// See also:
1039/// * `discardDelimiterExclusive`
1040/// * `discardDelimiterLimit`
1041pub fn discardDelimiterInclusive(r: *Reader, delimiter: u8) Error!usize {
1042 const n = discardDelimiterLimit(r, delimiter, .unlimited) catch |err| switch (err) {
1043 error.StreamTooLong => unreachable, // unlimited is passed
1044 else => |e| return e,
1045 };
1046 if (r.seek == r.end) return error.EndOfStream;
1047 assert(r.buffer[r.seek] == delimiter);
1048 toss(r, 1);
1049 return n + 1;
1050}
1051
1052/// Reads from the stream until specified byte is found, discarding all data,
1053/// excluding the delimiter.
1054///
1055/// Returns the number of bytes discarded.
1056///
1057/// Succeeds if stream ends before delimiter found. End of stream can be
1058/// detected by checking if the delimiter is buffered.
1059///
1060/// See also:
1061/// * `discardDelimiterInclusive`
1062/// * `discardDelimiterLimit`
1063pub fn discardDelimiterExclusive(r: *Reader, delimiter: u8) ShortError!usize {
1064 return discardDelimiterLimit(r, delimiter, .unlimited) catch |err| switch (err) {
1065 error.StreamTooLong => unreachable, // unlimited is passed
1066 else => |e| return e,
1067 };
1068}
1069
1070pub const DiscardDelimiterLimitError = error{
1071 ReadFailed,
1072 /// The delimiter was not found within the limit.
1073 StreamTooLong,
1074};
1075
1076/// Reads from the stream until specified byte is found, discarding all data,
1077/// excluding the delimiter.
1078///
1079/// Returns the number of bytes discarded.
1080///
1081/// Succeeds if stream ends before delimiter found. End of stream can be
1082/// detected by checking if the delimiter is buffered.
1083pub fn discardDelimiterLimit(r: *Reader, delimiter: u8, limit: Limit) DiscardDelimiterLimitError!usize {
1084 var remaining = @backingInt(limit);
1085 while (remaining != 0) {
1086 const available = Limit.limited(remaining).slice(r.peekGreedy(1) catch |err| switch (err) {
1087 error.ReadFailed => |e| return e,
1088 error.EndOfStream => return @backingInt(limit) - remaining,
1089 });
1090 if (std.mem.findScalar(u8, available, delimiter)) |delimiter_index| {
1091 r.toss(delimiter_index);
1092 remaining -= delimiter_index;
1093 return @backingInt(limit) - remaining;
1094 }
1095 r.toss(available.len);
1096 remaining -= available.len;
1097 }
1098 return error.StreamTooLong;
1099}
1100
1101/// Fills the buffer such that it contains at least `n` bytes, without
1102/// advancing the seek position.
1103///
1104/// Returns `error.EndOfStream` if and only if there are fewer than `n` bytes
1105/// remaining.
1106///
1107/// If the end of stream is not encountered, asserts buffer capacity is at
1108/// least `n`.
1109pub fn fill(r: *Reader, n: usize) Error!void {
1110 if (r.seek + n <= r.end) {
1111 @branchHint(.likely);
1112 return;
1113 }
1114 return fillUnbuffered(r, n);
1115}
1116
1117/// This internal function is separated from `fill` to encourage optimizers to inline `fill`, hence
1118/// propagating its `@branchHint` to usage sites. If these functions are combined, `fill` is large
1119/// enough that LLVM is reluctant to inline it, forcing usages of APIs like `takeInt` to go through
1120/// an expensive runtime function call just to figure out that the data is, in fact, already in the
1121/// buffer.
1122///
1123/// Missing this optimization can result in wall-clock time for the most affected benchmarks
1124/// increasing by a factor of 5 or more.
1125fn fillUnbuffered(r: *Reader, n: usize) Error!void {
1126 try rebase(r, n);
1127 var bufs: [1][]u8 = .{""};
1128 while (r.end < r.seek + n) _ = try r.vtable.readVec(r, &bufs);
1129}
1130
1131/// Without advancing the seek position, does exactly one underlying read, filling the buffer as
1132/// much as possible. This may result in zero bytes added to the buffer, which is not an end of
1133/// stream condition. End of stream is communicated via returning `error.EndOfStream`.
1134///
1135/// Asserts buffer capacity is at least 1.
1136pub fn fillMore(r: *Reader) Error!void {
1137 try rebase(r, r.end - r.seek + 1);
1138 var bufs: [1][]u8 = .{""};
1139 _ = try r.vtable.readVec(r, &bufs);
1140}
1141
1142/// Returns the next byte from the stream or returns `error.EndOfStream`.
1143///
1144/// Does not advance the seek position.
1145///
1146/// Asserts the buffer capacity is nonzero.
1147pub fn peekByte(r: *Reader) Error!u8 {
1148 const buffer = r.buffer[0..r.end];
1149 const seek = r.seek;
1150 if (seek < buffer.len) {
1151 @branchHint(.likely);
1152 return buffer[seek];
1153 }
1154 try fill(r, 1);
1155 return r.buffer[r.seek];
1156}
1157
1158/// Reads 1 byte from the stream or returns `error.EndOfStream`.
1159///
1160/// Asserts the buffer capacity is nonzero.
1161pub fn takeByte(r: *Reader) Error!u8 {
1162 const result = try peekByte(r);
1163 r.seek += 1;
1164 return result;
1165}
1166
1167/// Same as `takeByte` except the returned byte is signed.
1168pub fn takeByteSigned(r: *Reader) Error!i8 {
1169 return @bitCast(try r.takeByte());
1170}
1171
1172/// Asserts the buffer was initialized with a capacity at least `@bitSizeOf(T) / 8`.
1173pub inline fn takeInt(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1174 const n = @divExact(@typeInfo(T).int.bits, 8);
1175 return std.mem.readInt(T, try r.takeArray(n), endian);
1176}
1177
1178/// Asserts the buffer was initialized with a capacity at least `@bitSizeOf(T) / 8`.
1179pub inline fn peekInt(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1180 const n = @divExact(@typeInfo(T).int.bits, 8);
1181 return std.mem.readInt(T, try r.peekArray(n), endian);
1182}
1183
1184/// Asserts the buffer was initialized with a capacity at least `n`.
1185pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n: usize) Error!Int {
1186 assert(n <= @sizeOf(Int));
1187 return std.mem.readVarInt(Int, try r.take(n), endian);
1188}
1189
1190/// Obtains an unaligned pointer to the beginning of the stream, reinterpreted
1191/// as a pointer to the provided type, advancing the seek position.
1192///
1193/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1194///
1195/// See also:
1196/// * `peekStructPointer`
1197/// * `takeStruct`
1198pub fn takeStructPointer(r: *Reader, comptime T: type) Error!*align(1) T {
1199 // Only extern and packed structs have defined in-memory layout.
1200 comptime assert(@typeInfo(T).@"struct".layout != .auto);
1201 return @ptrCast(try r.takeArray(@sizeOf(T)));
1202}
1203
1204/// Obtains an unaligned pointer to the beginning of the stream, reinterpreted
1205/// as a pointer to the provided type, without advancing the seek position.
1206///
1207/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1208///
1209/// See also:
1210/// * `takeStructPointer`
1211/// * `peekStruct`
1212pub fn peekStructPointer(r: *Reader, comptime T: type) Error!*align(1) T {
1213 // Only extern and packed structs have defined in-memory layout.
1214 comptime assert(@typeInfo(T).@"struct".layout != .auto);
1215 return @ptrCast(try r.peekArray(@sizeOf(T)));
1216}
1217
1218/// This function is inline to avoid referencing `std.mem.byteSwapAllFields`
1219/// when `endian` is comptime-known and matches the host endianness.
1220///
1221/// See also:
1222/// * `takeStructPointer`
1223/// * `peekStruct`
1224pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1225 switch (@typeInfo(T)) {
1226 .@"struct" => |info| switch (info.layout) {
1227 .auto => @compileError("ill-defined memory layout"),
1228 .@"extern" => {
1229 var res: T = undefined;
1230 try r.readSliceEndian(T, (&res)[0..1], endian);
1231 return res;
1232 },
1233 .@"packed" => {
1234 return @bitCast(try takeInt(r, info.backing_integer.?, endian));
1235 },
1236 },
1237 else => @compileError("not a struct"),
1238 }
1239}
1240
1241/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1242///
1243/// This function is inline to avoid referencing `std.mem.byteSwapAllFields`
1244/// when `endian` is comptime-known and matches the host endianness.
1245///
1246/// See also:
1247/// * `takeStruct`
1248/// * `peekStructPointer`
1249pub inline fn peekStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1250 switch (@typeInfo(T)) {
1251 .@"struct" => |info| switch (info.layout) {
1252 .auto => @compileError("ill-defined memory layout"),
1253 .@"extern" => {
1254 var res = (try r.peekStructPointer(T)).*;
1255 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
1256 return res;
1257 },
1258 .@"packed" => {
1259 return @bitCast(try peekInt(r, info.backing_integer.?, endian));
1260 },
1261 },
1262 else => @compileError("not a struct"),
1263 }
1264}
1265
1266pub const TakeEnumError = Error || error{InvalidEnumTag};
1267
1268/// Reads an integer with the same size as the given enum's tag type. If the
1269/// integer matches an enum tag, casts the integer to the enum tag and returns
1270/// it. Otherwise, returns `error.InvalidEnumTag`.
1271///
1272/// Asserts the buffer was initialized with a capacity at least `@sizeOf(Enum)`.
1273pub fn takeEnum(r: *Reader, comptime Enum: type, endian: std.builtin.Endian) TakeEnumError!Enum {
1274 const Tag = @typeInfo(Enum).@"enum".tag_type;
1275 const int = try r.takeInt(Tag, endian);
1276 return std.enums.fromInt(Enum, int) orelse return error.InvalidEnumTag;
1277}
1278
1279/// Reads an integer with the same size as the given nonexhaustive enum's tag type.
1280///
1281/// Asserts the buffer was initialized with a capacity at least `@sizeOf(Enum)`.
1282pub fn takeEnumNonexhaustive(r: *Reader, comptime Enum: type, endian: std.builtin.Endian) Error!Enum {
1283 const info = @typeInfo(Enum).@"enum";
1284 comptime assert(info.mode != .exhaustive);
1285 comptime assert(@bitSizeOf(info.tag_type) == @sizeOf(info.tag_type) * 8);
1286 return takeEnum(r, Enum, endian) catch |err| switch (err) {
1287 error.InvalidEnumTag => unreachable,
1288 else => |e| return e,
1289 };
1290}
1291
1292pub const TakeLeb128Error = Error || error{Overflow};
1293
1294/// Read a single LEB128 value as type T, or `error.Overflow` if the value cannot fit.
1295pub fn takeLeb128(r: *Reader, comptime T: type) TakeLeb128Error!T {
1296 const info = switch (@typeInfo(T)) {
1297 .int => |info| info,
1298 else => @compileError(@typeName(T) ++ " not supported"),
1299 };
1300 const Byte = packed struct { bits: u7, more: bool };
1301
1302 if (info.bits <= 7) {
1303 var byte: Byte = undefined;
1304 const Bits = @Int(info.signedness, 7);
1305
1306 byte = @bitCast(try r.takeByte());
1307 const val = std.math.cast(T, @as(Bits, @bitCast(byte.bits))) orelse error.Overflow;
1308
1309 const allowed_bits: u7 = switch (info.signedness) {
1310 .unsigned => 0,
1311 .signed => @bitCast(@as(i7, @bitCast(byte.bits)) >> 6),
1312 };
1313
1314 var fits = true;
1315 while (byte.more) {
1316 byte = @bitCast(try r.takeByte());
1317
1318 if (byte.bits != allowed_bits) fits = false;
1319 }
1320
1321 return if (fits) blk: {
1322 @branchHint(.likely);
1323 break :blk val;
1324 } else error.Overflow;
1325 }
1326
1327 const Unsigned = @Int(.unsigned, info.bits);
1328 const UInt = std.math.ByteAlignedInt(Unsigned);
1329 const Int = std.math.ByteAlignedInt(T);
1330
1331 const uint_bits = @typeInfo(UInt).int.bits;
1332
1333 var byte: Byte = undefined;
1334 var val: UInt = 0;
1335 const max_bytes = @divFloor(info.bits - 1, 7) + 1;
1336 inline for (0..max_bytes) |iteration| {
1337 const shift = iteration * 7;
1338
1339 byte = @bitCast(try r.takeByte());
1340
1341 const extended: UInt = byte.bits;
1342 val |= extended << shift;
1343
1344 const bits_written = shift + 7;
1345
1346 if (bits_written >= info.bits) {
1347 const bits_overflowed = bits_written - info.bits;
1348 const bits_remaining = @mod(info.bits, 7);
1349
1350 const allowed_bits: u7, var fits: bool = switch (info.signedness) {
1351 .unsigned => blk: {
1352 const fits = bits_remaining == 0 or byte.bits >> bits_remaining == 0;
1353
1354 break :blk .{ 0, fits };
1355 },
1356 .signed => blk: {
1357 const bits: i7 = @bitCast(byte.bits);
1358
1359 // Move the sign bit into the MSB
1360 const shifted_bits: i7 = bits << bits_overflowed;
1361
1362 const value_sign: i7 = shifted_bits >> 6; // sign extends
1363 const bits_sign: i7 = bits >> bits_remaining; // sign extends
1364
1365 const fits = bits_remaining == 0 or bits_sign == value_sign;
1366
1367 if (uint_bits != info.bits and value_sign != 0) {
1368 const sign_extend_mask = @as(UInt, std.math.maxInt(UInt)) << info.bits;
1369 val |= sign_extend_mask;
1370 }
1371
1372 break :blk .{ @bitCast(value_sign), fits };
1373 },
1374 };
1375
1376 switch (info.signedness) {
1377 .signed => assert(allowed_bits == 0 or allowed_bits == 0x7F),
1378 .unsigned => comptime assert(allowed_bits == 0),
1379 }
1380
1381 while (byte.more) {
1382 byte = @bitCast(try r.takeByte());
1383 if (byte.bits != allowed_bits) fits = false;
1384 }
1385
1386 return if (fits) blk: {
1387 @branchHint(.likely);
1388 break :blk std.math.cast(T, @as(Int, @bitCast(val))) orelse error.Overflow;
1389 } else error.Overflow;
1390 }
1391
1392 comptime assert(bits_written < info.bits);
1393 if (!byte.more) {
1394 if (info.signedness == .signed and // can be negative
1395 byte.bits & 0x40 != 0) // is negative
1396 {
1397 const sign_extend_mask = @as(UInt, std.math.maxInt(UInt)) << bits_written;
1398 val |= sign_extend_mask;
1399 }
1400 return std.math.cast(T, @as(Int, @bitCast(val))) orelse error.Overflow;
1401 }
1402 }
1403}
1404
1405/// Ensures `capacity` data can be buffered without rebasing.
1406pub fn rebase(r: *Reader, capacity: usize) Error!void {
1407 if (r.buffer.len - r.seek >= capacity) {
1408 @branchHint(.likely);
1409 return;
1410 }
1411 return r.vtable.rebase(r, capacity);
1412}
1413
1414pub fn defaultRebase(r: *Reader, capacity: usize) Error!void {
1415 assert(r.buffer.len - r.seek < capacity);
1416 const data = r.buffer[r.seek..r.end];
1417 @memmove(r.buffer[0..data.len], data);
1418 r.seek = 0;
1419 r.end = data.len;
1420 assert(r.buffer.len - r.seek >= capacity);
1421}
1422
1423test fixed {
1424 var r: Reader = .fixed("a\x02");
1425 try testing.expect((try r.takeByte()) == 'a');
1426 try testing.expect((try r.takeEnum(enum(u8) {
1427 a = 0,
1428 b = 99,
1429 c = 2,
1430 d = 3,
1431 }, builtin.cpu.arch.endian())) == .c);
1432 try testing.expectError(error.EndOfStream, r.takeByte());
1433}
1434
1435test peek {
1436 var r: Reader = .fixed("abc");
1437 try testing.expectEqualStrings("ab", try r.peek(2));
1438 try testing.expectEqualStrings("a", try r.peek(1));
1439}
1440
1441test peekGreedy {
1442 var r: Reader = .fixed("abc");
1443 try testing.expectEqualStrings("abc", try r.peekGreedy(1));
1444}
1445
1446test toss {
1447 var r: Reader = .fixed("abc");
1448 r.toss(1);
1449 try testing.expectEqualStrings("bc", r.buffered());
1450}
1451
1452test take {
1453 var r: Reader = .fixed("abc");
1454 try testing.expectEqualStrings("ab", try r.take(2));
1455 try testing.expectEqualStrings("c", try r.take(1));
1456}
1457
1458test takeArray {
1459 var r: Reader = .fixed("abc");
1460 try testing.expectEqualStrings("ab", try r.takeArray(2));
1461 try testing.expectEqualStrings("c", try r.takeArray(1));
1462}
1463
1464test peekArray {
1465 var r: Reader = .fixed("abc");
1466 try testing.expectEqualStrings("ab", try r.peekArray(2));
1467 try testing.expectEqualStrings("a", try r.peekArray(1));
1468}
1469
1470test discardAll {
1471 var r: Reader = .fixed("foobar");
1472 try r.discardAll(3);
1473 try testing.expectEqualStrings("bar", try r.take(3));
1474 try r.discardAll(0);
1475 try testing.expectError(error.EndOfStream, r.discardAll(1));
1476}
1477
1478test discardRemaining {
1479 var r: Reader = .fixed("foobar");
1480 r.toss(1);
1481 try testing.expectEqual(5, try r.discardRemaining());
1482 try testing.expectEqual(0, try r.discardRemaining());
1483}
1484
1485test stream {
1486 var out_buffer: [10]u8 = undefined;
1487 var r: Reader = .fixed("foobar");
1488 var w: Writer = .fixed(&out_buffer);
1489 // Short streams are possible with this function but not with fixed.
1490 try testing.expectEqual(2, try r.stream(&w, .limited(2)));
1491 try testing.expectEqualStrings("fo", w.buffered());
1492 try testing.expectEqual(4, try r.stream(&w, .unlimited));
1493 try testing.expectEqualStrings("foobar", w.buffered());
1494}
1495
1496test takeSentinel {
1497 var r: Reader = .fixed("ab\nc");
1498 try testing.expectEqualStrings("ab", try r.takeSentinel('\n'));
1499 try testing.expectError(error.EndOfStream, r.takeSentinel('\n'));
1500 try testing.expectEqualStrings("c", try r.peek(1));
1501}
1502
1503test peekSentinel {
1504 var r: Reader = .fixed("ab\nc");
1505 try testing.expectEqualStrings("ab", try r.peekSentinel('\n'));
1506 try testing.expectEqualStrings("ab", try r.peekSentinel('\n'));
1507 r.toss(3);
1508 try testing.expectError(error.EndOfStream, r.peekSentinel('\n'));
1509 try testing.expectEqualStrings("c", try r.peek(1));
1510}
1511
1512test takeDelimiterInclusive {
1513 var r: Reader = .fixed("ab\nc");
1514 try testing.expectEqualStrings("ab\n", try r.takeDelimiterInclusive('\n'));
1515 try testing.expectError(error.EndOfStream, r.takeDelimiterInclusive('\n'));
1516}
1517
1518test peekDelimiterInclusive {
1519 var r: Reader = .fixed("ab\nc");
1520 try testing.expectEqualStrings("ab\n", try r.peekDelimiterInclusive('\n'));
1521 try testing.expectEqualStrings("ab\n", try r.peekDelimiterInclusive('\n'));
1522 r.toss(3);
1523 try testing.expectError(error.EndOfStream, r.peekDelimiterInclusive('\n'));
1524 try testing.expectEqualStrings("c", try r.peek(1));
1525}
1526
1527test takeDelimiterExclusive {
1528 var r: Reader = .fixed("ab\nc");
1529
1530 try testing.expectEqualStrings("ab", try r.takeDelimiterExclusive('\n'));
1531 try testing.expectEqualStrings("", try r.takeDelimiterExclusive('\n'));
1532 try testing.expectEqualStrings("", try r.takeDelimiterExclusive('\n'));
1533 try testing.expectEqualStrings("\n", try r.take(1));
1534
1535 try testing.expectEqualStrings("c", try r.takeDelimiterExclusive('\n'));
1536 try testing.expectError(error.EndOfStream, r.takeDelimiterExclusive('\n'));
1537}
1538
1539test peekDelimiterExclusive {
1540 var r: Reader = .fixed("ab\nc");
1541
1542 try testing.expectEqualStrings("ab", try r.peekDelimiterExclusive('\n'));
1543 try testing.expectEqualStrings("ab", try r.peekDelimiterExclusive('\n'));
1544 r.toss(2);
1545 try testing.expectEqualStrings("", try r.peekDelimiterExclusive('\n'));
1546 try testing.expectEqualStrings("\n", try r.take(1));
1547
1548 try testing.expectEqualStrings("c", try r.peekDelimiterExclusive('\n'));
1549 try testing.expectEqualStrings("c", try r.peekDelimiterExclusive('\n'));
1550 r.toss(1);
1551 try testing.expectError(error.EndOfStream, r.peekDelimiterExclusive('\n'));
1552}
1553
1554test takeDelimiter {
1555 var r: Reader = .fixed("ab\nc\n\nd");
1556 try testing.expectEqualStrings("ab", (try r.takeDelimiter('\n')).?);
1557 try testing.expectEqualStrings("c", (try r.takeDelimiter('\n')).?);
1558 try testing.expectEqualStrings("", (try r.takeDelimiter('\n')).?);
1559 try testing.expectEqualStrings("d", (try r.takeDelimiter('\n')).?);
1560 try testing.expectEqual(null, try r.takeDelimiter('\n'));
1561 try testing.expectEqual(null, try r.takeDelimiter('\n'));
1562
1563 r = .fixed("ab\nc\n\nd\n"); // one trailing newline does not affect behavior
1564 try testing.expectEqualStrings("ab", (try r.takeDelimiter('\n')).?);
1565 try testing.expectEqualStrings("c", (try r.takeDelimiter('\n')).?);
1566 try testing.expectEqualStrings("", (try r.takeDelimiter('\n')).?);
1567 try testing.expectEqualStrings("d", (try r.takeDelimiter('\n')).?);
1568 try testing.expectEqual(null, try r.takeDelimiter('\n'));
1569 try testing.expectEqual(null, try r.takeDelimiter('\n'));
1570}
1571
1572test streamDelimiter {
1573 var out_buffer: [10]u8 = undefined;
1574 var r: Reader = .fixed("foo\nbars");
1575 var w: Writer = .fixed(&out_buffer);
1576 try testing.expectEqual(3, try r.streamDelimiter(&w, '\n'));
1577 try testing.expectEqualStrings("foo", w.buffered());
1578 try testing.expectEqual(0, try r.streamDelimiter(&w, '\n'));
1579 r.toss(1);
1580 try testing.expectError(error.EndOfStream, r.streamDelimiter(&w, '\n'));
1581}
1582
1583test streamDelimiterEnding {
1584 var out_buffer: [10]u8 = undefined;
1585 var r: Reader = .fixed("foo\nbars");
1586 var w: Writer = .fixed(&out_buffer);
1587 try testing.expectEqual(3, try r.streamDelimiterEnding(&w, '\n'));
1588 try testing.expectEqualStrings("foo", w.buffered());
1589 r.toss(1);
1590 try testing.expectEqual(4, try r.streamDelimiterEnding(&w, '\n'));
1591 try testing.expectEqualStrings("foobars", w.buffered());
1592 try testing.expectEqual(0, try r.streamDelimiterEnding(&w, '\n'));
1593 try testing.expectEqual(0, try r.streamDelimiterEnding(&w, '\n'));
1594}
1595
1596test streamDelimiterLimit {
1597 var out_buffer: [10]u8 = undefined;
1598 var r: Reader = .fixed("foo\nbars");
1599 var w: Writer = .fixed(&out_buffer);
1600 try testing.expectError(error.StreamTooLong, r.streamDelimiterLimit(&w, '\n', .limited(2)));
1601 try testing.expectEqual(1, try r.streamDelimiterLimit(&w, '\n', .limited(3)));
1602 try testing.expectEqualStrings("\n", try r.take(1));
1603 try testing.expectEqual(4, try r.streamDelimiterLimit(&w, '\n', .unlimited));
1604 try testing.expectEqualStrings("foobars", w.buffered());
1605}
1606
1607test discardDelimiterExclusive {
1608 var r: Reader = .fixed("foob\nar");
1609 try testing.expectEqual(4, try r.discardDelimiterExclusive('\n'));
1610 try testing.expectEqualStrings("\n", try r.take(1));
1611 try testing.expectEqual(2, try r.discardDelimiterExclusive('\n'));
1612 try testing.expectEqual(0, try r.discardDelimiterExclusive('\n'));
1613}
1614
1615test discardDelimiterInclusive {
1616 var r: Reader = .fixed("foob\nar");
1617 try testing.expectEqual(5, try r.discardDelimiterInclusive('\n'));
1618 try testing.expectError(error.EndOfStream, r.discardDelimiterInclusive('\n'));
1619}
1620
1621test discardDelimiterLimit {
1622 var r: Reader = .fixed("foob\nar");
1623 try testing.expectError(error.StreamTooLong, r.discardDelimiterLimit('\n', .limited(4)));
1624 try testing.expectEqual(0, try r.discardDelimiterLimit('\n', .limited(2)));
1625 try testing.expectEqualStrings("\n", try r.take(1));
1626 try testing.expectEqual(2, try r.discardDelimiterLimit('\n', .unlimited));
1627 try testing.expectEqual(0, try r.discardDelimiterLimit('\n', .unlimited));
1628}
1629
1630test fill {
1631 var r: Reader = .fixed("abc");
1632 try r.fill(1);
1633 try r.fill(3);
1634}
1635
1636test takeByte {
1637 var r: Reader = .fixed("ab");
1638 try testing.expectEqual('a', try r.takeByte());
1639 try testing.expectEqual('b', try r.takeByte());
1640 try testing.expectError(error.EndOfStream, r.takeByte());
1641}
1642
1643test takeByteSigned {
1644 var r: Reader = .fixed(&.{ 255, 5 });
1645 try testing.expectEqual(-1, try r.takeByteSigned());
1646 try testing.expectEqual(5, try r.takeByteSigned());
1647 try testing.expectError(error.EndOfStream, r.takeByteSigned());
1648}
1649
1650test takeInt {
1651 var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 });
1652 try testing.expectEqual(0x1234, try r.takeInt(u16, .big));
1653 try testing.expectError(error.EndOfStream, r.takeInt(u16, .little));
1654}
1655
1656test takeVarInt {
1657 var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 });
1658 try testing.expectEqual(0x123456, try r.takeVarInt(u64, .big, 3));
1659 try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));
1660}
1661
1662test takeStructPointer {
1663 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1664 const S = extern struct { a: u8, b: u16 };
1665 switch (native_endian) {
1666 .little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStructPointer(S)).*),
1667 .big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStructPointer(S)).*),
1668 }
1669 try testing.expectError(error.EndOfStream, r.takeStructPointer(S));
1670}
1671
1672test peekStructPointer {
1673 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1674 const S = extern struct { a: u8, b: u16 };
1675 switch (native_endian) {
1676 .little => {
1677 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructPointer(S)).*);
1678 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructPointer(S)).*);
1679 },
1680 .big => {
1681 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructPointer(S)).*);
1682 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructPointer(S)).*);
1683 },
1684 }
1685}
1686
1687test takeStruct {
1688 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1689 const S = extern struct { a: u8, b: u16 };
1690 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.takeStruct(S, .big));
1691 try testing.expectError(error.EndOfStream, r.takeStruct(S, .little));
1692}
1693
1694test peekStruct {
1695 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1696 const S = extern struct { a: u8, b: u16 };
1697 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.peekStruct(S, .big));
1698 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), try r.peekStruct(S, .little));
1699}
1700
1701test takeEnum {
1702 var r: Reader = .fixed(&.{ 2, 0, 1 });
1703 const E1 = enum(u8) { a, b, c };
1704 const E2 = enum(u16) { _ };
1705 try testing.expectEqual(E1.c, try r.takeEnum(E1, .little));
1706 try testing.expectEqual(@as(E2, @fromBackingInt(@intCast(0x0001))), try r.takeEnum(E2, .big));
1707}
1708
1709test readSliceShort {
1710 var r: Reader = .fixed("HelloFren");
1711 var buf: [5]u8 = undefined;
1712 try testing.expectEqual(5, try r.readSliceShort(&buf));
1713 try testing.expectEqualStrings("Hello", buf[0..5]);
1714 try testing.expectEqual(4, try r.readSliceShort(&buf));
1715 try testing.expectEqualStrings("Fren", buf[0..4]);
1716 try testing.expectEqual(0, try r.readSliceShort(&buf));
1717}
1718
1719test "readSliceShort with smaller buffer than Reader" {
1720 var reader_buf: [15]u8 = undefined;
1721 const str = "This is a test";
1722 var one_byte_stream: testing.Reader = .init(&reader_buf, &.{
1723 .{ .buffer = str },
1724 });
1725 one_byte_stream.artificial_limit = .limited(1);
1726
1727 var buf: [14]u8 = undefined;
1728 try testing.expectEqual(14, try one_byte_stream.interface.readSliceShort(&buf));
1729 try testing.expectEqualStrings(str, &buf);
1730}
1731
1732test "readSliceShort with indirect reader" {
1733 var r: Reader = .fixed("HelloFren");
1734 var ri_buf: [3]u8 = undefined;
1735 var ri: std.testing.ReaderIndirect = .init(&r, &ri_buf);
1736 var buf: [5]u8 = undefined;
1737 try testing.expectEqual(5, try ri.interface.readSliceShort(&buf));
1738 try testing.expectEqualStrings("Hello", buf[0..5]);
1739 try testing.expectEqual(4, try ri.interface.readSliceShort(&buf));
1740 try testing.expectEqualStrings("Fren", buf[0..4]);
1741 try testing.expectEqual(0, try ri.interface.readSliceShort(&buf));
1742}
1743
1744test readVec {
1745 var r: Reader = .fixed(std.ascii.letters);
1746 var flat_buffer: [52]u8 = undefined;
1747 var bufs: [2][]u8 = .{
1748 flat_buffer[0..26],
1749 flat_buffer[26..],
1750 };
1751 // Short reads are possible with this function but not with fixed.
1752 try testing.expectEqual(26 * 2, try r.readVec(&bufs));
1753 try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]);
1754 try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]);
1755}
1756
1757test "expected error.EndOfStream" {
1758 // Unit test inspired by https://github.com/ziglang/zig/issues/17733
1759 var buffer: [3]u8 = undefined;
1760 var r: std.Io.Reader = .fixed(&buffer);
1761 r.end = 0; // capacity 3, but empty
1762 try std.testing.expectError(error.EndOfStream, r.takeEnum(enum(u8) { a, b }, .little));
1763 try std.testing.expectError(error.EndOfStream, r.take(3));
1764}
1765
1766test "readVec at end" {
1767 var reader_buffer: [8]u8 = "abcd1234".*;
1768 var reader: testing.Reader = .init(&reader_buffer, &.{});
1769 reader.interface.end = reader_buffer.len;
1770
1771 var out: [16]u8 = undefined;
1772 var vecs: [1][]u8 = .{&out};
1773 try testing.expectEqual(8, try reader.interface.readVec(&vecs));
1774 try testing.expectEqualStrings("abcd1234", vecs[0][0..8]);
1775}
1776
1777fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1778 _ = r;
1779 _ = w;
1780 _ = limit;
1781 return error.EndOfStream;
1782}
1783
1784fn endingReadVec(r: *Reader, data: [][]u8) Error!usize {
1785 _ = r;
1786 _ = data;
1787 return error.EndOfStream;
1788}
1789
1790fn endingDiscard(r: *Reader, limit: Limit) Error!usize {
1791 _ = r;
1792 _ = limit;
1793 return error.EndOfStream;
1794}
1795
1796fn endingRebase(r: *Reader, capacity: usize) RebaseError!void {
1797 _ = r;
1798 _ = capacity;
1799 return error.EndOfStream;
1800}
1801
1802fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1803 _ = r;
1804 _ = w;
1805 _ = limit;
1806 return error.ReadFailed;
1807}
1808
1809fn failingDiscard(r: *Reader, limit: Limit) Error!usize {
1810 _ = r;
1811 _ = limit;
1812 return error.ReadFailed;
1813}
1814
1815test "discardAll that has to call discard multiple times on an indirect reader" {
1816 var fr: Reader = .fixed("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
1817 var indirect_buffer: [3]u8 = undefined;
1818 var tri: std.testing.ReaderIndirect = .init(&fr, &indirect_buffer);
1819 const r = &tri.interface;
1820
1821 try r.discardAll(10);
1822 var remaining_buf: [16]u8 = undefined;
1823 try r.readSliceAll(&remaining_buf);
1824 try std.testing.expectEqualStrings(fr.buffer[10..], remaining_buf[0..]);
1825}
1826
1827test "readAlloc when the backing reader provides one byte at a time" {
1828 const str = "This is a test";
1829 var tiny_buffer: [1]u8 = undefined;
1830 var one_byte_stream: testing.Reader = .init(&tiny_buffer, &.{
1831 .{ .buffer = str },
1832 });
1833 one_byte_stream.artificial_limit = .limited(1);
1834 const res = try one_byte_stream.interface.allocRemaining(std.testing.allocator, .unlimited);
1835 defer std.testing.allocator.free(res);
1836 try std.testing.expectEqualStrings(str, res);
1837}
1838
1839test "takeDelimiterInclusive when it rebases" {
1840 const written_line = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
1841 var buffer: [128]u8 = undefined;
1842 var tr: std.testing.Reader = .init(&buffer, &.{
1843 .{ .buffer = written_line },
1844 .{ .buffer = written_line },
1845 .{ .buffer = written_line },
1846 .{ .buffer = written_line },
1847 .{ .buffer = written_line },
1848 .{ .buffer = written_line },
1849 });
1850 const r = &tr.interface;
1851 for (0..6) |_| {
1852 try std.testing.expectEqualStrings(written_line, try r.takeDelimiterInclusive('\n'));
1853 }
1854}
1855
1856test "takeDelimiterInclusive on an indirect reader when it rebases" {
1857 const written_line = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
1858 var buffer: [128]u8 = undefined;
1859 var tr: std.testing.Reader = .init(&buffer, &.{
1860 .{ .buffer = written_line[0..4] },
1861 .{ .buffer = written_line[4..] },
1862 .{ .buffer = written_line },
1863 .{ .buffer = written_line },
1864 .{ .buffer = written_line },
1865 .{ .buffer = written_line },
1866 .{ .buffer = written_line },
1867 });
1868 var indirect_buffer: [128]u8 = undefined;
1869 var tri: std.testing.ReaderIndirect = .init(&tr.interface, &indirect_buffer);
1870 const r = &tri.interface;
1871 for (0..6) |_| {
1872 try std.testing.expectEqualStrings(written_line, try r.takeDelimiterInclusive('\n'));
1873 }
1874}
1875
1876test "takeStruct and peekStruct packed" {
1877 var r: Reader = .fixed(&.{ 0b11110000, 0b00110011 });
1878 const S = packed struct(u16) { a: u2, b: u6, c: u7, d: u1 };
1879
1880 try testing.expectEqual(@as(S, .{
1881 .a = 0b11,
1882 .b = 0b001100,
1883 .c = 0b1110000,
1884 .d = 0b1,
1885 }), try r.peekStruct(S, .big));
1886
1887 try testing.expectEqual(@as(S, .{
1888 .a = 0b11,
1889 .b = 0b001100,
1890 .c = 0b1110000,
1891 .d = 0b1,
1892 }), try r.takeStruct(S, .big));
1893
1894 try testing.expectError(error.EndOfStream, r.takeStruct(S, .little));
1895}
1896
1897/// Provides a `Reader` implementation by passing data from an underlying
1898/// reader through `Hasher.update`.
1899///
1900/// The underlying reader is best unbuffered.
1901///
1902/// This implementation makes suboptimal buffering decisions due to being
1903/// generic. A better solution will involve creating a reader for each hash
1904/// function, where the discard buffer can be tailored to the hash
1905/// implementation details.
1906pub fn Hashed(comptime Hasher: type) type {
1907 return struct {
1908 in: *Reader,
1909 hasher: Hasher,
1910 reader: Reader,
1911
1912 pub fn init(in: *Reader, hasher: Hasher, buffer: []u8) @This() {
1913 return .{
1914 .in = in,
1915 .hasher = hasher,
1916 .reader = .{
1917 .vtable = &.{
1918 .stream = @This().stream,
1919 .readVec = @This().readVec,
1920 .discard = @This().discard,
1921 },
1922 .buffer = buffer,
1923 .end = 0,
1924 .seek = 0,
1925 },
1926 };
1927 }
1928
1929 fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1930 const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1931 const data = limit.slice(try w.writableSliceGreedy(1));
1932 var vec: [1][]u8 = .{data};
1933 const n = try this.in.readVec(&vec);
1934 this.hasher.update(data[0..n]);
1935 w.advance(n);
1936 return n;
1937 }
1938
1939 fn readVec(r: *Reader, data: [][]u8) Error!usize {
1940 const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1941 var vecs: [8][]u8 = undefined; // Arbitrarily chosen amount.
1942 const dest_n, const data_size = try r.writableVector(&vecs, data);
1943 const dest = vecs[0..dest_n];
1944 const n = try this.in.readVec(dest);
1945 var remaining: usize = n;
1946 for (dest) |slice| {
1947 if (remaining < slice.len) {
1948 this.hasher.update(slice[0..remaining]);
1949 remaining = 0;
1950 break;
1951 } else {
1952 remaining -= slice.len;
1953 this.hasher.update(slice);
1954 }
1955 }
1956 assert(remaining == 0);
1957 if (n > data_size) {
1958 r.end += n - data_size;
1959 return data_size;
1960 }
1961 return n;
1962 }
1963
1964 fn discard(r: *Reader, limit: Limit) Error!usize {
1965 const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1966 const peeked = limit.slice(try this.in.peekGreedy(1));
1967 this.hasher.update(peeked);
1968 this.in.toss(peeked.len);
1969 return peeked.len;
1970 }
1971 };
1972}
1973
1974pub fn writableVectorPosix(r: *Reader, buffer: []std.posix.iovec, data: []const []u8) Error!struct { usize, usize } {
1975 var i: usize = 0;
1976 var n: usize = 0;
1977 if (r.seek == r.end) {
1978 for (data) |buf| {
1979 if (buffer.len - i == 0) return .{ i, n };
1980 if (buf.len != 0) {
1981 buffer[i] = .{ .base = buf.ptr, .len = buf.len };
1982 i += 1;
1983 n += buf.len;
1984 }
1985 }
1986 const buf = r.buffer;
1987 if (buf.len != 0) {
1988 r.seek = 0;
1989 r.end = 0;
1990 buffer[i] = .{ .base = buf.ptr, .len = buf.len };
1991 i += 1;
1992 }
1993 } else {
1994 const buf = r.buffer[r.end..];
1995 buffer[i] = .{ .base = buf.ptr, .len = buf.len };
1996 i += 1;
1997 }
1998 return .{ i, n };
1999}
2000
2001pub fn writableVectorWsa(
2002 r: *Reader,
2003 buffer: []std.os.windows.AFD.WSABUF(.@"var"),
2004 data: []const []u8,
2005) Error!struct { usize, usize } {
2006 var i: usize = 0;
2007 var n: usize = 0;
2008 if (r.seek == r.end) {
2009 for (data) |buf| {
2010 if (buffer.len - i == 0) return .{ i, n };
2011 if (buf.len == 0) continue;
2012 if (std.math.cast(u32, buf.len)) |len| {
2013 buffer[i] = .{ .buf = buf.ptr, .len = len };
2014 i += 1;
2015 n += len;
2016 continue;
2017 }
2018 buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
2019 i += 1;
2020 n += std.math.maxInt(u32);
2021 return .{ i, n };
2022 }
2023 const buf = r.buffer;
2024 if (buf.len != 0) {
2025 r.seek = 0;
2026 r.end = 0;
2027 if (std.math.cast(u32, buf.len)) |len| {
2028 buffer[i] = .{ .buf = buf.ptr, .len = len };
2029 } else {
2030 buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
2031 }
2032 i += 1;
2033 }
2034 } else {
2035 buffer[i] = .{
2036 .buf = r.buffer.ptr + r.end,
2037 .len = @min(std.math.maxInt(u32), r.buffer.len - r.end),
2038 };
2039 i += 1;
2040 }
2041 return .{ i, n };
2042}
2043
2044pub fn writableVector(r: *Reader, buffer: [][]u8, data: []const []u8) Error!struct { usize, usize } {
2045 var i: usize = 0;
2046 var n: usize = 0;
2047 if (r.seek == r.end) {
2048 for (data) |buf| {
2049 if (buffer.len - i == 0) return .{ i, n };
2050 if (buf.len != 0) {
2051 buffer[i] = buf;
2052 i += 1;
2053 n += buf.len;
2054 }
2055 }
2056 if (r.buffer.len != 0) {
2057 r.seek = 0;
2058 r.end = 0;
2059 buffer[i] = r.buffer;
2060 i += 1;
2061 }
2062 } else {
2063 buffer[i] = r.buffer[r.end..];
2064 i += 1;
2065 }
2066 return .{ i, n };
2067}
2068
2069test "deserialize signed LEB128" {
2070 // Small values
2071 try testing.expectEqual(5, testLeb128(i7, "\x05"));
2072 try testing.expectEqual(53, testLeb128(i64, "\x35"));
2073
2074 try testing.expectEqual(-6, testLeb128(i7, "\x7A"));
2075 try testing.expectEqual(-23, testLeb128(i64, "\x69"));
2076
2077 // Random values
2078 try testing.expectEqual(90, testLeb128(i8, "\xDA\x00"));
2079 try testing.expectEqual(3434, testLeb128(i16, "\xEA\x1A"));
2080 try testing.expectEqual(1505683543, testLeb128(i32, "\xD7\xD0\xFB\xCD\x05"));
2081 try testing.expectEqual(105721575804011595, testLeb128(i64, "\xCB\x88\x92\xD7\xE8\xA6\xE6\xBB\x01"));
2082 try testing.expectEqual(51316697993548595875823294343650416388, testLeb128(i128, "\x84\xAE\xAC\xFC\xE4\xA0\xCD\xE2\x87\xED\x83\xB2\x87\xAA\xA3\x9E\x9B\xCD\x00"));
2083
2084 try testing.expectEqual(-68, testLeb128(i8, "\xBC\x7F"));
2085 try testing.expectEqual(-20174, testLeb128(i16, "\xB2\xE2\x7E"));
2086 try testing.expectEqual(-166511141, testLeb128(i32, "\xDB\xFB\xCC\xB0\x7F"));
2087 try testing.expectEqual(-4368809844285451825, testLeb128(i64, "\xCF\xA3\x8B\xA1\xFF\xD2\xB7\xAF\x43"));
2088 try testing.expectEqual(-43250117698642799010758201165100952046, testLeb128(i128, "\x92\xAC\xDB\xA4\xEC\xDE\xB9\x95\xD1\xBA\xEC\xB0\xD7\x80\xA4\xAA\xF6\xBE\x7F"));
2089
2090 // {min,max} values
2091 try testing.expectEqual(std.math.maxInt(i8), testLeb128(i8, "\xFF\x00"));
2092 try testing.expectEqual(std.math.maxInt(i16), testLeb128(i16, "\xFF\xFF\x01"));
2093 try testing.expectEqual(std.math.maxInt(i32), testLeb128(i32, "\xFF\xFF\xFF\xFF\x07"));
2094 try testing.expectEqual(std.math.maxInt(i64), testLeb128(i64, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"));
2095 try testing.expectEqual(std.math.maxInt(i128), testLeb128(i128, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
2096
2097 try testing.expectEqual(std.math.minInt(i8), testLeb128(i8, "\x80\x7F"));
2098 try testing.expectEqual(std.math.minInt(i16), testLeb128(i16, "\x80\x80\x7E"));
2099 try testing.expectEqual(std.math.minInt(i32), testLeb128(i32, "\x80\x80\x80\x80\x78"));
2100 try testing.expectEqual(std.math.minInt(i64), testLeb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x7F"));
2101 try testing.expectEqual(std.math.minInt(i128), testLeb128(i128, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x7E"));
2102
2103 // Specific cases
2104 try testing.expectEqual(0, testLeb128(i2, "\x00"));
2105 try testing.expectEqual(0, testLeb128(i8, "\x00"));
2106
2107 try testing.expectEqual(1, testLeb128(i2, "\x01"));
2108 try testing.expectEqual(1, testLeb128(i8, "\x01"));
2109
2110 try testing.expectEqual(-1, testLeb128(i2, "\x7F"));
2111 try testing.expectEqual(-1, testLeb128(i8, "\x7F"));
2112
2113 const end_of_stream: [20]u8 = @splat(0x80);
2114 const overflow: [21]u8 = end_of_stream ++ .{0x01};
2115 const long_zero: [21]u8 = end_of_stream ++ .{0x00};
2116 const long_one: [22]u8 = .{0x81} ++ end_of_stream ++ .{0x00};
2117 const long_minus_one: [20]u8 = @as([19]u8, @splat(0xFF)) ++ .{0x7F};
2118
2119 // Truncated
2120 try testing.expectError(error.EndOfStream, testLeb128(i16, "\x80\x80\x84\x80"));
2121 try testing.expectError(error.EndOfStream, testLeb128(i16, "\x80\x80\x80\x84\x80"));
2122 try testing.expectError(error.EndOfStream, testLeb128(i32, "\x80\x80\x80\x80\x90"));
2123
2124 try testing.expectError(error.EndOfStream, testLeb128(i7, ""));
2125 try testing.expectError(error.EndOfStream, testLeb128(i8, ""));
2126 try testing.expectError(error.EndOfStream, testLeb128(i14, ""));
2127 try testing.expectError(error.EndOfStream, testLeb128(i128, ""));
2128
2129 try testing.expectError(error.EndOfStream, testLeb128(i7, "\x80"));
2130 try testing.expectError(error.EndOfStream, testLeb128(i8, "\x80"));
2131 try testing.expectError(error.EndOfStream, testLeb128(i14, "\x80"));
2132 try testing.expectError(error.EndOfStream, testLeb128(i128, "\x80"));
2133
2134 try testing.expectError(error.EndOfStream, testLeb128(i7, &end_of_stream));
2135 try testing.expectError(error.EndOfStream, testLeb128(i8, &end_of_stream));
2136 try testing.expectError(error.EndOfStream, testLeb128(i14, &end_of_stream));
2137 try testing.expectError(error.EndOfStream, testLeb128(i128, &end_of_stream));
2138
2139 // Overflow
2140 try testing.expectError(error.Overflow, testLeb128(i8, "\x80\x01"));
2141 try testing.expectError(error.Overflow, testLeb128(i8, "\xFF\x7E"));
2142 try testing.expectError(error.Overflow, testLeb128(i8, "\x80\x80\x40"));
2143 try testing.expectError(error.Overflow, testLeb128(i16, "\x80\x80\x80\x40"));
2144 try testing.expectError(error.Overflow, testLeb128(i32, "\x80\x80\x80\x80\x08"));
2145 try testing.expectError(error.Overflow, testLeb128(i32, "\x80\x80\x80\x80\x40"));
2146 try testing.expectError(error.Overflow, testLeb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01"));
2147 try testing.expectError(error.Overflow, testLeb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x40"));
2148
2149 try testing.expectError(error.Overflow, testLeb128(i7, &overflow));
2150 try testing.expectError(error.Overflow, testLeb128(i8, &overflow));
2151 try testing.expectError(error.Overflow, testLeb128(i14, &overflow));
2152 try testing.expectError(error.Overflow, testLeb128(i128, &overflow));
2153
2154 // Extra padding
2155 try testing.expectEqual(-1, testLeb128(i32, "\xFF\xFF\xFF\xFF\x7F"));
2156 try testing.expectEqual(-1, testLeb128(i64, "\xFF\x7F"));
2157 try testing.expectEqual(0x7F, testLeb128(i64, "\xFF\x00"));
2158 try testing.expectEqual(0x7F, testLeb128(i64, "\xFF\x80\x00"));
2159 try testing.expectEqual(0x80, testLeb128(i64, "\x80\x81\x00"));
2160 try testing.expectEqual(0x80, testLeb128(i64, "\x80\x81\x80\x00"));
2161
2162 try testing.expectEqual(0, testLeb128(i7, &long_zero));
2163 try testing.expectEqual(0, testLeb128(i8, &long_zero));
2164 try testing.expectEqual(0, testLeb128(i14, &long_zero));
2165 try testing.expectEqual(0, testLeb128(i128, &long_zero));
2166
2167 try testing.expectEqual(1, testLeb128(i2, &long_one));
2168 try testing.expectEqual(1, testLeb128(i7, &long_one));
2169 try testing.expectEqual(1, testLeb128(i8, &long_one));
2170 try testing.expectEqual(1, testLeb128(i14, &long_one));
2171 try testing.expectEqual(1, testLeb128(i128, &long_one));
2172
2173 try testing.expectEqual(-1, testLeb128(i2, &long_minus_one));
2174 try testing.expectEqual(-1, testLeb128(i7, &long_minus_one));
2175 try testing.expectEqual(-1, testLeb128(i8, &long_minus_one));
2176 try testing.expectEqual(-1, testLeb128(i14, &long_minus_one));
2177 try testing.expectEqual(-1, testLeb128(i128, &long_minus_one));
2178
2179 // Decode byte boundaries
2180 try testing.expectEqual(std.math.maxInt(i7), testLeb128(i7, "\x3F"));
2181 try testing.expectEqual(std.math.maxInt(i7) + 1, testLeb128(i8, "\xC0\x00"));
2182 try testing.expectEqual(std.math.maxInt(i14), testLeb128(i14, "\xFF\x3F"));
2183 try testing.expectEqual(std.math.maxInt(i14) + 1, testLeb128(i15, "\x80\xC0\x00"));
2184 try testing.expectEqual(std.math.maxInt(i49), testLeb128(i49, "\xFF\xFF\xFF\xFF\xFF\xFF\x3F"));
2185 try testing.expectEqual(std.math.maxInt(i49) + 1, testLeb128(i50, "\x80\x80\x80\x80\x80\x80\xC0\x00"));
2186 try testing.expectEqual(std.math.maxInt(i56), testLeb128(i56, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F"));
2187 try testing.expectEqual(std.math.maxInt(i56) + 1, testLeb128(i57, "\x80\x80\x80\x80\x80\x80\x80\xC0\x00"));
2188 try testing.expectEqual(std.math.maxInt(i63), testLeb128(i63, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F"));
2189 try testing.expectEqual(std.math.maxInt(i63) + 1, testLeb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\xC0\x00"));
2190
2191 try testing.expectEqual(std.math.minInt(i7), testLeb128(i7, "\x40"));
2192 try testing.expectEqual(std.math.minInt(i7) - 1, testLeb128(i8, "\xBF\x7F"));
2193 try testing.expectEqual(std.math.minInt(i14), testLeb128(i14, "\x80\x40"));
2194 try testing.expectEqual(std.math.minInt(i14) - 1, testLeb128(i15, "\xFF\xBF\x7F"));
2195 try testing.expectEqual(std.math.minInt(i49), testLeb128(i49, "\x80\x80\x80\x80\x80\x80\x40"));
2196 try testing.expectEqual(std.math.minInt(i49) - 1, testLeb128(i50, "\xFF\xFF\xFF\xFF\xFF\xFF\xBF\x7F"));
2197 try testing.expectEqual(std.math.minInt(i56), testLeb128(i56, "\x80\x80\x80\x80\x80\x80\x80\x40"));
2198 try testing.expectEqual(std.math.minInt(i56) - 1, testLeb128(i57, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBF\x7F"));
2199 try testing.expectEqual(std.math.minInt(i63), testLeb128(i63, "\x80\x80\x80\x80\x80\x80\x80\x80\x40"));
2200 try testing.expectEqual(std.math.minInt(i63) - 1, testLeb128(i64, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBF\x7F"));
2201}
2202
2203test "deserialize unsigned LEB128" {
2204 // Small values
2205 try testing.expectEqual(46, testLeb128(u7, "\x2E"));
2206 try testing.expectEqual(117, testLeb128(u64, "\x75"));
2207
2208 // Random values
2209 try testing.expectEqual(224, testLeb128(u8, "\xE0\x01"));
2210 try testing.expectEqual(53023, testLeb128(u16, "\x9F\x9E\x03"));
2211 try testing.expectEqual(2609971022, testLeb128(u32, "\xCE\xFE\xC3\xDC\x09"));
2212 try testing.expectEqual(10223253173206528843, testLeb128(u64, "\xCB\xE6\xF0\xEE\x88\xD3\x92\xF0\x8D\x01"));
2213 try testing.expectEqual(67831258924174241363439488509570048548, testLeb128(u128, "\xA4\xC4\xD7\xE9\x8C\xD2\x86\x80\xBC\xAC\xE5\xAB\xB4\xA2\xD1\xE9\x87\x66"));
2214
2215 // max values
2216 try testing.expectEqual(std.math.maxInt(u8), testLeb128(u8, "\xFF\x01"));
2217 try testing.expectEqual(std.math.maxInt(u16), testLeb128(u16, "\xFF\xFF\x03"));
2218 try testing.expectEqual(std.math.maxInt(u32), testLeb128(u32, "\xFF\xFF\xFF\xFF\x0F"));
2219 try testing.expectEqual(std.math.maxInt(u64), testLeb128(u64, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
2220 try testing.expectEqual(std.math.maxInt(u128), testLeb128(u128, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x03"));
2221
2222 // Specific cases
2223 try testing.expectEqual(0, testLeb128(u0, "\x00"));
2224 try testing.expectEqual(0, testLeb128(u1, "\x00"));
2225 try testing.expectEqual(0, testLeb128(u8, "\x00"));
2226
2227 try testing.expectEqual(1, testLeb128(u1, "\x01"));
2228 try testing.expectEqual(1, testLeb128(u8, "\x01"));
2229
2230 const end_of_stream: [20]u8 = @splat(0x80);
2231 const overflow: [21]u8 = end_of_stream ++ .{0x01};
2232 const long_zero: [21]u8 = end_of_stream ++ .{0x00};
2233 const long_one: [22]u8 = .{0x81} ++ end_of_stream ++ .{0x00};
2234
2235 // Truncated
2236 try testing.expectError(error.EndOfStream, testLeb128(u16, "\x80\x80\x84\x80"));
2237 try testing.expectError(error.EndOfStream, testLeb128(u16, "\x80\x80\x80\x84\x80"));
2238 try testing.expectError(error.EndOfStream, testLeb128(u32, "\x80\x80\x80\x80\x90"));
2239
2240 try testing.expectError(error.EndOfStream, testLeb128(u7, ""));
2241 try testing.expectError(error.EndOfStream, testLeb128(u8, ""));
2242 try testing.expectError(error.EndOfStream, testLeb128(u14, ""));
2243 try testing.expectError(error.EndOfStream, testLeb128(u128, ""));
2244
2245 try testing.expectError(error.EndOfStream, testLeb128(u7, "\x80"));
2246 try testing.expectError(error.EndOfStream, testLeb128(u8, "\x80"));
2247 try testing.expectError(error.EndOfStream, testLeb128(u14, "\x80"));
2248 try testing.expectError(error.EndOfStream, testLeb128(u128, "\x80"));
2249
2250 try testing.expectError(error.EndOfStream, testLeb128(u7, &end_of_stream));
2251 try testing.expectError(error.EndOfStream, testLeb128(u8, &end_of_stream));
2252 try testing.expectError(error.EndOfStream, testLeb128(u14, &end_of_stream));
2253 try testing.expectError(error.EndOfStream, testLeb128(u128, &end_of_stream));
2254
2255 // Overflow
2256 try testing.expectError(error.Overflow, testLeb128(u0, "\x01"));
2257 try testing.expectError(error.Overflow, testLeb128(u1, "\x02"));
2258 try testing.expectError(error.Overflow, testLeb128(u8, "\x80\x02"));
2259 try testing.expectError(error.Overflow, testLeb128(u8, "\x80\x80\x40"));
2260 try testing.expectError(error.Overflow, testLeb128(u16, "\x80\x80\x80\x40"));
2261 try testing.expectError(error.Overflow, testLeb128(u32, "\x80\x80\x80\x80\x40"));
2262 try testing.expectError(error.Overflow, testLeb128(u64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x40"));
2263
2264 try testing.expectError(error.Overflow, testLeb128(u7, &overflow));
2265 try testing.expectError(error.Overflow, testLeb128(u8, &overflow));
2266 try testing.expectError(error.Overflow, testLeb128(u14, &overflow));
2267 try testing.expectError(error.Overflow, testLeb128(u128, &overflow));
2268
2269 // Extra padding
2270 try testing.expectEqual(0x7F, testLeb128(u64, "\xFF\x00"));
2271 try testing.expectEqual(0x7F, testLeb128(u64, "\xFF\x80\x00"));
2272 try testing.expectEqual(0x80, testLeb128(u64, "\x80\x81\x00"));
2273 try testing.expectEqual(0x80, testLeb128(u64, "\x80\x81\x80\x80\x00"));
2274
2275 try testing.expectEqual(0, testLeb128(u0, &long_zero));
2276 try testing.expectEqual(0, testLeb128(u7, &long_zero));
2277 try testing.expectEqual(0, testLeb128(u8, &long_zero));
2278 try testing.expectEqual(0, testLeb128(u14, &long_zero));
2279 try testing.expectEqual(0, testLeb128(u128, &long_zero));
2280
2281 try testing.expectEqual(1, testLeb128(u1, &long_one));
2282 try testing.expectEqual(1, testLeb128(u7, &long_one));
2283 try testing.expectEqual(1, testLeb128(u8, &long_one));
2284 try testing.expectEqual(1, testLeb128(u14, &long_one));
2285 try testing.expectEqual(1, testLeb128(u128, &long_one));
2286
2287 // Decode byte boundaries
2288 try testing.expectEqual(std.math.maxInt(u7), testLeb128(u7, "\x7F"));
2289 try testing.expectEqual(std.math.maxInt(u7) + 1, testLeb128(u8, "\x80\x01"));
2290 try testing.expectEqual(std.math.maxInt(u14), testLeb128(u14, "\xFF\x7F"));
2291 try testing.expectEqual(std.math.maxInt(u14) + 1, testLeb128(u15, "\x80\x80\x01"));
2292 try testing.expectEqual(std.math.maxInt(u49), testLeb128(u49, "\xFF\xFF\xFF\xFF\xFF\xFF\x7F"));
2293 try testing.expectEqual(std.math.maxInt(u49) + 1, testLeb128(u50, "\x80\x80\x80\x80\x80\x80\x80\x01"));
2294 try testing.expectEqual(std.math.maxInt(u56), testLeb128(u56, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"));
2295 try testing.expectEqual(std.math.maxInt(u56) + 1, testLeb128(u57, "\x80\x80\x80\x80\x80\x80\x80\x80\x01"));
2296 try testing.expectEqual(std.math.maxInt(u63), testLeb128(u63, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"));
2297 try testing.expectEqual(std.math.maxInt(u63) + 1, testLeb128(u64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01"));
2298}
2299
2300fn testLeb128(comptime T: type, encoded: []const u8) !T {
2301 var reader: std.Io.Reader = .fixed(encoded);
2302 const result = reader.takeLeb128(T);
2303 try testing.expectEqual(reader.seek, reader.end);
2304 return result;
2305}
2306
2307test streamExactPreserve {
2308 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .stream_len = 5 });
2309 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 9, .preserve = 5, .stream_len = 2 });
2310 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .stream_len = 6 });
2311 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 6 });
2312 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .stream_len = 10 });
2313 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 10 });
2314 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 11 });
2315 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 80 });
2316 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 85 });
2317 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .stream_len = 6 });
2318 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .stream_len = 11 });
2319 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .stream_len = 80 });
2320 try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .stream_len = 85 });
2321}
2322
2323fn testStreamExactPreserve(options: struct { buf_len: u4, fill_len: u4, preserve: u4, stream_len: u8 }) !void {
2324 assert(options.fill_len <= options.buf_len);
2325 assert(options.preserve <= options.buf_len);
2326
2327 var input: [256]u8 = undefined;
2328 for (&input, 0..) |*val, i| {
2329 val.* = @as(u8, @intCast(i % 26)) + 'a';
2330 }
2331 const expected_out = input[0 .. options.fill_len + options.stream_len];
2332 const expected_preserved = expected_out[expected_out.len -| options.preserve..];
2333
2334 var r: Reader = .fixed(&input);
2335 var out_buf: [256]u8 = undefined;
2336 var fw: Writer = .fixed(&out_buf);
2337 var indirect_buffer: [16]u8 = undefined;
2338 var twi: std.testing.WriterIndirect = .init(&fw, indirect_buffer[0..options.buf_len]);
2339 const w = &twi.interface;
2340
2341 try r.streamExact(w, options.fill_len);
2342 try r.streamExactPreserve(w, options.preserve, options.stream_len);
2343
2344 try std.testing.expectEqualStrings(expected_preserved, w.buffer[w.end -| options.preserve..w.end]);
2345
2346 try w.flush();
2347
2348 try std.testing.expectEqualStrings(expected_out, fw.buffered());
2349}
2350
2351test {
2352 _ = Limited;
2353}