~alva/zig-bare

b1561f5d9e4076a62f50b8bfe30eb8a777d309b3 — Alva 4 months ago 7c1b963
Clean up `void` handling

As it's only supported in tagged unions, might as well special-case it there.
2 files changed, 56 insertions(+), 48 deletions(-)

M src/bare.zig
M src/test.zig
M src/bare.zig => src/bare.zig +29 -15
@@ 40,11 40,17 @@ pub const Reader = struct {
            .Array => self.readArray(T, stream),
            .Union => self.readUnion(T, stream),
            .Pointer => self.readPointer(T, stream),
            .Void => {},
            else => @compileError("unsupported type"),
        };
    }

    fn readAllowVoid(self: *Self, comptime T: type, stream: var) !T {
        return switch (T) {
            void => {},
            else => self.read(T, stream),
        };
    }

    fn readVarInt(self: *Self, stream: var) !i64 {
        const ux = try self.readVarUint(stream);
        var x = @intCast(i64, ux >> 1);


@@ 67,7 73,7 @@ pub const Reader = struct {
    //            if (9 < i or i == 9 and 1 < b)
                if (i == 9 and 1 < b)
                    return ReadError.Overflow;
                

                return x | @as(u64, b & 0x7f) << s;
            }



@@ 103,7 109,7 @@ pub const Reader = struct {
        var s: T = undefined;

        if (ti.fields.len < 1)
            return @compileError("structs must have at least one field");
            @compileError("structs must have at least one field");

        inline for (ti.fields) |f|
            @field(s, f.name) = try self.read(f.field_type, stream);


@@ 144,13 150,13 @@ pub const Reader = struct {

        if (ti.tag_type == null)
            @compileError("only tagged unions are supported");
        

        const tag = try self.readVarUint(stream);

        inline for (ti.fields) |f| {
            if (f.enum_field) |ef| {
                if (tag == ef.value) {
                    const v = try self.read(f.field_type, stream);
                    const v = try self.readAllowVoid(f.field_type, stream);
                    return @unionInit(T, f.name, v);
                }
            }


@@ 176,11 182,7 @@ pub const Reader = struct {
        return buf;
    }

    fn readHashMap(
        self: *Self,
        comptime T: type,
        stream: var
    ) !T {
    fn readHashMap(self: *Self, comptime T: type, stream: var) !T {
        const K = HashMapKeyType(T);
        const V = HashMapValueType(T);



@@ 229,11 231,17 @@ pub const Writer = struct {
            .Array => self.writeArray(value, stream),
            .Union => self.writeUnion(value, stream),
            .Pointer => self.writePointer(value, stream),
            .Void => {},
            else => @compileError("unsupported type"),
        };
    }

    fn writeAllowVoid(self: *Self, value: var, stream: var) !void {
        return switch (@TypeOf(value)) {
            void => {},
            else => self.write(value, stream),
        };
    }

    fn writeVarUint(self: *Self, value: u64, stream: var) !void {
        var x = value;



@@ 295,7 303,9 @@ pub const Writer = struct {
    }

    fn writeArray(self: *Self, value: var, stream: var) !void {
        if (@typeInfo(@TypeOf(value)).Array.len < 1)
        const ti = @typeInfo(@TypeOf(value)).Array;

        if (ti.len < 1)
            @compileError("array length must be at least 1");

        for (value) |v|


@@ 303,7 313,9 @@ pub const Writer = struct {
    }

    fn writePointer(self: *Self, value: var, stream: var) !void {
        if (@typeInfo(@TypeOf(value)).Pointer.size != .Slice)
        const ti = @typeInfo(@TypeOf(value)).Pointer;

        if (ti.size != .Slice)
            @compileError("unsupported type");

        try self.writeVarUint(value.len, stream);


@@ 313,7 325,9 @@ pub const Writer = struct {
    }

    fn writeHashMap(self: *Self, value: var, stream: var) !void {
        if (comptime !isValidHashMapKeyType(HashMapKeyType(@TypeOf(value))))
        const T = @TypeOf(value);

        if (comptime !isValidHashMapKeyType(HashMapKeyType(T)))
            @compileError("unsupported hashmap key type");

        try self.writeVarUint(value.size, stream);


@@ 336,7 350,7 @@ pub const Writer = struct {
            inline for (ti.fields) |f| {
                if (f.enum_field) |ef| {
                    if (tag == @intToEnum(TT, ef.value))
                        return self.write(@field(value, f.name), stream);
                        try self.writeAllowVoid(@field(value, f.name), stream);
                }
            }
        } else

M src/test.zig => src/test.zig +27 -33
@@ 16,6 16,8 @@ const expectEqualSlices = testing.expectEqualSlices;
const expectError = testing.expectError;
const warn = std.debug.warn;

// TODO: Test that expected compile errors actually result in compile errors.

test "read variable uint" {
    const x = try Reader.init(testing.allocator)
        .readVarUint(io.fixedBufferStream("\x2a").inStream());


@@ 137,6 139,10 @@ test "read struct 6" {
    expectEqual(res.c, true);
}

test "read struct with void members" {
    // Compile error.
}

test "read enum" {
    const Foo = enum { a = 2, b = 1, c = 0, };
    var res = try Reader.init(testing.allocator).read(Foo,


@@ 213,16 219,7 @@ test "read map[string]u8" {
}

test "read map[u8]void" {
    var r = Reader.init(testing.allocator);
    defer r.deinit();
    const T = std.AutoHashMap(u8, void);
    const map = try r.read(T,
        io.fixedBufferStream("\x02\x01\x02").inStream());
    expectEqual(map.size, 2);
    expectEqual((map.get(1) orelse unreachable).key, 1);
    expectEqual((map.get(2) orelse unreachable).key, 2);
    expectEqual((map.get(1) orelse unreachable).value, {});
    expectEqual((map.get(2) orelse unreachable).value, {});
    // Compile error.
}

test "read tagged union" {


@@ 233,8 230,7 @@ test "read tagged union" {
}

test "read void" {
    expectEqual(void, @TypeOf(Reader.init(testing.allocator)
        .read(void, io.fixedBufferStream("").inStream())).Payload);
    // Compile error.
}

test "read unsupported type" {


@@ 290,6 286,10 @@ test "write struct" {
    expect(mem.eql(u8, fbs.getWritten(), expected));
}

test "write struct with void members" {
    // Compile error.
}

test "write enum" {
    const Foo = enum {
        a,


@@ 322,6 322,10 @@ test "write optional u8 null" {
    expectEqual(fbs.getWritten()[0], @boolToInt(false));
}

test "write optional void" {
    // This is a compile error now.
}

test "write u8 array" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);


@@ 332,6 336,10 @@ test "write u8 array" {
    expectEqualSlices(u8, fbs.getWritten()[0..], expected[0..]);
}

test "write u8 array of void" {
    // Compile error.
}

test "write slice" {
    var buf: [5]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);


@@ 345,6 353,10 @@ test "write slice" {
    expectEqualSlices(u8, fbs.getWritten()[1..], expected[0..]);
}

test "write slice of void" {
    // Compile error.
}

test "write map[u8]u8" {
    var buf: [5]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);


@@ 380,20 392,7 @@ test "write map[string]u8" {
}

test "write map[u8]void" {
    var buf: [100]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);

    var map = std.AutoHashMap(u8, void).init(testing.allocator);

    defer map.deinit();
    _ = try map.put(1, {});
    _ = try map.put(42, {});

    try Writer.init().write(map, fbs.outStream());
    // TODO: Fix this; later versions of std.HashMap preserve insertion order.
    const expected = "\x02\x2a\x01";
    expectEqual(fbs.getWritten().len, 3);
    expectEqualSlices(u8, fbs.getWritten(), expected[0..]);
    // Compile error.
}

test "write tagged union" {


@@ 422,12 421,7 @@ test "write tagged union with void member active" {
}

test "write void" {
     var buf: [10]u8 = undefined;
     var fbs = io.fixedBufferStream(&buf);
     var foo: void = undefined;

     try Writer.init().write(foo, fbs.outStream());
     expectEqual(fbs.getWritten().len, 0);
    // Compile error.
}

test "write unsupported type" {


@@ 511,7 505,7 @@ test "round trip i64 array" {
        .read(@TypeOf(arr), io.fixedBufferStream(fbs.getWritten()).inStream());
    expectEqualSlices(i64, arr[0..], res[0..]);
}
 

test "round trip i32 slice" {
    var buf: [0x100]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);