~ntgg/serdes-zig

9fdffc855037714222a1242018948142aff43ab7 — Noah Graff 5 years ago 07f4c12
added serialize for tagged union an enum
1 files changed, 54 insertions(+), 2 deletions(-)

M src/serialize.zig
M src/serialize.zig => src/serialize.zig +54 -2
@@ 41,12 41,40 @@ pub fn serializeValue(allocator: *Allocator, comptime T: type, value: T) anyerro
        .Pointer => return try serializePointer(allocator, T, value),
        .Array => return try serializeArray(allocator, T, value),
        .Struct => return try serializeStruct(allocator, T, value),
        // .Enum => return try serializeEnum(allocator, T, value),
        // .Union => return try serializeUnion(allocator, T, value),
        .Enum => return Value{ .String = @tagName(value) },
        .Union => return try serializeUnion(allocator, T, value),
        else => @compileError(@typeName(T) ++ " is not able to be serialized!"),
    }
}

fn serializeUnion(allocator: *Allocator, comptime T: type, value: T) anyerror!Value {
    const info = switch (@typeInfo(T)) {
        .Union => |i| i,
        else => @compileError("Expected union, found '" ++ @typeName(T) ++ "'"),
    };

    comptime std.testing.expect(info.tag_type != null);

    // the way of getting the active value is jank, is there a better way to do this?
    // can't just do @field(vaule, @tagName), because @tagName is not comptime
    inline for (info.fields) |field| {
        if (std.mem.eql(u8, @tagName(value), field.name)) {
            if (field.field_type != void) {
                var object = ObjectMap.init(allocator);
                errdefer object.deinit();

                const child_value = @field(value, field.name);
                _ = try object.put(field.name, try serializeValue(allocator, field.field_type, child_value));
                return Value { .Object = object };
            } else {
                return Value { .String = field.name };
            }
        }
    }

    std.debug.panic("Should not have gotten here!");
}

fn serializeStruct(allocator: *Allocator, comptime T: type, value: T) anyerror!Value {
    const hasFn = std.meta.trait.hasFn;
    const info = switch (@typeInfo(T)) {


@@ 60,6 88,7 @@ fn serializeStruct(allocator: *Allocator, comptime T: type, value: T) anyerror!V
        return try value.serialize(allocator);
    } else {
        var members = ObjectMap.init(allocator);
        errdefer members.deinit();
        inline for (info.fields) |field| {
            _ = try members.put(
                field.name,


@@ 86,6 115,7 @@ fn serializePointer(allocator: *Allocator, comptime T: type, value: T) anyerror!
            return Value{ .String = value };
        } else {
            var list = std.ArrayList(Value).init(allocator);
            errdefer list.deinit();
            for (value) |v| {
                try list.append(try serializeValue(allocator, @typeOf(v), v));
            }


@@ 106,6 136,7 @@ fn serializeArray(allocator: *Allocator, comptime T: type, value: T) anyerror!Va
        return Value{ .String = value };
    } else {
        var list = std.ArrayList(Value).init(allocator);
        errdefer list.deinit();
        for (value) |v| {
            try list.append(try serializeValue(allocator, @typeOf(v), v));
        }


@@ 249,3 280,24 @@ test "serialize struct with custom serialize function" {
    t.expectEqual(serialized_struct.Object.getValue("3000").?.Integer, 44);
    t.expectEqual(serialized_struct_json.Object.getValue("big").?.Integer, 44);
}

test "serialize enum and union" {
    const t = std.testing;

    const U1 = union(enum) {
        A: void,
        B: u32,
    };
    const E1 = enum {
        Optional,
        Bool,
    };

    const ua = U1{ .A = {} };
    const ub = U1{ .B = 96 };
    const e = E1.Optional;

    t.expectEqual((try serializeValue(std.heap.direct_allocator, U1, ua)).String, "A");
    t.expectEqual((try serializeValue(std.heap.direct_allocator, U1, ub)).Object.getValue("B").?.Integer, 96);
    t.expectEqual((try serializeValue(std.heap.direct_allocator, E1, e)).String, "Optional");
}