@@ 5,12 5,19 @@ const math = std.math;
const mem = std.mem;
const meta = std.meta;
-pub const DecodeError = error{ Overflow, InvalidUnion };
+pub const DecodeError = error{
+ Overflow,
+ InvalidBool,
+ InvalidUnion,
+};
pub fn decoder(allocator: mem.Allocator, reader: anytype) Decoder(@TypeOf(reader)) {
return Decoder(@TypeOf(reader)).init(allocator, reader);
}
+pub const VarInt = varint.VarInt;
+pub const VarUint = varint.VarUint;
+
/// Decodes BARE messages.
/// Uses an internal arena backed by the passed-in allocator.
pub fn Decoder(comptime ReaderType: type) type {
@@ 40,6 47,10 @@ pub fn Decoder(comptime ReaderType: type) type {
.Bool => self.decodeBool(),
.Struct => if (comptime isHashMap(T))
self.decodeHashMap(T)
+ else if (T == VarInt)
+ self.decodeVarInt()
+ else if (T == VarUint)
+ self.decodeVarUint()
else
self.decodeStruct(T),
.Enum => self.decodeEnum(T),
@@ 58,11 69,11 @@ pub fn Decoder(comptime ReaderType: type) type {
};
}
- fn decodeVarInt(self: *Self) !i64 {
+ fn decodeVarInt(self: *Self) !VarInt {
return varint.decodeVarInt(self.reader);
}
- fn decodeVarUint(self: *Self) !u64 {
+ fn decodeVarUint(self: *Self) !VarUint {
return varint.decodeVarUint(self.reader);
}
@@ 82,7 93,11 @@ pub fn Decoder(comptime ReaderType: type) type {
}
fn decodeBool(self: *Self) !bool {
- return 0 != try self.reader.readByte();
+ return switch (try self.reader.readByte()) {
+ 0 => false,
+ 1 => true,
+ else => DecodeError.InvalidBool,
+ };
}
fn decodeStruct(self: *Self, comptime T: type) !T {
@@ 99,7 114,7 @@ pub fn Decoder(comptime ReaderType: type) type {
}
fn decodeEnum(self: *Self, comptime T: type) !T {
- const x: meta.Tag(T) = @intCast(try self.decodeVarUint());
+ const x: meta.Tag(T) = @intCast((try self.decodeVarUint())[0]);
return meta.intToEnum(T, x);
}
@@ 132,7 147,7 @@ pub fn Decoder(comptime ReaderType: type) type {
const tag = try self.decodeVarUint();
inline for (ti.fields) |f| {
- if (tag == @intFromEnum(@field(ti.tag_type.?, f.name))) {
+ if (tag[0] == @intFromEnum(@field(ti.tag_type.?, f.name))) {
const v = try self.decodeAllowVoid(f.type);
return @unionInit(T, f.name, v);
}
@@ 148,9 163,9 @@ pub fn Decoder(comptime ReaderType: type) type {
@compileError("slices are the only supported pointer type");
const len = try self.decodeVarUint();
- var buf = try self.arena.allocator().alloc(ti.child, len);
+ var buf = try self.arena.allocator().alloc(ti.child, len[0]);
- for (0..len) |i|
+ for (0..len[0]) |i|
buf[i] = try self.decode(ti.child);
return buf;
@@ 165,13 180,13 @@ pub fn Decoder(comptime ReaderType: type) type {
const i = try self.decodeVarUint();
- if (std.math.maxInt(T.Size) < i)
+ if (std.math.maxInt(T.Size) < i[0])
return DecodeError.Overflow;
var map = T.Unmanaged{};
- try map.ensureUnusedCapacity(self.arena.allocator(), @intCast(i));
+ try map.ensureUnusedCapacity(self.arena.allocator(), @intCast(i[0]));
- for (0..i) |_| {
+ for (0..i[0]) |_| {
const key = try self.decode(K);
const val = try self.decode(V);
_ = map.putAssumeCapacity(key, val);
@@ 230,7 245,7 @@ pub fn Encoder(comptime WriterType: type) type {
};
}
- fn encodeVarUint(self: *Self, value: u64) !void {
+ fn encodeVarUint(self: *Self, value: VarUint) !void {
return varint.encodeVarUint(self.writer, value);
}
@@ 270,7 285,7 @@ pub fn Encoder(comptime WriterType: type) type {
}
fn encodeEnum(self: *Self, value: anytype) !void {
- try self.encodeVarUint(@intFromEnum(value));
+ try self.encodeVarUint(VarUint{@intFromEnum(value)});
}
fn encodeOptional(self: *Self, value: anytype) !void {
@@ 296,7 311,7 @@ pub fn Encoder(comptime WriterType: type) type {
if (ti.size != .Slice)
@compileError("slices are the only supported pointer type");
- try self.encodeVarUint(value.len);
+ try self.encodeVarUint(VarUint{value.len});
for (value) |v|
try self.encode(v);
@@ 309,7 324,7 @@ pub fn Encoder(comptime WriterType: type) type {
if (comptime !isValidHashMapKeyType(K))
@compileError("unsupported hashmap key type " ++ @typeName(K));
- try self.encodeVarUint(value.count());
+ try self.encodeVarUint(VarUint{value.count()});
var it = value.iterator();
@@ 325,7 340,7 @@ pub fn Encoder(comptime WriterType: type) type {
if (ti.tag_type) |TT| {
const tag = @intFromEnum(value);
- try self.encodeVarUint(tag);
+ try self.encodeVarUint(VarUint{tag});
inline for (ti.fields) |f| {
if (value == @field(TT, f.name))
@@ 0,0 1,70 @@
+const std = @import("std");
+const io = std.io;
+const math = std.math;
+const mem = std.mem;
+const testing = std.testing;
+
+const bare = @import("bare");
+const decoder = bare.decoder;
+const encoder = bare.encoder;
+
+const expect = testing.expect;
+const expectEqual = testing.expectEqual;
+const expectEqualSlices = testing.expectEqualSlices;
+const expectError = testing.expectError;
+
+const payloads1 = [_][]const u8{
+ &[_]u8{0x42},
+ &[_]u8{ 0xFE, 0xCA },
+ &[_]u8{ 0xEF, 0xBE, 0xAD, 0xDE },
+ &[_]u8{ 0xEF, 0xBE, 0xAD, 0xDE, 0xBE, 0xBA, 0xFE, 0xCA },
+ &[_]u8{ 0xEF, 0xFD, 0xB6, 0xF5, 0x0D },
+ &[_]u8{0xD6},
+ &[_]u8{ 0x2E, 0xFB },
+ &[_]u8{ 0xB2, 0x9E, 0x43, 0xFF },
+ &[_]u8{ 0x4F, 0x0B, 0x6E, 0x9D, 0xAB, 0x23, 0xD4, 0xFF },
+ &[_]u8{ 0x9B, 0x85, 0xE3, 0x0B },
+ &[_]u8{ 0x71, 0x2D, 0xA7, 0x44 },
+ &[_]u8{ 0x9B, 0x6C, 0xC9, 0x20, 0xF0, 0x21, 0x3F, 0x42 },
+ &[_]u8{ 0x00, 0x01, 0x02 },
+ &[_]u8{ 0x1B, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0xAB, 0xE3, 0x81, 0xA1, 0xE3, 0x81, 0xAF, 0xE3, 0x80, 0x81, 0xE4, 0xB8, 0x96, 0xE7, 0x95, 0x8C, 0xEF, 0xBC, 0x81 },
+};
+
+// tests ported from go-bare
+test "unmarshal value" {
+ inline for (.{
+ .{ payloads1[0], u8, 0x42 },
+ .{ payloads1[1], u16, 0xCAFE },
+ .{ payloads1[2], u32, 0xDEADBEEF },
+ .{ payloads1[3], u64, 0xCAFEBABEDEADBEEF },
+ //.{payloads1[4], c_uint, 0xDEADBEEF },
+ .{ payloads1[4], bare.VarUint, bare.VarUint{0xDEADBEEF} },
+ .{ payloads1[5], i8, -42 },
+ .{ payloads1[6], i16, -1234 },
+ .{ payloads1[7], i32, -12345678 },
+ .{ payloads1[8], i64, -12345678987654321 },
+ //.{payloads1[9], c_int, -12345678 },
+ .{ payloads1[9], bare.VarInt, bare.VarInt{-12345678} },
+ .{ payloads1[10], f32, 1337.42 },
+ .{ payloads1[11], f64, 133713371337.42424242 },
+ .{ payloads1[12][0..], bool, false },
+ .{ payloads1[12][1..], bool, true },
+ .{ payloads1[12][2..], bool, error.InvalidBool },
+ .{ payloads1[13], []const u8, "こんにちは、世界!" },
+ }) |tuple| {
+ var fbs = io.fixedBufferStream(tuple[0]);
+ const reader = fbs.reader();
+ var d = decoder(testing.allocator, reader);
+ defer d.deinit();
+ const res = switch (@typeInfo(@TypeOf(tuple[2]))) {
+ .ErrorSet => |_| {
+ try testing.expectError(tuple[2], d.decode(tuple[1]));
+ continue;
+ },
+ else => try d.decode(tuple[1]),
+ };
+ try testing.expectEqualDeep(@as(tuple[1], tuple[2]), res); // catch {
+ // try std.io.getStdErr().writer().print("{any}", .{tuple});
+ //};
+ }
+}