authorgravatar for tgschultz@gmail.comtgschultz <tgschultz@gmail.com> 2019-04-03 15:47:46+00:00
committergravatar for tgschultz@gmail.comtgschultz <tgschultz@gmail.com> 2019-04-03 15:47:46+00:00
logba774c5697e5dcdf0f0676e2077a3034c310baf3
treedc4df11aed4e9f5828f391dd37b008a3bc5435ad
parent85edf55b73acda669a2388949d7cf31118d70764

(De)serializer now uses enum instead of bool to determine packing mode (byte/bit).

Optional is initialized in a more straight-forward way by deserializer.

2 files changed, 55 insertions(+), 51 deletions(-)

std/io.zig+27-23
...@@ -1088,6 +1088,11 @@ test "io.readLineSliceFrom" {...@@ -1088,6 +1088,11 @@ test "io.readLineSliceFrom" {
1088 testing.expectError(error.OutOfMemory, readLineSliceFrom(stream, buf[0..]));1088 testing.expectError(error.OutOfMemory, readLineSliceFrom(stream, buf[0..]));
1089}1089}
10901090
1091pub const Packing = enum {
1092 Byte, /// Pack data to byte alignment
1093 Bit, /// Pack data to bit alignment
1094};
1095
1091/// Creates a deserializer that deserializes types from any stream.1096/// Creates a deserializer that deserializes types from any stream.
1092/// If `is_packed` is true, the data stream is treated as bit-packed,1097/// If `is_packed` is true, the data stream is treated as bit-packed,
1093/// otherwise data is expected to be packed to the smallest byte.1098/// otherwise data is expected to be packed to the smallest byte.
...@@ -1097,18 +1102,18 @@ test "io.readLineSliceFrom" {...@@ -1097,18 +1102,18 @@ test "io.readLineSliceFrom" {
1097/// which will be called when the deserializer is used to deserialize1102/// which will be called when the deserializer is used to deserialize
1098/// that type. It will pass a pointer to the type instance to deserialize1103/// that type. It will pass a pointer to the type instance to deserialize
1099/// into and a pointer to the deserializer struct.1104/// into and a pointer to the deserializer struct.
1100pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime Error: type) type {1105pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime Error: type) type {
1101 return struct {1106 return struct {
1102 const Self = @This();1107 const Self = @This();
11031108
1104 in_stream: if (is_packed) BitInStream(endian, Stream.Error) else *Stream,1109 in_stream: if (packing == .Bit) BitInStream(endian, Stream.Error) else *Stream,
11051110
1106 pub const Stream = InStream(Error);1111 pub const Stream = InStream(Error);
11071112
1108 pub fn init(in_stream: *Stream) Self {1113 pub fn init(in_stream: *Stream) Self {
1109 return Self{ .in_stream = switch (is_packed) {1114 return Self{ .in_stream = switch (packing) {
1110 true => BitInStream(endian, Stream.Error).init(in_stream),1115 .Bit => BitInStream(endian, Stream.Error).init(in_stream),
1111 else => in_stream,1116 .Byte => in_stream,
1112 } };1117 } };
1113 }1118 }
11141119
...@@ -1128,7 +1133,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E...@@ -1128,7 +1133,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
1128 const Log2U = math.Log2Int(U);1133 const Log2U = math.Log2Int(U);
1129 const int_size = (U.bit_count + 7) / 8;1134 const int_size = (U.bit_count + 7) / 8;
11301135
1131 if (is_packed) {1136 if (packing == .Bit) {
1132 const result = try self.in_stream.readBitsNoEof(U, t_bit_count);1137 const result = try self.in_stream.readBitsNoEof(U, t_bit_count);
1133 return @bitCast(T, result);1138 return @bitCast(T, result);
1134 }1139 }
...@@ -1211,8 +1216,8 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E...@@ -1211,8 +1216,8 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
1211 //custom deserializer: fn(self: *Self, deserializer: var) !void1216 //custom deserializer: fn(self: *Self, deserializer: var) !void
1212 if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self);1217 if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self);
12131218
1214 if (comptime trait.isPacked(C) and !is_packed) {1219 if (comptime trait.isPacked(C) and packing != .Bit) {
1215 var packed_deserializer = Deserializer(endian, true, Error).init(self.in_stream);1220 var packed_deserializer = Deserializer(endian, .Bit, Error).init(self.in_stream);
1216 return packed_deserializer.deserializeInto(ptr);1221 return packed_deserializer.deserializeInto(ptr);
1217 }1222 }
12181223
...@@ -1276,14 +1281,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E...@@ -1276,14 +1281,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
1276 ptr.* = null;1281 ptr.* = null;
1277 return;1282 return;
1278 }1283 }
12791284
1285 //This should ensure that the optional is set to non-null.
1286 ptr.* = OC(undefined);
1280 //The way non-pointer optionals are implemented ensures a pointer to them1287 //The way non-pointer optionals are implemented ensures a pointer to them
1281 // will point to the value. The flag is stored at the end of that data.1288 // will point to the value. The flag is stored at the end of that data.
1282 var val_ptr = @ptrCast(*OC, ptr);1289 var val_ptr = @ptrCast(*OC, ptr);
1283 try self.deserializeInto(val_ptr);1290 try self.deserializeInto(val_ptr);
1284 //This bit ensures the null flag isn't set. Any actual copying should be
1285 // optimized out... I hope.
1286 ptr.* = val_ptr.*;
1287 },1291 },
1288 builtin.TypeId.Enum => {1292 builtin.TypeId.Enum => {
1289 var value = try self.deserializeInt(@TagType(C));1293 var value = try self.deserializeInt(@TagType(C));
...@@ -1310,24 +1314,24 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E...@@ -1310,24 +1314,24 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
1310/// which will be called when the serializer is used to serialize that type. It will1314/// which will be called when the serializer is used to serialize that type. It will
1311/// pass a const pointer to the type instance to be serialized and a pointer1315/// pass a const pointer to the type instance to be serialized and a pointer
1312/// to the serializer struct.1316/// to the serializer struct.
1313pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, comptime Error: type) type {1317pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime Error: type) type {
1314 return struct {1318 return struct {
1315 const Self = @This();1319 const Self = @This();
13161320
1317 out_stream: if (is_packed) BitOutStream(endian, Stream.Error) else *Stream,1321 out_stream: if (packing == .Bit) BitOutStream(endian, Stream.Error) else *Stream,
13181322
1319 pub const Stream = OutStream(Error);1323 pub const Stream = OutStream(Error);
13201324
1321 pub fn init(out_stream: *Stream) Self {1325 pub fn init(out_stream: *Stream) Self {
1322 return Self{ .out_stream = switch (is_packed) {1326 return Self{ .out_stream = switch (packing) {
1323 true => BitOutStream(endian, Stream.Error).init(out_stream),1327 .Bit => BitOutStream(endian, Stream.Error).init(out_stream),
1324 else => out_stream,1328 .Byte => out_stream,
1325 } };1329 } };
1326 }1330 }
13271331
1328 /// Flushes any unwritten bits to the stream1332 /// Flushes any unwritten bits to the stream
1329 pub fn flush(self: *Self) Error!void {1333 pub fn flush(self: *Self) Error!void {
1330 if (is_packed) return self.out_stream.flushBits();1334 if (packing == .Bit) return self.out_stream.flushBits();
1331 }1335 }
13321336
1333 fn serializeInt(self: *Self, value: var) Error!void {1337 fn serializeInt(self: *Self, value: var) Error!void {
...@@ -1343,15 +1347,15 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com...@@ -1343,15 +1347,15 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com
13431347
1344 const u_value = @bitCast(U, value);1348 const u_value = @bitCast(U, value);
13451349
1346 if (is_packed) return self.out_stream.writeBits(u_value, t_bit_count);1350 if (packing == .Bit) return self.out_stream.writeBits(u_value, t_bit_count);
13471351
1348 var buffer: [int_size]u8 = undefined;1352 var buffer: [int_size]u8 = undefined;
1349 if (int_size == 1) buffer[0] = u_value;1353 if (int_size == 1) buffer[0] = u_value;
13501354
1351 for (buffer) |*byte, i| {1355 for (buffer) |*byte, i| {
1352 const idx = switch (endian) {1356 const idx = switch (endian) {
1353 builtin.Endian.Big => int_size - i - 1,1357 .Big => int_size - i - 1,
1354 builtin.Endian.Little => i,1358 .Little => i,
1355 };1359 };
1356 const shift = @intCast(Log2U, idx * u8_bit_count);1360 const shift = @intCast(Log2U, idx * u8_bit_count);
1357 const v = u_value >> shift;1361 const v = u_value >> shift;
...@@ -1374,8 +1378,8 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com...@@ -1374,8 +1378,8 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com
1374 //custom serializer: fn(self: Self, serializer: var) !void1378 //custom serializer: fn(self: Self, serializer: var) !void
1375 if (comptime trait.hasFn("serialize")(T)) return T.serialize(value, self);1379 if (comptime trait.hasFn("serialize")(T)) return T.serialize(value, self);
13761380
1377 if (comptime trait.isPacked(T) and !is_packed) {1381 if (comptime trait.isPacked(T) and packing != .Bit) {
1378 var packed_serializer = Serializer(endian, true, Error).init(self.out_stream);1382 var packed_serializer = Serializer(endian, .Bit, Error).init(self.out_stream);
1379 try packed_serializer.serialize(value);1383 try packed_serializer.serialize(value);
1380 try packed_serializer.flush();1384 try packed_serializer.flush();
1381 return;1385 return;
std/io_test.zig+28-28
...@@ -318,7 +318,7 @@ test "BitStreams with File Stream" {...@@ -318,7 +318,7 @@ test "BitStreams with File Stream" {
318 try os.deleteFile(tmp_file_name);318 try os.deleteFile(tmp_file_name);
319}319}
320320
321fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void {321fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
322 //@NOTE: if this test is taking too long, reduce the maximum tested bitsize322 //@NOTE: if this test is taking too long, reduce the maximum tested bitsize
323 const max_test_bitsize = 128;323 const max_test_bitsize = 128;
324324
...@@ -333,12 +333,12 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa...@@ -333,12 +333,12 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa
333 var out = io.SliceOutStream.init(data_mem[0..]);333 var out = io.SliceOutStream.init(data_mem[0..]);
334 const OutError = io.SliceOutStream.Error;334 const OutError = io.SliceOutStream.Error;
335 var out_stream = &out.stream;335 var out_stream = &out.stream;
336 var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);336 var serializer = io.Serializer(endian, packing, OutError).init(out_stream);
337337
338 var in = io.SliceInStream.init(data_mem[0..]);338 var in = io.SliceInStream.init(data_mem[0..]);
339 const InError = io.SliceInStream.Error;339 const InError = io.SliceInStream.Error;
340 var in_stream = &in.stream;340 var in_stream = &in.stream;
341 var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);341 var deserializer = io.Deserializer(endian, packing, InError).init(in_stream);
342342
343 comptime var i = 0;343 comptime var i = 0;
344 inline while (i <= max_test_bitsize) : (i += 1) {344 inline while (i <= max_test_bitsize) : (i += 1) {
...@@ -366,21 +366,21 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa...@@ -366,21 +366,21 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa
366 const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0);366 const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0);
367 const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte;367 const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte;
368368
369 expect(in.pos == if (is_packed) total_packed_bytes else total_bytes);369 expect(in.pos == if (packing == .Bit) total_packed_bytes else total_bytes);
370370
371 //Verify that empty error set works with serializer.371 //Verify that empty error set works with serializer.
372 //deserializer is covered by SliceInStream372 //deserializer is covered by SliceInStream
373 const NullError = io.NullOutStream.Error;373 const NullError = io.NullOutStream.Error;
374 var null_out = io.NullOutStream.init();374 var null_out = io.NullOutStream.init();
375 var null_out_stream = &null_out.stream;375 var null_out_stream = &null_out.stream;
376 var null_serializer = io.Serializer(endian, is_packed, NullError).init(null_out_stream);376 var null_serializer = io.Serializer(endian, packing, NullError).init(null_out_stream);
377 try null_serializer.serialize(data_mem[0..]);377 try null_serializer.serialize(data_mem[0..]);
378 try null_serializer.flush();378 try null_serializer.flush();
379}379}
380380
381test "Serializer/Deserializer Int" {381test "Serializer/Deserializer Int" {
382 try testIntSerializerDeserializer(builtin.Endian.Big, false);382 try testIntSerializerDeserializer(.Big, .Byte);
383 try testIntSerializerDeserializer(builtin.Endian.Little, false);383 try testIntSerializerDeserializer(.Little, .Byte);
384 // TODO these tests are disabled due to tripping an LLVM assertion384 // TODO these tests are disabled due to tripping an LLVM assertion
385 // https://github.com/ziglang/zig/issues/2019385 // https://github.com/ziglang/zig/issues/2019
386 //try testIntSerializerDeserializer(builtin.Endian.Big, true);386 //try testIntSerializerDeserializer(builtin.Endian.Big, true);
...@@ -389,7 +389,7 @@ test "Serializer/Deserializer Int" {...@@ -389,7 +389,7 @@ test "Serializer/Deserializer Int" {
389389
390fn testIntSerializerDeserializerInfNaN(390fn testIntSerializerDeserializerInfNaN(
391 comptime endian: builtin.Endian,391 comptime endian: builtin.Endian,
392 comptime is_packed: bool,392 comptime packing: io.Packing,
393) !void {393) !void {
394 const mem_size = (16 * 2 + 32 * 2 + 64 * 2 + 128 * 2) / comptime meta.bitCount(u8);394 const mem_size = (16 * 2 + 32 * 2 + 64 * 2 + 128 * 2) / comptime meta.bitCount(u8);
395 var data_mem: [mem_size]u8 = undefined;395 var data_mem: [mem_size]u8 = undefined;
...@@ -397,12 +397,12 @@ fn testIntSerializerDeserializerInfNaN(...@@ -397,12 +397,12 @@ fn testIntSerializerDeserializerInfNaN(
397 var out = io.SliceOutStream.init(data_mem[0..]);397 var out = io.SliceOutStream.init(data_mem[0..]);
398 const OutError = io.SliceOutStream.Error;398 const OutError = io.SliceOutStream.Error;
399 var out_stream = &out.stream;399 var out_stream = &out.stream;
400 var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);400 var serializer = io.Serializer(endian, packing, OutError).init(out_stream);
401401
402 var in = io.SliceInStream.init(data_mem[0..]);402 var in = io.SliceInStream.init(data_mem[0..]);
403 const InError = io.SliceInStream.Error;403 const InError = io.SliceInStream.Error;
404 var in_stream = &in.stream;404 var in_stream = &in.stream;
405 var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);405 var deserializer = io.Deserializer(endian, packing, InError).init(in_stream);
406406
407 //@TODO: isInf/isNan not currently implemented for f128.407 //@TODO: isInf/isNan not currently implemented for f128.
408 try serializer.serialize(std.math.nan(f16));408 try serializer.serialize(std.math.nan(f16));
...@@ -432,17 +432,17 @@ fn testIntSerializerDeserializerInfNaN(...@@ -432,17 +432,17 @@ fn testIntSerializerDeserializerInfNaN(
432}432}
433433
434test "Serializer/Deserializer Int: Inf/NaN" {434test "Serializer/Deserializer Int: Inf/NaN" {
435 try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, false);435 try testIntSerializerDeserializerInfNaN(.Big, .Byte);
436 try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, false);436 try testIntSerializerDeserializerInfNaN(.Little, .Byte);
437 try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, true);437 try testIntSerializerDeserializerInfNaN(.Big, .Bit);
438 try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, true);438 try testIntSerializerDeserializerInfNaN(.Little, .Bit);
439}439}
440440
441fn testAlternateSerializer(self: var, serializer: var) !void {441fn testAlternateSerializer(self: var, serializer: var) !void {
442 try serializer.serialize(self.f_f16);442 try serializer.serialize(self.f_f16);
443}443}
444444
445fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void {445fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
446 const ColorType = enum(u4) {446 const ColorType = enum(u4) {
447 RGB8 = 1,447 RGB8 = 1,
448 RA16 = 2,448 RA16 = 2,
...@@ -529,12 +529,12 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe...@@ -529,12 +529,12 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe
529 var out = io.SliceOutStream.init(data_mem[0..]);529 var out = io.SliceOutStream.init(data_mem[0..]);
530 const OutError = io.SliceOutStream.Error;530 const OutError = io.SliceOutStream.Error;
531 var out_stream = &out.stream;531 var out_stream = &out.stream;
532 var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);532 var serializer = io.Serializer(endian, packing, OutError).init(out_stream);
533533
534 var in = io.SliceInStream.init(data_mem[0..]);534 var in = io.SliceInStream.init(data_mem[0..]);
535 const InError = io.SliceInStream.Error;535 const InError = io.SliceInStream.Error;
536 var in_stream = &in.stream;536 var in_stream = &in.stream;
537 var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);537 var deserializer = io.Deserializer(endian, packing, InError).init(in_stream);
538538
539 try serializer.serialize(my_inst);539 try serializer.serialize(my_inst);
540540
...@@ -543,13 +543,13 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe...@@ -543,13 +543,13 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe
543}543}
544544
545test "Serializer/Deserializer generic" {545test "Serializer/Deserializer generic" {
546 try testSerializerDeserializer(builtin.Endian.Big, false);546 try testSerializerDeserializer(builtin.Endian.Big, .Byte);
547 try testSerializerDeserializer(builtin.Endian.Little, false);547 try testSerializerDeserializer(builtin.Endian.Little, .Byte);
548 try testSerializerDeserializer(builtin.Endian.Big, true);548 try testSerializerDeserializer(builtin.Endian.Big, .Bit);
549 try testSerializerDeserializer(builtin.Endian.Little, true);549 try testSerializerDeserializer(builtin.Endian.Little, .Bit);
550}550}
551551
552fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void {552fn testBadData(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
553 const E = enum(u14) {553 const E = enum(u14) {
554 One = 1,554 One = 1,
555 Two = 2,555 Two = 2,
...@@ -568,12 +568,12 @@ fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void...@@ -568,12 +568,12 @@ fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void
568 var out = io.SliceOutStream.init(data_mem[0..]);568 var out = io.SliceOutStream.init(data_mem[0..]);
569 const OutError = io.SliceOutStream.Error;569 const OutError = io.SliceOutStream.Error;
570 var out_stream = &out.stream;570 var out_stream = &out.stream;
571 var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);571 var serializer = io.Serializer(endian, packing, OutError).init(out_stream);
572572
573 var in = io.SliceInStream.init(data_mem[0..]);573 var in = io.SliceInStream.init(data_mem[0..]);
574 const InError = io.SliceInStream.Error;574 const InError = io.SliceInStream.Error;
575 var in_stream = &in.stream;575 var in_stream = &in.stream;
576 var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);576 var deserializer = io.Deserializer(endian, packing, InError).init(in_stream);
577577
578 try serializer.serialize(u14(3));578 try serializer.serialize(u14(3));
579 expectError(error.InvalidEnumTag, deserializer.deserialize(A));579 expectError(error.InvalidEnumTag, deserializer.deserialize(A));
...@@ -584,8 +584,8 @@ fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void...@@ -584,8 +584,8 @@ fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void
584}584}
585585
586test "Deserializer bad data" {586test "Deserializer bad data" {
587 try testBadData(builtin.Endian.Big, false);587 try testBadData(.Big, .Byte);
588 try testBadData(builtin.Endian.Little, false);588 try testBadData(.Little, .Byte);
589 try testBadData(builtin.Endian.Big, true);589 try testBadData(.Big, .Bit);
590 try testBadData(builtin.Endian.Little, true);590 try testBadData(.Little, .Bit);
591}591}