| ... | @@ -1094,33 +1094,41 @@ pub inline fn takeInt(r: *Reader, comptime T: type, endian: std.builtin.Endian) | ... | @@ -1094,33 +1094,41 @@ pub inline fn takeInt(r: *Reader, comptime T: type, endian: std.builtin.Endian) |
| 1094 | return std.mem.readInt(T, try r.takeArray(n), endian); | 1094 | return std.mem.readInt(T, try r.takeArray(n), endian); |
| 1095 | } | 1095 | } |
| 1096 | | 1096 | |
| | 1097 | /// Asserts the buffer was initialized with a capacity at least `@bitSizeOf(T) / 8`. |
| | 1098 | pub inline fn peekInt(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { |
| | 1099 | const n = @divExact(@typeInfo(T).int.bits, 8); |
| | 1100 | return std.mem.readInt(T, try r.peekArray(n), endian); |
| | 1101 | } |
| | 1102 | |
| 1097 | /// Asserts the buffer was initialized with a capacity at least `n`. | 1103 | /// Asserts the buffer was initialized with a capacity at least `n`. |
| 1098 | pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n: usize) Error!Int { | 1104 | pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n: usize) Error!Int { |
| 1099 | assert(n <= @sizeOf(Int)); | 1105 | assert(n <= @sizeOf(Int)); |
| 1100 | return std.mem.readVarInt(Int, try r.take(n), endian); | 1106 | return std.mem.readVarInt(Int, try r.take(n), endian); |
| 1101 | } | 1107 | } |
| 1102 | | 1108 | |
| 1103 | /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. | 1109 | /// Obtains an unaligned pointer to the beginning of the stream, reinterpreted |
| | 1110 | /// as a pointer to the provided type, advancing the seek position. |
| 1104 | /// | 1111 | /// |
| 1105 | /// Advances the seek position. | 1112 | /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. |
| 1106 | /// | 1113 | /// |
| 1107 | /// See also: | 1114 | /// See also: |
| 1108 | /// * `peekStruct` | 1115 | /// * `peekStructReference` |
| 1109 | /// * `takeStructEndian` | 1116 | /// * `takeStruct` |
| 1110 | pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T { | 1117 | pub fn takeStructReference(r: *Reader, comptime T: type) Error!*align(1) T { |
| 1111 | // Only extern and packed structs have defined in-memory layout. | 1118 | // Only extern and packed structs have defined in-memory layout. |
| 1112 | comptime assert(@typeInfo(T).@"struct".layout != .auto); | 1119 | comptime assert(@typeInfo(T).@"struct".layout != .auto); |
| 1113 | return @ptrCast(try r.takeArray(@sizeOf(T))); | 1120 | return @ptrCast(try r.takeArray(@sizeOf(T))); |
| 1114 | } | 1121 | } |
| 1115 | | 1122 | |
| 1116 | /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. | 1123 | /// Obtains an unaligned pointer to the beginning of the stream, reinterpreted |
| | 1124 | /// as a pointer to the provided type, without advancing the seek position. |
| 1117 | /// | 1125 | /// |
| 1118 | /// Does not advance the seek position. | 1126 | /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. |
| 1119 | /// | 1127 | /// |
| 1120 | /// See also: | 1128 | /// See also: |
| 1121 | /// * `takeStruct` | 1129 | /// * `takeStructReference` |
| 1122 | /// * `peekStructEndian` | 1130 | /// * `peekStruct` |
| 1123 | pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T { | 1131 | pub fn peekStructReference(r: *Reader, comptime T: type) Error!*align(1) T { |
| 1124 | // Only extern and packed structs have defined in-memory layout. | 1132 | // Only extern and packed structs have defined in-memory layout. |
| 1125 | comptime assert(@typeInfo(T).@"struct".layout != .auto); | 1133 | comptime assert(@typeInfo(T).@"struct".layout != .auto); |
| 1126 | return @ptrCast(try r.peekArray(@sizeOf(T))); | 1134 | return @ptrCast(try r.peekArray(@sizeOf(T))); |
| ... | @@ -1132,12 +1140,23 @@ pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T { | ... | @@ -1132,12 +1140,23 @@ pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T { |
| 1132 | /// when `endian` is comptime-known and matches the host endianness. | 1140 | /// when `endian` is comptime-known and matches the host endianness. |
| 1133 | /// | 1141 | /// |
| 1134 | /// See also: | 1142 | /// See also: |
| 1135 | /// * `takeStruct` | 1143 | /// * `takeStructReference` |
| 1136 | /// * `peekStructEndian` | 1144 | /// * `peekStruct` |
| 1137 | pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { | 1145 | pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { |
| 1138 | var res = (try r.takeStruct(T)).*; | 1146 | switch (@typeInfo(T)) { |
| 1139 | if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); | 1147 | .@"struct" => |info| switch (info.layout) { |
| 1140 | return res; | 1148 | .auto => @compileError("ill-defined memory layout"), |
| | 1149 | .@"extern" => { |
| | 1150 | var res = (try r.takeStructReference(T)).*; |
| | 1151 | if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); |
| | 1152 | return res; |
| | 1153 | }, |
| | 1154 | .@"packed" => { |
| | 1155 | return takeInt(r, info.backing_integer.?, endian); |
| | 1156 | }, |
| | 1157 | }, |
| | 1158 | else => @compileError("not a struct"), |
| | 1159 | } |
| 1141 | } | 1160 | } |
| 1142 | | 1161 | |
| 1143 | /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. | 1162 | /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. |
| ... | @@ -1146,12 +1165,23 @@ pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin | ... | @@ -1146,12 +1165,23 @@ pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin |
| 1146 | /// when `endian` is comptime-known and matches the host endianness. | 1165 | /// when `endian` is comptime-known and matches the host endianness. |
| 1147 | /// | 1166 | /// |
| 1148 | /// See also: | 1167 | /// See also: |
| 1149 | /// * `takeStructEndian` | 1168 | /// * `takeStruct` |
| 1150 | /// * `peekStruct` | 1169 | /// * `peekStructReference` |
| 1151 | pub inline fn peekStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { | 1170 | pub inline fn peekStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T { |
| 1152 | var res = (try r.peekStruct(T)).*; | 1171 | switch (@typeInfo(T)) { |
| 1153 | if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); | 1172 | .@"struct" => |info| switch (info.layout) { |
| 1154 | return res; | 1173 | .auto => @compileError("ill-defined memory layout"), |
| | 1174 | .@"extern" => { |
| | 1175 | var res = (try r.peekStructReference(T)).*; |
| | 1176 | if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); |
| | 1177 | return res; |
| | 1178 | }, |
| | 1179 | .@"packed" => { |
| | 1180 | return peekInt(r, info.backing_integer.?, endian); |
| | 1181 | }, |
| | 1182 | }, |
| | 1183 | else => @compileError("not a struct"), |
| | 1184 | } |
| 1155 | } | 1185 | } |
| 1156 | | 1186 | |
| 1157 | pub const TakeEnumError = Error || error{InvalidEnumTag}; | 1187 | pub const TakeEnumError = Error || error{InvalidEnumTag}; |
| ... | @@ -1517,43 +1547,43 @@ test takeVarInt { | ... | @@ -1517,43 +1547,43 @@ test takeVarInt { |
| 1517 | try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1)); | 1547 | try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1)); |
| 1518 | } | 1548 | } |
| 1519 | | 1549 | |
| 1520 | test takeStruct { | 1550 | test takeStructReference { |
| 1521 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); | 1551 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); |
| 1522 | const S = extern struct { a: u8, b: u16 }; | 1552 | const S = extern struct { a: u8, b: u16 }; |
| 1523 | switch (native_endian) { | 1553 | switch (native_endian) { |
| 1524 | .little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStruct(S)).*), | 1554 | .little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStructReference(S)).*), |
| 1525 | .big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStruct(S)).*), | 1555 | .big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStructReference(S)).*), |
| 1526 | } | 1556 | } |
| 1527 | try testing.expectError(error.EndOfStream, r.takeStruct(S)); | 1557 | try testing.expectError(error.EndOfStream, r.takeStructReference(S)); |
| 1528 | } | 1558 | } |
| 1529 | | 1559 | |
| 1530 | test peekStruct { | 1560 | test peekStructReference { |
| 1531 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); | 1561 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); |
| 1532 | const S = extern struct { a: u8, b: u16 }; | 1562 | const S = extern struct { a: u8, b: u16 }; |
| 1533 | switch (native_endian) { | 1563 | switch (native_endian) { |
| 1534 | .little => { | 1564 | .little => { |
| 1535 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*); | 1565 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructReference(S)).*); |
| 1536 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*); | 1566 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructReference(S)).*); |
| 1537 | }, | 1567 | }, |
| 1538 | .big => { | 1568 | .big => { |
| 1539 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*); | 1569 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructReference(S)).*); |
| 1540 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*); | 1570 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructReference(S)).*); |
| 1541 | }, | 1571 | }, |
| 1542 | } | 1572 | } |
| 1543 | } | 1573 | } |
| 1544 | | 1574 | |
| 1545 | test takeStructEndian { | 1575 | test takeStruct { |
| 1546 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); | 1576 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); |
| 1547 | const S = extern struct { a: u8, b: u16 }; | 1577 | const S = extern struct { a: u8, b: u16 }; |
| 1548 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.takeStructEndian(S, .big)); | 1578 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.takeStruct(S, .big)); |
| 1549 | try testing.expectError(error.EndOfStream, r.takeStructEndian(S, .little)); | 1579 | try testing.expectError(error.EndOfStream, r.takeStruct(S, .little)); |
| 1550 | } | 1580 | } |
| 1551 | | 1581 | |
| 1552 | test peekStructEndian { | 1582 | test peekStruct { |
| 1553 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); | 1583 | var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 }); |
| 1554 | const S = extern struct { a: u8, b: u16 }; | 1584 | const S = extern struct { a: u8, b: u16 }; |
| 1555 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.peekStructEndian(S, .big)); | 1585 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.peekStruct(S, .big)); |
| 1556 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), try r.peekStructEndian(S, .little)); | 1586 | try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), try r.peekStruct(S, .little)); |
| 1557 | } | 1587 | } |
| 1558 | | 1588 | |
| 1559 | test takeEnum { | 1589 | test takeEnum { |