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