@@ 8,362 8,351 @@ pub const DecodeError = error{ Overflow, InvalidUnion };
/// Decodes BARE messages.
/// Uses an internal arena backed by the passed-in allocator.
-pub const Decoder = struct {
- arena: std.heap.ArenaAllocator,
- const Self = @This();
-
- /// Call `deinit` when done.
- pub fn init(allocator: mem.Allocator) Self {
- return .{
- .arena = std.heap.ArenaAllocator.init(allocator),
- };
- }
+pub fn Decoder(comptime ReaderType: type) type {
+ return struct {
+ arena: std.heap.ArenaAllocator,
+ reader: ReaderType,
+ const Self = @This();
+
+ /// Call `deinit` when done.
+ pub fn init(reader: ReaderType, allocator: mem.Allocator) Self {
+ return .{
+ .arena = std.heap.ArenaAllocator.init(allocator),
+ .reader = reader,
+ };
+ }
- /// Free everything in the internal arena allocator.
- pub fn deinit(self: *Self) void {
- self.arena.deinit();
- }
+ /// Free everything in the internal arena allocator.
+ pub fn deinit(self: *Self) void {
+ self.arena.deinit();
+ }
- /// Decode a supported BARE type.
- pub fn decode(self: *Self, comptime T: type, reader: anytype) !ReturnType(T) {
- return switch (@typeInfo(T)) {
- .Int => self.decodeInt(T, reader),
- .Float => self.decodeFloat(T, reader),
- .Bool => self.decodeBool(reader),
- .Struct => if (comptime isHashMap(T))
- self.decodeHashMap(T, reader)
- else
- self.decodeStruct(T, reader),
- .Enum => self.decodeEnum(T, reader),
- .Optional => self.decodeOptional(T, reader),
- .Array => self.decodeArray(T, reader),
- .Union => self.decodeUnion(T, reader),
- .Pointer => self.decodePointer(T, reader),
- else => @compileError("unsupported type " ++ @typeName(T)),
- };
- }
+ /// Decode a supported BARE type.
+ pub fn decode(self: *Self, comptime T: type) !ReturnType(T) {
+ return switch (@typeInfo(T)) {
+ .Int => self.decodeInt(T),
+ .Float => self.decodeFloat(T),
+ .Bool => self.decodeBool(),
+ .Struct => if (comptime isHashMap(T))
+ self.decodeHashMap(T)
+ else
+ self.decodeStruct(T),
+ .Enum => self.decodeEnum(T),
+ .Optional => self.decodeOptional(T),
+ .Array => self.decodeArray(T),
+ .Union => self.decodeUnion(T),
+ .Pointer => self.decodePointer(T),
+ else => @compileError("unsupported type " ++ @typeName(T)),
+ };
+ }
- fn decodeAllowVoid(self: *Self, comptime T: type, reader: anytype) !T {
- return switch (T) {
- void => {},
- else => self.decode(T, reader),
- };
- }
+ fn decodeAllowVoid(self: *Self, comptime T: type) !T {
+ return switch (T) {
+ void => {},
+ else => self.decode(T),
+ };
+ }
- fn decodeVarInt(self: *Self, reader: anytype) !i64 {
- const ux = try self.decodeVarUint(reader);
- return @intCast(i64, ux >> 1) ^ -@intCast(i64, ux & 1);
- }
+ fn decodeVarInt(self: *Self) !i64 {
+ const ux = try self.decodeVarUint();
+ return @intCast(i64, ux >> 1) ^ -@intCast(i64, ux & 1);
+ }
- fn decodeVarUint(self: *Self, reader: anytype) !u64 {
- _ = self;
+ fn decodeVarUint(self: *Self) !u64 {
+ var x: u64 = 0;
+ var s: u6 = 0;
+ var i: u4 = 0;
- var x: u64 = 0;
- var s: u6 = 0;
- var i: u4 = 0;
+ while (true) : (i += 1) {
+ const b = try self.reader.readByte();
+ x |= @intCast(u64, b & 0x7f) << s;
- while (true) : (i += 1) {
- const b = try reader.readByte();
- x |= @intCast(u64, b & 0x7f) << s;
+ if (b < 0x80) {
+ if (9 < i or i == 9 and 1 < b)
+ return DecodeError.Overflow;
- if (b < 0x80) {
- if (9 < i or i == 9 and 1 < b)
- return DecodeError.Overflow;
+ return x;
+ }
- return x;
+ if (@addWithOverflow(@TypeOf(s), s, 7, &s))
+ return DecodeError.Overflow;
}
- const ov = @addWithOverflow(s, 7);
-
- if (0 != ov[1])
- return DecodeError.Overflow;
-
- s = ov[0];
+ return 0;
}
- return 0;
- }
-
- fn decodeInt(self: *Self, comptime T: type, reader: anytype) !T {
- _ = self;
-
- return switch (@bitSizeOf(T)) {
- 8, 16, 32, 64 => reader.readIntLittle(T),
- else => @compileError("unsupported integer type " ++ @typeName(T)),
- };
- }
-
- fn decodeFloat(self: *Self, comptime T: type, reader: anytype) !T {
- _ = self;
-
- const bits = @bitSizeOf(T);
- return switch (bits) {
- 32, 64 => @bitCast(T, try reader.readIntLittle(meta.Int(.unsigned, bits))),
- else => @compileError("unsupported float type " ++ @typeName(T)),
- };
- }
+ fn decodeInt(self: *Self, comptime T: type) !T {
+ return switch (@bitSizeOf(T)) {
+ 8, 16, 32, 64 => self.reader.readIntLittle(T),
+ else => @compileError("unsupported integer type " ++ @typeName(T)),
+ };
+ }
- fn decodeBool(self: *Self, reader: anytype) !bool {
- _ = self;
+ fn decodeFloat(self: *Self, comptime T: type) !T {
+ const bits = @bitSizeOf(T);
+ return switch (bits) {
+ 32, 64 => @bitCast(T, try self.reader.readIntLittle(meta.Int(.unsigned, bits))),
+ else => @compileError("unsupported float type " ++ @typeName(T)),
+ };
+ }
- return 0 != try reader.readByte();
- }
+ fn decodeBool(self: *Self) !bool {
+ return 0 != try self.reader.readByte();
+ }
- fn decodeStruct(self: *Self, comptime T: type, reader: anytype) !T {
- const ti = @typeInfo(T).Struct;
- if (ti.fields.len < 1)
- @compileError("structs must have 1 or more fields");
+ fn decodeStruct(self: *Self, comptime T: type) !T {
+ const ti = @typeInfo(T).Struct;
+ if (ti.fields.len < 1)
+ @compileError("structs must have 1 or more fields");
- var s: T = undefined;
- inline for (ti.fields) |f|
- @field(s, f.name) = try self.decode(f.type, reader);
+ var s: T = undefined;
+ inline for (ti.fields) |f|
+ @field(s, f.name) = try self.decode(f.field_type);
- return s;
- }
+ return s;
+ }
- fn decodeEnum(self: *Self, comptime T: type, reader: anytype) !T {
- const TT = if (@hasDecl(meta, "Tag")) meta.Tag(T) else meta.TagType(T);
- return meta.intToEnum(T, @intCast(TT, try self.decodeVarUint(reader)));
- }
+ fn decodeEnum(self: *Self, comptime T: type) !T {
+ const TT = if (@hasDecl(meta, "Tag")) meta.Tag(T) else meta.TagType(T);
+ return meta.intToEnum(T, @intCast(TT, try self.decodeVarUint()));
+ }
- fn decodeOptional(self: *Self, comptime T: type, reader: anytype) !T {
- if (0x0 == try reader.readByte())
- return null;
+ fn decodeOptional(self: *Self, comptime T: type) !T {
+ if (0x0 == try self.reader.readByte())
+ return null;
- const type_info = @typeInfo(T);
- return @as(T, try self.decode(type_info.Optional.child, reader));
- }
+ const type_info = @typeInfo(T);
+ return @as(T, try self.decode(type_info.Optional.child));
+ }
- fn decodeArray(self: *Self, comptime T: type, reader: anytype) !T {
- const ti = @typeInfo(T).Array;
- if (ti.len < 1)
- @compileError("array length must be at least 1");
+ fn decodeArray(self: *Self, comptime T: type) !T {
+ const ti = @typeInfo(T).Array;
+ if (ti.len < 1)
+ @compileError("array length must be at least 1");
- var buf: [ti.len]ti.child = undefined;
- var i: usize = 0;
+ var buf: [ti.len]ti.child = undefined;
+ var i: usize = 0;
- while (i < ti.len) : (i += 1)
- buf[i] = try self.decode(ti.child, reader);
+ while (i < ti.len) : (i += 1)
+ buf[i] = try self.decode(ti.child);
- return buf;
- }
+ return buf;
+ }
- fn decodeUnion(self: *Self, comptime T: type, reader: anytype) !T {
- const ti = @typeInfo(T).Union;
+ fn decodeUnion(self: *Self, comptime T: type) !T {
+ const ti = @typeInfo(T).Union;
- if (ti.tag_type == null)
- @compileError("only tagged unions are supported");
+ if (ti.tag_type == null)
+ @compileError("only tagged unions are supported");
- const tag = try self.decodeVarUint(reader);
+ const tag = try self.decodeVarUint();
- inline for (ti.fields) |f| {
- if (tag == @enumToInt(@field(ti.tag_type.?, f.name))) {
- const v = try self.decodeAllowVoid(f.type, reader);
- return @unionInit(T, f.name, v);
+ inline for (ti.fields) |f| {
+ if (tag == @enumToInt(@field(ti.tag_type.?, f.name))) {
+ const v = try self.decodeAllowVoid(f.field_type);
+ return @unionInit(T, f.name, v);
+ }
}
+
+ return DecodeError.InvalidUnion;
}
- return DecodeError.InvalidUnion;
- }
+ fn decodePointer(self: *Self, comptime T: type) !T {
+ const ti = @typeInfo(T).Pointer;
- fn decodePointer(self: *Self, comptime T: type, reader: anytype) !T {
- const ti = @typeInfo(T).Pointer;
+ if (ti.size != .Slice)
+ @compileError("slices are the only supported pointer type");
- if (ti.size != .Slice)
- @compileError("slices are the only supported pointer type");
+ const len = try self.decodeVarUint();
+ var buf = try self.arena.allocator().alloc(ti.child, len);
- const len = try self.decodeVarUint(reader);
- var buf = try self.arena.allocator().alloc(ti.child, len);
+ var i: usize = 0;
+ while (i < len) : (i += 1)
+ buf[i] = try self.decode(ti.child);
- var i: usize = 0;
- while (i < len) : (i += 1)
- buf[i] = try self.decode(ti.child, reader);
+ return buf;
+ }
- return buf;
- }
+ fn decodeHashMap(self: *Self, comptime T: type) !T.Unmanaged {
+ const K = HashMapKeyType(T);
+ const V = HashMapValueType(T);
- fn decodeHashMap(self: *Self, comptime T: type, reader: anytype) !T.Unmanaged {
- const K = HashMapKeyType(T);
- const V = HashMapValueType(T);
+ if (comptime !isValidHashMapKeyType(K))
+ @compileError("unsupported hashmap key type " ++ @typeName(K));
- if (comptime !isValidHashMapKeyType(K))
- @compileError("unsupported hashmap key type " ++ @typeName(K));
+ var i = try self.decodeVarUint();
+ if (std.math.maxInt(T.Size) < i)
+ return DecodeError.Overflow;
- var i = try self.decodeVarUint(reader);
- if (std.math.maxInt(T.Size) < i)
- return DecodeError.Overflow;
+ var map = T.Unmanaged{};
+ try map.ensureUnusedCapacity(self.arena.allocator(), @intCast(T.Size, i));
- var map = T.Unmanaged{};
- try map.ensureUnusedCapacity(self.arena.allocator(), @intCast(T.Size, i));
+ while (i != 0) : (i -= 1) {
+ const key = try self.decode(K);
+ const val = try self.decode(V);
+ _ = map.putAssumeCapacity(key, val);
+ }
- while (i != 0) : (i -= 1) {
- const key = try self.decode(K, reader);
- const val = try self.decode(V, reader);
- _ = map.putAssumeCapacity(key, val);
+ return map;
}
- return map;
- }
-
- fn ReturnType(comptime T: type) type {
- return if (isHashMap(T)) T.Unmanaged else T;
- }
-};
+ fn ReturnType(comptime T: type) type {
+ return if (isHashMap(T)) T.Unmanaged else T;
+ }
+ };
+}
/// Encodes a BARE message.
-pub const Encoder = struct {
- const Self = @This();
-
- /// No `deinit` needed.
- pub fn init() Self {
- return .{};
- }
-
- /// Encode a supported BARE type.
- pub fn encode(self: *Self, value: anytype, writer: anytype) !void {
- const T = @TypeOf(value);
- return switch (@typeInfo(T)) {
- .Int => self.encodeInt(T, value, writer),
- .Float => self.encodeFloat(T, value, writer),
- .Bool => self.encodeBool(value, writer),
- .Struct => if (comptime isHashMap(T))
- self.encodeHashMap(value, writer)
- else
- self.encodeStruct(value, writer),
- .Enum => self.encodeEnum(value, writer),
- .Optional => self.encodeOptional(value, writer),
- .Array => self.encodeArray(value, writer),
- .Union => self.encodeUnion(value, writer),
- .Pointer => self.encodePointer(value, writer),
- else => @compileError("unsupported type " ++ @typeName(T)),
- };
- }
-
- fn encodeAllowVoid(self: *Self, value: anytype, writer: anytype) !void {
- return switch (@TypeOf(value)) {
- void => {},
- else => self.encode(value, writer),
- };
- }
-
- fn encodeVarUint(self: *Self, value: u64, writer: anytype) !void {
- _ = self;
-
- var x = value;
+pub fn Encoder(comptime WriterType: type) type {
+ return struct {
+ writer: WriterType,
+ const Self = @This();
+
+ /// No `deinit` needed.
+ pub fn init(writer: WriterType) Self {
+ return .{
+ .writer = writer,
+ };
+ }
- while (0x80 <= x) {
- try writer.writeByte(@truncate(u8, x) | 0x80);
- x >>= 7;
+ /// Encode a supported BARE type.
+ pub fn encode(self: *Self, value: anytype) !void {
+ const T = @TypeOf(value);
+ return switch (@typeInfo(T)) {
+ .Int => self.encodeInt(T, value),
+ .Float => self.encodeFloat(T, value),
+ .Bool => self.encodeBool(value),
+ .Struct => if (comptime isHashMap(T))
+ self.encodeHashMap(value)
+ else
+ self.encodeStruct(value),
+ .Enum => self.encodeEnum(value),
+ .Optional => self.encodeOptional(value),
+ .Array => self.encodeArray(value),
+ .Union => self.encodeUnion(value),
+ .Pointer => self.encodePointer(value),
+ else => @compileError("unsupported type " ++ @typeName(T)),
+ };
}
- try writer.writeByte(@truncate(u8, x));
- }
+ fn encodeAllowVoid(self: *Self, value: anytype) !void {
+ return switch (@TypeOf(value)) {
+ void => {},
+ else => self.encode(value),
+ };
+ }
- fn encodeVarInt(self: *Self, value: i64, writer: anytype) !void {
- const ux = @bitCast(u64, (2 * value) ^ (value >> 63));
- return self.encodeVarUint(ux, writer);
- }
+ fn encodeVarUint(self: *Self, value: u64) !void {
+ var x = value;
- fn encodeInt(self: *Self, comptime T: type, value: T, writer: anytype) !void {
- _ = self;
+ while (0x80 <= x) {
+ try self.writer.writeByte(@truncate(u8, x) | 0x80);
+ x >>= 7;
+ }
- return switch (@bitSizeOf(T)) {
- 8, 16, 32, 64 => writer.writeIntLittle(T, value),
- else => @compileError("unsupported integer type " ++ @typeName(T)),
- };
- }
+ try self.writer.writeByte(@truncate(u8, x));
+ }
- fn encodeFloat(self: *Self, comptime T: type, value: T, writer: anytype) !void {
- _ = self;
+ fn encodeVarInt(self: *Self, value: i64) !void {
+ const ux = @bitCast(u64, (2 * value) ^ (value >> 63));
+ return self.encodeVarUint(ux);
+ }
- return switch (@bitSizeOf(T)) {
- 32 => writer.writeIntLittle(u32, @bitCast(u32, value)),
- 64 => writer.writeIntLittle(u64, @bitCast(u64, value)),
- else => @compileError("unsupported float type " ++ @typeName(T)),
- };
- }
+ fn encodeInt(self: *Self, comptime T: type, value: T) !void {
+ return switch (@bitSizeOf(T)) {
+ 8, 16, 32, 64 => self.writer.writeIntLittle(T, value),
+ else => @compileError("unsupported integer type " ++ @typeName(T)),
+ };
+ }
- fn encodeBool(self: *Self, value: bool, writer: anytype) !void {
- _ = self;
+ fn encodeFloat(self: *Self, comptime T: type, value: T) !void {
+ return switch (@bitSizeOf(T)) {
+ 32 => self.writer.writeIntLittle(u32, @bitCast(u32, value)),
+ 64 => self.writer.writeIntLittle(u64, @bitCast(u64, value)),
+ else => @compileError("unsupported float type " ++ @typeName(T)),
+ };
+ }
- try writer.writeByte(@boolToInt(value));
- }
+ fn encodeBool(self: *Self, value: bool) !void {
+ try self.writer.writeByte(@boolToInt(value));
+ }
- fn encodeStruct(self: *Self, value: anytype, writer: anytype) !void {
- const ti = @typeInfo(@TypeOf(value)).Struct;
+ fn encodeStruct(self: *Self, value: anytype) !void {
+ const ti = @typeInfo(@TypeOf(value)).Struct;
- if (ti.fields.len < 1)
- @compileError("structs must have 1 or more fields");
+ if (ti.fields.len < 1)
+ @compileError("structs must have 1 or more fields");
- inline for (ti.fields) |f|
- try self.encode(@field(value, f.name), writer);
- }
+ inline for (ti.fields) |f|
+ try self.encode(@field(value, f.name));
+ }
- fn encodeEnum(self: *Self, value: anytype, writer: anytype) !void {
- try self.encodeVarUint(@enumToInt(value), writer);
- }
+ fn encodeEnum(self: *Self, value: anytype) !void {
+ try self.encodeVarUint(@enumToInt(value));
+ }
- fn encodeOptional(self: *Self, value: anytype, writer: anytype) !void {
- if (value) |val| {
- try writer.writeByte(@boolToInt(true));
- try self.encode(val, writer);
- } else try writer.writeByte(@boolToInt(false));
- }
+ fn encodeOptional(self: *Self, value: anytype) !void {
+ if (value) |val| {
+ try self.writer.writeByte(@boolToInt(true));
+ try self.encode(val);
+ } else try self.writer.writeByte(@boolToInt(false));
+ }
- fn encodeArray(self: *Self, value: anytype, writer: anytype) !void {
- const ti = @typeInfo(@TypeOf(value)).Array;
+ fn encodeArray(self: *Self, value: anytype) !void {
+ const ti = @typeInfo(@TypeOf(value)).Array;
- if (ti.len < 1)
- @compileError("array length must be at least 1");
+ if (ti.len < 1)
+ @compileError("array length must be at least 1");
- for (value) |v|
- try self.encode(v, writer);
- }
+ for (value) |v|
+ try self.encode(v);
+ }
- fn encodePointer(self: *Self, value: anytype, writer: anytype) !void {
- const ti = @typeInfo(@TypeOf(value)).Pointer;
+ fn encodePointer(self: *Self, value: anytype) !void {
+ const ti = @typeInfo(@TypeOf(value)).Pointer;
- if (ti.size != .Slice)
- @compileError("slices are the only supported pointer type");
+ if (ti.size != .Slice)
+ @compileError("slices are the only supported pointer type");
- try self.encodeVarUint(value.len, writer);
+ try self.encodeVarUint(value.len);
- for (value) |v|
- try self.encode(v, writer);
- }
+ for (value) |v|
+ try self.encode(v);
+ }
- fn encodeHashMap(self: *Self, value: anytype, writer: anytype) !void {
- const T = @TypeOf(value);
- const K = HashMapKeyType(T);
+ fn encodeHashMap(self: *Self, value: anytype) !void {
+ const T = @TypeOf(value);
+ const K = HashMapKeyType(T);
- if (comptime !isValidHashMapKeyType(K))
- @compileError("unsupported hashmap key type " ++ @typeName(K));
+ if (comptime !isValidHashMapKeyType(K))
+ @compileError("unsupported hashmap key type " ++ @typeName(K));
- try self.encodeVarUint(value.count(), writer);
+ try self.encodeVarUint(value.count());
- var it = value.iterator();
+ var it = value.iterator();
- while (it.next()) |kv| {
- try self.encode(kv.key_ptr.*, writer);
- try self.encode(kv.value_ptr.*, writer);
+ while (it.next()) |kv| {
+ try self.encode(kv.key_ptr.*);
+ try self.encode(kv.value_ptr.*);
+ }
}
- }
- fn encodeUnion(self: *Self, value: anytype, writer: anytype) !void {
- const T = @TypeOf(value);
- const ti = @typeInfo(T).Union;
+ fn encodeUnion(self: *Self, value: anytype) !void {
+ const T = @TypeOf(value);
+ const ti = @typeInfo(T).Union;
- if (ti.tag_type) |TT| {
- const tag = @enumToInt(value);
- try self.encodeVarUint(tag, writer);
+ if (ti.tag_type) |TT| {
+ const tag = @enumToInt(value);
+ try self.encodeVarUint(tag);
- inline for (ti.fields) |f| {
- if (value == @field(TT, f.name))
- return try self.encodeAllowVoid(@field(value, f.name), writer);
- }
- } else @compileError("only tagged unions are supported");
- }
-};
+ inline for (ti.fields) |f| {
+ if (value == @field(TT, f.name))
+ return try self.encodeAllowVoid(@field(value, f.name));
+ }
+ } else @compileError("only tagged unions are supported");
+ }
+ };
+}
fn isHashMap(comptime T: type) bool {
switch (@typeInfo(T)) {
@@ 393,7 382,7 @@ fn HashMapType(comptime T: type, comptime field_name: []const u8) type {
inline for (fields) |f|
if (comptime mem.eql(u8, f.name, field_name))
- return f.type;
+ return f.field_type;
}
fn isValidHashMapKeyType(comptime T: type) bool {
@@ 406,38 395,42 @@ fn isValidHashMapKeyType(comptime T: type) bool {
}
test "read variable uint" {
- var d = Decoder.init(std.testing.allocator);
var fbs = io.fixedBufferStream("\x2a");
- const x = try d.decodeVarUint(fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, std.testing.allocator);
+ const x = try d.decodeVarUint();
try std.testing.expectEqual(x, 42);
fbs = io.fixedBufferStream("\x80\x02");
- const y = d.decodeVarUint(fbs.reader());
+ const y = d.decodeVarUint();
try std.testing.expectEqual(y, 0x100);
}
test "read variable uint overflow 1" {
const buf = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02";
- var d = Decoder.init(std.testing.allocator);
var fbs = io.fixedBufferStream(buf);
- const x = d.decodeVarUint(fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, std.testing.allocator);
+ const x = d.decodeVarUint();
try std.testing.expectError(DecodeError.Overflow, x);
}
test "read variable uint overflow 2" {
const buf = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00";
- var d = Decoder.init(std.testing.allocator);
var fbs = io.fixedBufferStream(buf);
- const x = d.decodeVarUint(fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, std.testing.allocator);
+ const x = d.decodeVarUint();
try std.testing.expectError(DecodeError.Overflow, x);
}
test "write variable uint" {
var buf: [4]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encodeVarUint(42, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encodeVarUint(42);
try std.testing.expectEqual(fbs.getWritten()[0], 42);
- try e.encodeVarUint(0x100, fbs.writer());
+ try e.encodeVarUint(0x100);
try std.testing.expectEqual(fbs.getWritten()[1], 128);
try std.testing.expectEqual(fbs.getWritten()[2], 2);
}
@@ 445,41 438,48 @@ test "write variable uint" {
test "write variable int" {
var buf: [4]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encodeVarInt(42, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encodeVarInt(42);
try std.testing.expectEqual(fbs.getWritten()[0], 42 << 1);
}
test "round trip variable uint" {
var buf: [4]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encodeVarUint(0x10000, fbs.writer());
- var d = Decoder.init(std.testing.allocator);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encodeVarUint(0x10000);
+ var d = Decoder(@TypeOf(reader)).init(reader, std.testing.allocator);
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decodeVarUint(fbs.reader());
+ const res = try d.decodeVarUint();
try std.testing.expectEqual(res, 0x10000);
}
test "round trip variable int 1" {
var buf: [4]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encodeVarInt(-0x10000, fbs.writer());
- var d = Decoder.init(std.testing.allocator);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encodeVarInt(-0x10000);
+ var d = Decoder(@TypeOf(reader)).init(reader, std.testing.allocator);
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decodeVarInt(fbs.reader());
+ const res = try d.decodeVarInt();
try std.testing.expectEqual(res, -0x10000);
}
test "round trip variable int 2" {
var buf: [4]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encodeVarInt(0x10000, fbs.writer());
- var d = Decoder.init(std.testing.allocator);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encodeVarInt(0x10000);
+ var d = Decoder(@TypeOf(reader)).init(reader, std.testing.allocator);
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decodeVarInt(fbs.reader());
+ const res = try d.decodeVarInt();
try std.testing.expectEqual(res, 0x10000);
}
@@ 490,10 490,12 @@ test "round trip union with void member" {
};
var buf: [4]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encode(U{ .Hello = 123 }, fbs.writer());
- var d = Decoder.init(std.testing.allocator);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(U{ .Hello = 123 });
+ var d = Decoder(@TypeOf(reader)).init(reader, std.testing.allocator);
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decode(U, fbs.reader());
+ const res = try d.decode(U);
try std.testing.expectEqual(res, U{ .Hello = 123 });
}
@@ 26,22 26,24 @@ test "read u8" {
};
inline for (cases) |pair| {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream(pair[0]);
- try expectEqual(@as(u8, pair[1]), try d.decode(u8, fbs.reader()));
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ try expectEqual(@as(u8, pair[1]), try d.decode(u8));
}
}
test "read bool" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00");
- try expectEqual(d.decode(bool, fbs.reader()), false);
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ try expectEqual(d.decode(bool), false);
fbs = io.fixedBufferStream("\xff");
- try expectEqual(d.decode(bool, fbs.reader()), true);
+ try expectEqual(d.decode(bool), true);
fbs = io.fixedBufferStream("\x01");
- try expectEqual(d.decode(bool, fbs.reader()), true);
+ try expectEqual(d.decode(bool), true);
}
test "read struct 1" {
@@ 51,11 53,11 @@ test "read struct 1" {
c: bool,
};
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00\x00\x28\x42\x2a\xaa");
- const res = try d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
+ const res = try d.decode(Foo);
try expectEqual(res.a, 42.0);
try expectEqual(res.b, 42);
try expectEqual(res.c, true);
@@ 68,10 70,11 @@ test "read struct 2" {
c: bool,
};
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00\x00\x28\x42\x2a\x00");
- const res = try d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode(Foo);
try expectEqual(res.a, 42.0);
try expectEqual(res.b, 42);
try expectEqual(res.c, false);
@@ 84,10 87,11 @@ test "read struct 3" {
c: bool,
};
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00\x00\x28\x42\x2b\x00");
- const res = try d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode(Foo);
try expectEqual(res.a, 42.0);
try expectEqual(res.b, 43);
try expectEqual(res.c, false);
@@ 100,10 104,11 @@ test "read struct 4" {
c: bool,
};
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00\x00\x29\x42\x2b\x00");
- const res = try d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode(Foo);
try expectEqual(res.a, 42.25);
try expectEqual(res.b, 43);
try expectEqual(res.c, false);
@@ 116,10 121,11 @@ test "read struct 5" {
c: bool,
};
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00\x00\x00\x00\x00\x00");
- const res = try d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode(Foo);
try expectEqual(res.a, 0.0);
try expectEqual(res.b, 0);
try expectEqual(res.c, false);
@@ 132,10 138,11 @@ test "read struct 6" {
c: bool,
};
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\xff\xff\xff\xff\xff\xff");
- const res = try d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode(Foo);
try expect(math.isNan(res.a));
try expectEqual(res.b, 255);
try expectEqual(res.c, true);
@@ 145,10 152,11 @@ test "read struct with void members" {
try testCompileError(
\\pub fn main() !void {
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ const Foo = struct { a: u8, b: void };
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(Foo, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(Foo);
\\}
, "unsupported type void");
}
@@ 159,18 167,19 @@ test "read enum" {
b = 1,
c = 0,
};
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x02");
- var res = try d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ var res = try d.decode(Foo);
try expectEqual(res, .a);
fbs = io.fixedBufferStream("\x01");
- res = try d.decode(Foo, fbs.reader());
+ res = try d.decode(Foo);
try expectEqual(res, .b);
fbs = io.fixedBufferStream("\x00");
- res = try d.decode(Foo, fbs.reader());
+ res = try d.decode(Foo);
try expectEqual(res, .c);
}
@@ 180,88 189,98 @@ test "read invalid enum value" {
b = 1,
c = 0,
};
- var d = Decoder.init(testing.allocator);
var fbs = io.fixedBufferStream("\x03");
- try expectError(error.InvalidEnumTag, d.decode(Foo, fbs.reader()));
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ try expectError(error.InvalidEnumTag, d.decode(Foo));
}
test "read optional u8 value" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x01\x2a");
- const res = try d.decode(?u8, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode(?u8);
try expectEqual(res, 42);
}
test "read optional u8 null" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00");
- const res = try d.decode(?u8, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode(?u8);
try expectEqual(res, null);
}
test "read u8 array" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x01\x02\x03\x04");
- const res = try d.decode([4]u8, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode([4]u8);
const expected = [4]u8{ 1, 2, 3, 4 };
try expectEqual(res, expected);
}
test "read u8 slice" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x04\x01\x02\x03\x04");
- const res = try d.decode([]const u8, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode([]const u8);
const expected = [_]u8{ 1, 2, 3, 4 };
try expectEqualSlices(u8, &expected, res);
}
test "read 0-length slice" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00");
- const res = try d.decode([]const u8, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode([]const u8);
defer testing.allocator.free(res);
const expected = [_]u8{};
try expectEqualSlices(u8, &expected, res);
}
test "read map[u8]u8" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x02\x01\x02\x03\x04");
- const map = try d.decode(std.AutoHashMap(u8, u8), fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const map = try d.decode(std.AutoHashMap(u8, u8));
try expectEqual(map.get(1) orelse unreachable, 2);
try expectEqual(map.get(3) orelse unreachable, 4);
}
test "read map[u8]u8 with 0 items" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x00");
- const map = try d.decode(std.AutoHashMap(u8, u8), fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const map = try d.decode(std.AutoHashMap(u8, u8));
try expectEqual(map.count(), 0);
}
test "read map[string]u8" {
- var d = Decoder.init(testing.allocator);
+ var fbs = io.fixedBufferStream("\x02\x04zomg\x04\x03lol\x02");
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
const T = std.StringHashMap(u8);
- var fbs = io.fixedBufferStream("\x02\x04zomg\x04\x03lol\x02");
- const map = try d.decode(T, fbs.reader());
+ const map = try d.decode(T);
try expectEqual(map.get("lol") orelse unreachable, 2);
try expectEqual(map.get("zomg") orelse unreachable, 4);
}
test "read map overflow" {
- var d = Decoder.init(testing.allocator);
+ var fbs = io.fixedBufferStream("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x04zomg\x04\x03lol\x02");
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
const T = std.StringHashMap(u8);
- var fbs = io.fixedBufferStream("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x04zomg\x04\x03lol\x02");
- const map = d.decode(T, fbs.reader());
+ const map = d.decode(T);
try expectError(error.Overflow, map);
}
@@ 269,20 288,22 @@ test "read map[u8]void" {
try testCompileError(
\\pub fn main() !void {
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ const HM = std.AutoHashMap(u8, void);
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(HM, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(HM);
\\}
, "unsupported type void");
}
test "read tagged union" {
const Foo = union(enum) { a: i64, b: bool, c: u8 };
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x02\x2a");
- const res = try d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ const res = try d.decode(Foo);
try expectEqual(Foo{ .c = 42 }, res);
}
@@ 291,9 312,10 @@ test "read untagged union" {
\\pub fn main() !void {
\\ const Foo = union { a: u8, b: void };
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(Foo, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(Foo);
\\}
, "only tagged unions are supported");
}
@@ 302,9 324,10 @@ test "read void" {
try testCompileError(
\\pub fn main() !void {
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(void, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(void);
\\}
, "unsupported type void");
}
@@ 313,9 336,10 @@ test "read unsupported integer type" {
try testCompileError(
\\pub fn main() !void {
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(u7, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(u7);
\\}
, "unsupported integer type u7");
}
@@ 324,9 348,10 @@ test "read unsupported float type" {
try testCompileError(
\\pub fn main() !void {
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(f16, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(f16);
\\}
, "unsupported float type f16");
}
@@ 335,9 360,10 @@ test "read unsupported pointer type" {
try testCompileError(
\\pub fn main() !void {
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(*u8, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(*u8);
\\}
, "slices are the only supported pointer type");
}
@@ 345,18 371,20 @@ test "read unsupported pointer type" {
test "write u8" {
var buf: [1]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
+ var writer = fbs.writer();
const x: u8 = 42;
- var e = Encoder.init();
- try e.encode(x, fbs.writer());
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(x);
try expectEqual(fbs.getWritten()[0], x);
}
test "write bool" {
var buf: [2]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encode(false, fbs.writer());
- try e.encode(true, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(false);
+ try e.encode(true);
try expectEqual(fbs.getWritten()[0], 0);
try expectEqual(fbs.getWritten()[1], 1);
}
@@ 371,8 399,9 @@ test "write struct" {
var buf: [@sizeOf(Foo)]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
const expected = "\x00\x00\x28\x42\x2a\x01";
- var e = Encoder.init();
- try e.encode(Foo{ .a = 42.0, .b = 42, .c = true }, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(Foo{ .a = 42.0, .b = 42, .c = true });
try expect(mem.eql(u8, fbs.getWritten(), expected));
}
@@ 382,8 411,9 @@ test "write struct with void members" {
\\ const Foo = struct { x: u8, y: void };
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
- \\ var e = Encoder.init();
- \\ try e.encode(Foo{ .x = 1, .y = {} }, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(Foo{ .x = 1, .y = {} });
\\}
, "unsupported type");
}
@@ 398,17 428,19 @@ test "write enum" {
var buf: [@sizeOf(Foo)]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
const expected = "\x02";
- var e = Encoder.init();
- try e.encode(Foo.c, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(Foo.c);
try expect(mem.eql(u8, fbs.getWritten(), expected));
}
test "write optional u8 value" {
var buf: [2]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
+ var writer = fbs.writer();
var x: ?u8 = 42;
- var e = Encoder.init();
- try e.encode(x, fbs.writer());
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(x);
try expectEqual(fbs.getWritten()[0], @boolToInt(true));
try expectEqual(fbs.getWritten()[1], 42);
}
@@ 417,8 449,9 @@ test "write optional u8 null" {
var buf: [2]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
var x: ?u8 = null;
- var e = Encoder.init();
- try e.encode(x, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(x);
try expectEqual(fbs.getWritten().len, 1);
try expectEqual(fbs.getWritten()[0], @boolToInt(false));
}
@@ 429,8 462,9 @@ test "write optional void" {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
\\ const foo: ?void = null;
- \\ var e = Encoder.init();
- \\ try e.encode(foo, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(foo);
\\}
, "unsupported type");
}
@@ 439,8 473,9 @@ test "write u8 array" {
var buf: [4]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
var x = [4]u8{ 1, 2, 3, 4 };
- var e = Encoder.init();
- try e.encode(x, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(x);
const expected = [_]u8{ 1, 2, 3, 4 };
try expectEqual(fbs.getWritten().len, 4);
try expectEqualSlices(u8, fbs.getWritten(), &expected);
@@ 452,8 487,9 @@ test "write array of void" {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
\\ const foo: [4]void = .{ {}, {}, {}, {} };
- \\ var e = Encoder.init();
- \\ try e.encode(foo, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(foo);
\\}
, "unsupported type");
}
@@ 465,8 501,9 @@ test "write slice" {
const expected = [_]u8{ 1, 2, 3, 4 };
const slajs: []const u8 = &expected;
- var e = Encoder.init();
- try e.encode(slajs, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(slajs);
try expectEqual(fbs.getWritten().len, 5);
try expectEqual(fbs.getWritten()[0], 4);
try expectEqualSlices(u8, fbs.getWritten()[1..], &expected);
@@ 478,8 515,9 @@ test "write slice of void" {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
\\ const foo: []const void = &[_]void{ {}, {} };
- \\ var e = Encoder.init();
- \\ try e.encode(foo, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(foo);
\\}
, "unsupported type void");
}
@@ 494,8 532,9 @@ test "write map[u8]u8" {
_ = try map.put(1, 2);
_ = try map.put(3, 4);
- var e = Encoder.init();
- try e.encode(map, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(map);
const expected = "\x02\x01\x02\x03\x04";
try expectEqual(fbs.getWritten().len, 5);
try expectEqualSlices(u8, fbs.getWritten(), expected);
@@ 511,8 550,9 @@ test "write map[string]u8" {
_ = try map.put("lol", 2);
_ = try map.put("zomg", 4);
- var e = Encoder.init();
- try e.encode(map, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(map);
// TODO: Fix this; later versions of std.HashMap preserve insertion order.
const expected = "\x02\x04zomg\x04\x03lol\x02";
try expectEqual(fbs.getWritten().len, 12);
@@ 525,8 565,9 @@ test "write map[u8]void" {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
\\ const foo = std.AutoHashMap(u8, void);
- \\ var e = Encoder.init();
- \\ try e.encode(foo, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(foo);
\\}
, "unsupported type");
}
@@ 538,8 579,9 @@ test "write tagged union" {
const Foo = union(enum) { a: i64, b: bool, c: u8 };
const foo = Foo{ .a = 42 };
- var e = Encoder.init();
- try e.encode(foo, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(foo);
const expected = "\x00\x2a\x00\x00\x00\x00\x00\x00\x00";
try expectEqual(fbs.getWritten().len, 1 + @sizeOf(i64));
try expectEqualSlices(u8, fbs.getWritten(), expected);
@@ 552,8 594,9 @@ test "write tagged union with void member active" {
const Foo = union(enum) { a: i64, b: void, c: u8 };
const foo = Foo{ .b = {} };
- var e = Encoder.init();
- try e.encode(foo, fbs.writer());
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(foo);
const expected = "\x01";
try expectEqualSlices(u8, fbs.getWritten(), expected);
}
@@ 563,8 606,9 @@ test "write untagged union" {
\\pub fn main() !void {
\\ const Foo = union { a: u8, b: void };
\\ var fbs = io.fixedBufferStream("lol");
- \\ var e = Encoder.init();
- \\ _ = try e.encode(Foo{ .a = 2 }, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ _ = try e.encode(Foo{ .a = 2 });
\\}
, "only tagged unions are supported");
}
@@ 574,8 618,9 @@ test "write void" {
\\pub fn main() !void {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
- \\ var e = Encoder.init();
- \\ try e.encode({}, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode({});
\\}
, "unsupported type void");
}
@@ 586,8 631,9 @@ test "write unsupported integer type" {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
\\ const foo: u7 = 7;
- \\ var e = Encoder.init();
- \\ try e.encode(foo, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(foo);
\\}
, "unsupported integer type u7");
}
@@ 597,9 643,10 @@ test "write unsupported float type" {
\\pub fn main() !void {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
+ \\ var writer = fbs.writer();
\\ const foo: f16 = 4.2;
- \\ var e = Encoder.init();
- \\ try e.encode(foo, fbs.writer());
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(foo);
\\}
, "unsupported float type f16");
}
@@ 609,10 656,11 @@ test "write unsupported pointer type" {
\\pub fn main() !void {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
+ \\ var writer = fbs.writer();
\\ const x: u8 = 2;
\\ const foo: *const u8 = &x;
- \\ var e = Encoder.init();
- \\ try e.encode(foo, fbs.writer());
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(foo);
\\}
, "slices are the only supported pointer type");
}
@@ 620,13 668,15 @@ test "write unsupported pointer type" {
test "round trip u8" {
var buf: [0x100]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
const x: u8 = 42;
- var e = Encoder.init();
- try e.encode(x, fbs.writer());
- var d = Decoder.init(testing.allocator);
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(x);
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decode(u8, fbs.reader());
+ const res = try d.decode(u8);
try expectEqual(res, x);
}
@@ 640,12 690,14 @@ test "round trip struct" {
const foo = Foo{ .a = 42.0, .b = 3, .c = true };
var buf: [@sizeOf(Foo)]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encode(foo, fbs.writer());
- var d = Decoder.init(testing.allocator);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(foo);
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decode(Foo, fbs.reader());
+ const res = try d.decode(Foo);
try expectEqual(res, foo);
}
@@ 658,40 710,48 @@ test "round trip enum" {
var buf: [@sizeOf(Foo)]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
- var e = Encoder.init();
- try e.encode(Foo.c, fbs.writer());
- var d = Decoder.init(testing.allocator);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(Foo.c);
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decode(Foo, fbs.reader());
+ const res = try d.decode(Foo);
try expectEqual(res, Foo.c);
}
test "round trip i64 array" {
var buf: [0x100]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
const arr = [_]i64{ -1, 1, math.maxInt(i64), math.minInt(i64) };
- var e = Encoder.init();
- try e.encode(arr, fbs.writer());
- var d = Decoder.init(testing.allocator);
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(arr);
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decode(@TypeOf(arr), fbs.reader());
+ const res = try d.decode(@TypeOf(arr));
try expectEqualSlices(i64, &arr, &res);
}
test "round trip i32 slice" {
var buf: [0x100]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
+
+ var e = Encoder(@TypeOf(writer)).init(writer);
const expected = [4]i32{ -1, 2, math.maxInt(i32), math.minInt(i32) };
const slajs: []const i32 = &expected;
- var e = Encoder.init();
- try e.encode(slajs, fbs.writer());
- var d = Decoder.init(testing.allocator);
+
+ try e.encode(slajs);
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decode([]const i32, fbs.reader());
+ const res = try d.decode([]const i32);
try expectEqualSlices(i32, slajs, res);
}
@@ 704,13 764,15 @@ test "round trip tagged union" {
const foo = Foo{ .b = 42 };
var buf: [0x100]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
- var e = Encoder.init();
- try e.encode(foo, fbs.writer());
- var d = Decoder.init(testing.allocator);
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(foo);
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decode(Foo, fbs.reader());
+ const res = try d.decode(Foo);
try expectEqual(foo, res);
}
@@ 724,32 786,36 @@ test "round trip tagged union with void member active" {
const foo = Foo{ .b = {} };
var buf: [0x100]u8 = undefined;
var fbs = io.fixedBufferStream(&buf);
+ var reader = fbs.reader();
+ var writer = fbs.writer();
- var e = Encoder.init();
- try e.encode(foo, fbs.writer());
- var d = Decoder.init(testing.allocator);
+ var e = Encoder(@TypeOf(writer)).init(writer);
+ try e.encode(foo);
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
defer d.deinit();
fbs = io.fixedBufferStream(fbs.getWritten());
- const res = try d.decode(Foo, fbs.reader());
+ const res = try d.decode(Foo);
try expectEqual(foo, res);
}
test "invalid union returns error" {
const Foo = union(enum) { a: i64, b: bool, c: u8 };
- var d = Decoder.init(testing.allocator);
var fbs = io.fixedBufferStream("\x09\x2a");
- const res = d.decode(Foo, fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ const res = d.decode(Foo);
try expectError(error.InvalidUnion, res);
}
test "bare.Decoder frees its memory" {
- var d = Decoder.init(testing.allocator);
- defer d.deinit();
var fbs = io.fixedBufferStream("\x02\x01\x02\x03\x04");
- _ = try d.decode(std.AutoHashMap(u8, u8), fbs.reader());
+ var reader = fbs.reader();
+ var d = Decoder(@TypeOf(reader)).init(reader, testing.allocator);
+ defer d.deinit();
+ _ = try d.decode(std.AutoHashMap(u8, u8));
fbs = io.fixedBufferStream("\x04\x01\x02\x03\x04");
- _ = try d.decode([]const u8, fbs.reader());
+ _ = try d.decode([]const u8);
// testing.allocator will yell if memory is leaked
}
@@ 757,9 823,10 @@ test "invariant: fixed-length array must have length > 0 (read)" {
try testCompileError(
\\pub fn main() !void {
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ try d.decode([0]u8, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ try d.decode([0]u8);
\\}
, "array length must be at least 1");
}
@@ 770,8 837,9 @@ test "invariant: fixed-length array must have length > 0 (write)" {
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
\\ var foo = [0]u8{};
- \\ var e = Encoder.init();
- \\ try e.encode(foo, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(foo);
\\}
, "array length must be at least 1");
}
@@ 781,9 849,10 @@ test "invariant: structs must have at least 1 field (read)" {
\\pub fn main() !void {
\\ const Foo = struct {};
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ try d.decode(Foo, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ try d.decode(Foo);
\\}
, "structs must have 1 or more fields");
}
@@ 794,8 863,9 @@ test "invariant: structs must have at least 1 field (write)" {
\\ const Foo = struct {};
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
- \\ var e = Encoder.init();
- \\ try e.encode(Foo{}, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ try e.encode(Foo{});
\\}
, "structs must have 1 or more fields");
}
@@ 805,9 875,10 @@ test "invariant: unions must have at least 1 field (read)" {
\\pub fn main() !void {
\\ const Foo = union(enum) {};
\\ var fbs = io.fixedBufferStream("lol");
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(Foo{}, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(Foo{});
\\}
, "union initializer must initialize one field");
}
@@ 818,9 889,10 @@ test "invariant: unions must have at least 1 field (write)" {
\\ const Foo = union(enum) {};
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
- \\ var e = Encoder.init();
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
\\ const foo = Foo{};
- \\ _ = try e.encode(foo, fbs.writer());
+ \\ _ = try e.encode(foo);
\\}
, "union initializer must initialize one field");
}
@@ 832,8 904,9 @@ test "invariant: hashmap keys must be of primitive type" {
\\ const hm = std.AutoHashMap([64]u8, void).init(gpa.allocator());
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
- \\ var e = Encoder.init();
- \\ _ = try e.encode(hm, fbs.writer());
+ \\ var writer = fbs.writer();
+ \\ var e = Encoder(@TypeOf(writer)).init(writer);
+ \\ _ = try e.encode(hm);
\\}
, "unsupported hashmap key type [64]u8");
}
@@ 847,9 920,10 @@ test "invariant: enum values must be unique" {
\\ };
\\ var buf: [0x100]u8 = undefined;
\\ var fbs = io.fixedBufferStream(&buf);
+ \\ var reader = fbs.reader();
\\ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- \\ var d = Decoder.init(gpa.allocator());
- \\ _ = try d.decode(Foo, fbs.reader());
+ \\ var d = Decoder(@TypeOf(reader)).init(reader, gpa.allocator());
+ \\ _ = try d.decode(Foo);
\\}
, "enum tag value 1 already taken");
}