| ... | @@ -1594,7 +1594,10 @@ test containsAtLeast { | ... | @@ -1594,7 +1594,10 @@ test containsAtLeast { |
| 1594 | /// T specifies the return type, which must be large enough to store | 1594 | /// T specifies the return type, which must be large enough to store |
| 1595 | /// the result. | 1595 | /// the result. |
| 1596 | pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian) ReturnType { | 1596 | pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian) ReturnType { |
| 1597 | var result: ReturnType = 0; | 1597 | const bits = @typeInfo(ReturnType).Int.bits; |
| | 1598 | const signedness = @typeInfo(ReturnType).Int.signedness; |
| | 1599 | const WorkType = std.meta.Int(signedness, @max(16, bits)); |
| | 1600 | var result: WorkType = 0; |
| 1598 | switch (endian) { | 1601 | switch (endian) { |
| 1599 | .big => { | 1602 | .big => { |
| 1600 | for (bytes) |b| { | 1603 | for (bytes) |b| { |
| ... | @@ -1602,13 +1605,36 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian) | ... | @@ -1602,13 +1605,36 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian) |
| 1602 | } | 1605 | } |
| 1603 | }, | 1606 | }, |
| 1604 | .little => { | 1607 | .little => { |
| 1605 | const ShiftType = math.Log2Int(ReturnType); | 1608 | const ShiftType = math.Log2Int(WorkType); |
| 1606 | for (bytes, 0..) |b, index| { | 1609 | for (bytes, 0..) |b, index| { |
| 1607 | result = result | (@as(ReturnType, b) << @as(ShiftType, @intCast(index * 8))); | 1610 | result = result | (@as(WorkType, b) << @as(ShiftType, @intCast(index * 8))); |
| 1608 | } | 1611 | } |
| 1609 | }, | 1612 | }, |
| 1610 | } | 1613 | } |
| 1611 | return result; | 1614 | return @as(ReturnType, @truncate(result)); |
| | 1615 | } |
| | 1616 | |
| | 1617 | test readVarInt { |
| | 1618 | try testing.expect(readVarInt(u0, &[_]u8{}, .big) == 0x0); |
| | 1619 | try testing.expect(readVarInt(u0, &[_]u8{}, .little) == 0x0); |
| | 1620 | try testing.expect(readVarInt(u8, &[_]u8{0x12}, .big) == 0x12); |
| | 1621 | try testing.expect(readVarInt(u8, &[_]u8{0xde}, .little) == 0xde); |
| | 1622 | try testing.expect(readVarInt(u16, &[_]u8{ 0x12, 0x34 }, .big) == 0x1234); |
| | 1623 | try testing.expect(readVarInt(u16, &[_]u8{ 0x12, 0x34 }, .little) == 0x3412); |
| | 1624 | |
| | 1625 | try testing.expect(readVarInt(i8, &[_]u8{0xff}, .big) == -1); |
| | 1626 | try testing.expect(readVarInt(i8, &[_]u8{0xfe}, .little) == -2); |
| | 1627 | try testing.expect(readVarInt(i16, &[_]u8{ 0xff, 0xfd }, .big) == -3); |
| | 1628 | try testing.expect(readVarInt(i16, &[_]u8{ 0xfc, 0xff }, .little) == -4); |
| | 1629 | |
| | 1630 | // Return type can be oversized (bytes.len * 8 < @typeInfo(ReturnType).Int.bits) |
| | 1631 | try testing.expect(readVarInt(u9, &[_]u8{0x12}, .little) == 0x12); |
| | 1632 | try testing.expect(readVarInt(u9, &[_]u8{0xde}, .big) == 0xde); |
| | 1633 | try testing.expect(readVarInt(u80, &[_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }, .big) == 0x123456789abcdef024); |
| | 1634 | try testing.expect(readVarInt(u80, &[_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }, .little) == 0xfedcba9876543210ec); |
| | 1635 | |
| | 1636 | try testing.expect(readVarInt(i9, &[_]u8{0xff}, .big) == 0xff); |
| | 1637 | try testing.expect(readVarInt(i9, &[_]u8{0xfe}, .little) == 0xfe); |
| 1612 | } | 1638 | } |
| 1613 | | 1639 | |
| 1614 | /// Loads an integer from packed memory with provided bit_count, bit_offset, and signedness. | 1640 | /// Loads an integer from packed memory with provided bit_count, bit_offset, and signedness. |