| ... | @@ -445,7 +445,7 @@ pub fn toss(r: *Reader, n: usize) void { | ... | @@ -445,7 +445,7 @@ pub fn toss(r: *Reader, n: usize) void { |
| 445 | } | 445 | } |
| 446 | | 446 | |
| 447 | /// Equivalent to `toss(r.bufferedLen())`. | 447 | /// Equivalent to `toss(r.bufferedLen())`. |
| 448 | pub fn tossAll(r: *Reader) void { | 448 | pub fn tossBuffered(r: *Reader) void { |
| 449 | r.seek = 0; | 449 | r.seek = 0; |
| 450 | r.end = 0; | 450 | r.end = 0; |
| 451 | } | 451 | } |
| ... | @@ -557,7 +557,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize { | ... | @@ -557,7 +557,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize { |
| 557 | /// See also: | 557 | /// See also: |
| 558 | /// * `peek` | 558 | /// * `peek` |
| 559 | /// * `readSliceShort` | 559 | /// * `readSliceShort` |
| 560 | pub fn readSlice(r: *Reader, buffer: []u8) Error!void { | 560 | pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void { |
| 561 | const n = try readSliceShort(r, buffer); | 561 | const n = try readSliceShort(r, buffer); |
| 562 | if (n != buffer.len) return error.EndOfStream; | 562 | if (n != buffer.len) return error.EndOfStream; |
| 563 | } | 563 | } |
| ... | @@ -571,7 +571,7 @@ pub fn readSlice(r: *Reader, buffer: []u8) Error!void { | ... | @@ -571,7 +571,7 @@ pub fn readSlice(r: *Reader, buffer: []u8) Error!void { |
| 571 | /// only if the stream reached the end. | 571 | /// only if the stream reached the end. |
| 572 | /// | 572 | /// |
| 573 | /// See also: | 573 | /// See also: |
| 574 | /// * `readSlice` | 574 | /// * `readSliceAll` |
| 575 | pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize { | 575 | pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize { |
| 576 | const in_buffer = r.buffer[r.seek..r.end]; | 576 | const in_buffer = r.buffer[r.seek..r.end]; |
| 577 | const copy_len = @min(buffer.len, in_buffer.len); | 577 | const copy_len = @min(buffer.len, in_buffer.len); |
| ... | @@ -630,7 +630,7 @@ pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize { | ... | @@ -630,7 +630,7 @@ pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize { |
| 630 | /// comptime-known and matches host endianness. | 630 | /// comptime-known and matches host endianness. |
| 631 | /// | 631 | /// |
| 632 | /// See also: | 632 | /// See also: |
| 633 | /// * `readSlice` | 633 | /// * `readSliceAll` |
| 634 | /// * `readSliceEndianAlloc` | 634 | /// * `readSliceEndianAlloc` |
| 635 | pub inline fn readSliceEndian( | 635 | pub inline fn readSliceEndian( |
| 636 | r: *Reader, | 636 | r: *Reader, |
| ... | @@ -638,7 +638,7 @@ pub inline fn readSliceEndian( | ... | @@ -638,7 +638,7 @@ pub inline fn readSliceEndian( |
| 638 | buffer: []Elem, | 638 | buffer: []Elem, |
| 639 | endian: std.builtin.Endian, | 639 | endian: std.builtin.Endian, |
| 640 | ) Error!void { | 640 | ) Error!void { |
| 641 | try readSlice(r, @ptrCast(buffer)); | 641 | try readSliceAll(r, @ptrCast(buffer)); |
| 642 | if (native_endian != endian) for (buffer) |*elem| std.mem.byteSwapAllFields(Elem, elem); | 642 | if (native_endian != endian) for (buffer) |*elem| std.mem.byteSwapAllFields(Elem, elem); |
| 643 | } | 643 | } |
| 644 | | 644 | |
| ... | @@ -655,15 +655,16 @@ pub inline fn readSliceEndianAlloc( | ... | @@ -655,15 +655,16 @@ pub inline fn readSliceEndianAlloc( |
| 655 | ) ReadAllocError![]Elem { | 655 | ) ReadAllocError![]Elem { |
| 656 | const dest = try allocator.alloc(Elem, len); | 656 | const dest = try allocator.alloc(Elem, len); |
| 657 | errdefer allocator.free(dest); | 657 | errdefer allocator.free(dest); |
| 658 | try readSlice(r, @ptrCast(dest)); | 658 | try readSliceAll(r, @ptrCast(dest)); |
| 659 | if (native_endian != endian) for (dest) |*elem| std.mem.byteSwapAllFields(Elem, elem); | 659 | if (native_endian != endian) for (dest) |*elem| std.mem.byteSwapAllFields(Elem, elem); |
| 660 | return dest; | 660 | return dest; |
| 661 | } | 661 | } |
| 662 | | 662 | |
| 663 | pub fn readSliceAlloc(r: *Reader, allocator: Allocator, len: usize) ReadAllocError![]u8 { | 663 | /// Shortcut for calling `readSliceAll` with a buffer provided by `allocator`. |
| | 664 | pub fn readAlloc(r: *Reader, allocator: Allocator, len: usize) ReadAllocError![]u8 { |
| 664 | const dest = try allocator.alloc(u8, len); | 665 | const dest = try allocator.alloc(u8, len); |
| 665 | errdefer allocator.free(dest); | 666 | errdefer allocator.free(dest); |
| 666 | try readSlice(r, dest); | 667 | try readSliceAll(r, dest); |
| 667 | return dest; | 668 | return dest; |
| 668 | } | 669 | } |
| 669 | | 670 | |
| ... | @@ -1092,6 +1093,7 @@ pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n: | ... | @@ -1092,6 +1093,7 @@ pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n: |
| 1092 | /// | 1093 | /// |
| 1093 | /// See also: | 1094 | /// See also: |
| 1094 | /// * `peekStruct` | 1095 | /// * `peekStruct` |
| | 1096 | /// * `takeStructEndian` |
| 1095 | pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T { | 1097 | pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T { |
| 1096 | // Only extern and packed structs have defined in-memory layout. | 1098 | // Only extern and packed structs have defined in-memory layout. |
| 1097 | comptime assert(@typeInfo(T).@"struct".layout != .auto); | 1099 | comptime assert(@typeInfo(T).@"struct".layout != .auto); |
| ... | @@ -1104,6 +1106,7 @@ pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T { | ... | @@ -1104,6 +1106,7 @@ pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T { |
| 1104 | /// | 1106 | /// |
| 1105 | /// See also: | 1107 | /// See also: |
| 1106 | /// * `takeStruct` | 1108 | /// * `takeStruct` |
| | 1109 | /// * `peekStructEndian` |
| 1107 | pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T { | 1110 | pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T { |
| 1108 | // Only extern and packed structs have defined in-memory layout. | 1111 | // Only extern and packed structs have defined in-memory layout. |
| 1109 | comptime assert(@typeInfo(T).@"struct".layout != .auto); | 1112 | comptime assert(@typeInfo(T).@"struct".layout != .auto); |
| ... | @@ -1114,6 +1117,10 @@ pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T { | ... | @@ -1114,6 +1117,10 @@ pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T { |
| 1114 | /// | 1117 | /// |
| 1115 | /// This function is inline to avoid referencing `std.mem.byteSwapAllFields` | 1118 | /// This function is inline to avoid referencing `std.mem.byteSwapAllFields` |
| 1116 | /// when `endian` is comptime-known and matches the host endianness. | 1119 | /// when `endian` is comptime-known and matches the host endianness. |
| | 1120 | /// |
| | 1121 | /// See also: |
| | 1122 | /// * `takeStruct` |
| | 1123 | /// * `peekStructEndian` |
| 1117 | pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { | 1124 | pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { |
| 1118 | var res = (try r.takeStruct(T)).*; | 1125 | var res = (try r.takeStruct(T)).*; |
| 1119 | if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); | 1126 | if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); |
| ... | @@ -1124,6 +1131,10 @@ pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin | ... | @@ -1124,6 +1131,10 @@ pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin |
| 1124 | /// | 1131 | /// |
| 1125 | /// This function is inline to avoid referencing `std.mem.byteSwapAllFields` | 1132 | /// This function is inline to avoid referencing `std.mem.byteSwapAllFields` |
| 1126 | /// when `endian` is comptime-known and matches the host endianness. | 1133 | /// when `endian` is comptime-known and matches the host endianness. |
| | 1134 | /// |
| | 1135 | /// See also: |
| | 1136 | /// * `takeStructEndian` |
| | 1137 | /// * `peekStruct` |
| 1127 | pub inline fn peekStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { | 1138 | pub inline fn peekStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { |
| 1128 | var res = (try r.peekStruct(T)).*; | 1139 | var res = (try r.peekStruct(T)).*; |
| 1129 | if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); | 1140 | if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); |
| ... | @@ -1489,25 +1500,47 @@ test takeInt { | ... | @@ -1489,25 +1500,47 @@ test takeInt { |
| 1489 | | 1500 | |
| 1490 | test takeVarInt { | 1501 | test takeVarInt { |
| 1491 | var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 }); | 1502 | var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 }); |
| 1492 | std.debug.print("{x}", .{r.buffer}); | | |
| 1493 | try testing.expectEqual(0x123456, try r.takeVarInt(u64, .big, 3)); | 1503 | try testing.expectEqual(0x123456, try r.takeVarInt(u64, .big, 3)); |
| 1494 | try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1)); | 1504 | try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1)); |
| 1495 | } | 1505 | } |
| 1496 | | 1506 | |
| 1497 | test takeStruct { | 1507 | test takeStruct { |
| 1498 | return error.Unimplemented; | 1508 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); |
| | 1509 | const S = extern struct { a: u8, b: u16 }; |
| | 1510 | switch (native_endian) { |
| | 1511 | .little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStruct(S)).*), |
| | 1512 | .big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStruct(S)).*), |
| | 1513 | } |
| | 1514 | try testing.expectError(error.EndOfStream, r.takeStruct(S)); |
| 1499 | } | 1515 | } |
| 1500 | | 1516 | |
| 1501 | test peekStruct { | 1517 | test peekStruct { |
| 1502 | return error.Unimplemented; | 1518 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); |
| | 1519 | const S = extern struct { a: u8, b: u16 }; |
| | 1520 | switch (native_endian) { |
| | 1521 | .little => { |
| | 1522 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*); |
| | 1523 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*); |
| | 1524 | }, |
| | 1525 | .big => { |
| | 1526 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*); |
| | 1527 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*); |
| | 1528 | }, |
| | 1529 | } |
| 1503 | } | 1530 | } |
| 1504 | | 1531 | |
| 1505 | test takeStructEndian { | 1532 | test takeStructEndian { |
| 1506 | return error.Unimplemented; | 1533 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); |
| | 1534 | const S = extern struct { a: u8, b: u16 }; |
| | 1535 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.takeStructEndian(S, .big)); |
| | 1536 | try testing.expectError(error.EndOfStream, r.takeStructEndian(S, .little)); |
| 1507 | } | 1537 | } |
| 1508 | | 1538 | |
| 1509 | test peekStructEndian { | 1539 | test peekStructEndian { |
| 1510 | return error.Unimplemented; | 1540 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); |
| | 1541 | const S = extern struct { a: u8, b: u16 }; |
| | 1542 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.peekStructEndian(S, .big)); |
| | 1543 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), try r.peekStructEndian(S, .little)); |
| 1511 | } | 1544 | } |
| 1512 | | 1545 | |
| 1513 | test takeEnum { | 1546 | test takeEnum { |
| ... | @@ -1519,15 +1552,46 @@ test takeEnum { | ... | @@ -1519,15 +1552,46 @@ test takeEnum { |
| 1519 | } | 1552 | } |
| 1520 | | 1553 | |
| 1521 | test takeLeb128 { | 1554 | test takeLeb128 { |
| 1522 | return error.Unimplemented; | 1555 | var r: Reader = .fixed("\xc7\x9f\x7f\x80"); |
| | 1556 | try testing.expectEqual(-12345, try r.takeLeb128(i64)); |
| | 1557 | try testing.expectEqual(0x80, try r.peekByte()); |
| | 1558 | try testing.expectError(error.EndOfStream, r.takeLeb128(i64)); |
| 1523 | } | 1559 | } |
| 1524 | | 1560 | |
| 1525 | test readSliceShort { | 1561 | test readSliceShort { |
| 1526 | return error.Unimplemented; | 1562 | var r: Reader = .fixed("HelloFren"); |
| | 1563 | var buf: [5]u8 = undefined; |
| | 1564 | try testing.expectEqual(5, try r.readSliceShort(&buf)); |
| | 1565 | try testing.expectEqualStrings("Hello", buf[0..5]); |
| | 1566 | try testing.expectEqual(4, try r.readSliceShort(&buf)); |
| | 1567 | try testing.expectEqualStrings("Fren", buf[0..4]); |
| | 1568 | try testing.expectEqual(0, try r.readSliceShort(&buf)); |
| 1527 | } | 1569 | } |
| 1528 | | 1570 | |
| 1529 | test readVec { | 1571 | test readVec { |
| 1530 | return error.Unimplemented; | 1572 | var r: Reader = .fixed(std.ascii.letters); |
| | 1573 | var flat_buffer: [52]u8 = undefined; |
| | 1574 | var bufs: [2][]u8 = .{ |
| | 1575 | flat_buffer[0..26], |
| | 1576 | flat_buffer[26..], |
| | 1577 | }; |
| | 1578 | // Short reads are possible with this function but not with fixed. |
| | 1579 | try testing.expectEqual(26 * 2, try r.readVec(&bufs)); |
| | 1580 | try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]); |
| | 1581 | try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]); |
| | 1582 | } |
| | 1583 | |
| | 1584 | test readVecLimit { |
| | 1585 | var r: Reader = .fixed(std.ascii.letters); |
| | 1586 | var flat_buffer: [52]u8 = undefined; |
| | 1587 | var bufs: [2][]u8 = .{ |
| | 1588 | flat_buffer[0..26], |
| | 1589 | flat_buffer[26..], |
| | 1590 | }; |
| | 1591 | // Short reads are possible with this function but not with fixed. |
| | 1592 | try testing.expectEqual(50, try r.readVecLimit(&bufs, .limited(50))); |
| | 1593 | try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]); |
| | 1594 | try testing.expectEqualStrings(std.ascii.letters[26..50], bufs[1][0..24]); |
| 1531 | } | 1595 | } |
| 1532 | | 1596 | |
| 1533 | test "expected error.EndOfStream" { | 1597 | test "expected error.EndOfStream" { |