~ntgg/serdes-zig

cf6a979d01b173f4088a404c521ea134b5908c1d — Noah Graff 6 months ago e40f5f7 master
changed serialize functions from (type, T) to (var)
2 files changed, 46 insertions(+), 47 deletions(-)

M src/main.zig
M src/serialize.zig
M src/main.zig => src/main.zig +0 -1
@@ 143,7 143,6 @@ test "valueToJsonIndent" {

    var value_tree = try serialize(
        std.debug.global_allocator,
        Person,
        Person{
            .first_name = "Noah",
            .last_name = "Graff",

M src/serialize.zig => src/serialize.zig +46 -46
@@ 14,11 14,11 @@ const Error = error{OutOfMemory};
// to use that instead of the default way of serializing a struct. If you do
// you have to use the provided allocator to allocate, not one in the struct.
// if the struct has both serialize and serializeJson it will use serializeJson.
pub fn serialize(allocator: *Allocator, comptime T: type, value: T) Error!ValueTree {
pub fn serialize(allocator: *Allocator, value: var) Error!ValueTree {
    var arena = std.heap.ArenaAllocator.init(allocator);
    errdefer arena.deinit();

    const root = try serializeValue(&arena.allocator, T, value);
    const root = try serializeValue(&arena.allocator, value);

    return ValueTree{
        .arena = arena,


@@ 28,30 28,31 @@ pub fn serialize(allocator: *Allocator, comptime T: type, value: T) Error!ValueT

/// If you want a ValueTree instead, use serialize
/// user is responsible for freeing memory
pub fn serializeValue(allocator: *Allocator, comptime T: type, value: T) Error!Value {
pub fn serializeValue(allocator: *Allocator, value: var) Error!Value {
    const T = @typeOf(value);
    switch (@typeId(T)) {
        .Null => return Value{ .Null = {} },
        .Bool => return Value{ .Bool = value },
        .Int, .ComptimeInt => return Value{ .Integer = @intCast(i64, value) },
        .Float, .ComptimeFloat => return Value{ .Float = @floatCast(f64, value) },
        .Optional => if (value) |v| {
            return try serializeValue(allocator, @typeOf(v), v);
            return try serializeValue(allocator, v);
        } else {
            return Value{ .Null = {} };
        },
        .Pointer => return try serializePointer(allocator, T, value),
        .Array => return try serializeArray(allocator, T, value),
        .Struct => return try serializeStruct(allocator, T, value),
        .Pointer => return try serializePointer(allocator, value),
        .Array => return try serializeArray(allocator, value),
        .Struct => return try serializeStruct(allocator, value),
        .Enum => return Value{ .String = @tagName(value) },
        .Union => return try serializeUnion(allocator, T, value),
        .Union => return try serializeUnion(allocator, value),
        else => @compileError(@typeName(T) ++ " is not able to be serialized!"),
    }
}

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

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


@@ 65,7 66,7 @@ fn serializeUnion(allocator: *Allocator, comptime T: type, value: T) Error!Value
                errdefer object.deinit();

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


@@ 76,8 77,9 @@ fn serializeUnion(allocator: *Allocator, comptime T: type, value: T) Error!Value
    std.debug.panic("Should not have gotten here!");
}

fn serializeStruct(allocator: *Allocator, comptime T: type, value: T) Error!Value {
fn serializeStruct(allocator: *Allocator, value: var) Error!Value {
    const hasFn = std.meta.trait.hasFn;
    const T = @typeOf(value);
    const info = switch (@typeInfo(T)) {
        .Struct => |i| i,
        else => @compileError("Expected a struct, found '" ++ @typeName(T) ++ "'"),


@@ 93,7 95,7 @@ fn serializeStruct(allocator: *Allocator, comptime T: type, value: T) Error!Valu
        inline for (info.fields) |field| {
            _ = try members.put(
                field.name,
                try serializeValue(allocator, field.field_type, @field(value, field.name)),
                try serializeValue(allocator, @field(value, field.name)),
            );
        }



@@ 104,21 106,21 @@ fn serializeStruct(allocator: *Allocator, comptime T: type, value: T) Error!Valu
/// treats the pointer as it's child type if the size is one,
/// if size > 1 returns a Value.String if the child type is u8
/// otherwise this will return a Value.Array
fn serializePointer(allocator: *Allocator, comptime T: type, value: T) Error!Value {
    const info = switch (@typeInfo(T)) {
fn serializePointer(allocator: *Allocator, value: var) Error!Value {
    const info = switch (@typeInfo(@typeOf(value))) {
        .Pointer => |i| i,
        else => @compileError("Expected a pointer or slice, found '" ++ @typeName(T) ++ "'"),
        else => @compileError("Expected a pointer or slice, found '" ++ @typeName(@typeOf(value)) ++ "'"),
    };

    switch (info.size) {
        .One => return try serializeValue(allocator, info.child, value.*),
        .One => return try serializeValue(allocator, value.*),
        .Slice => if (info.child == u8) {
            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));
                try list.append(try serializeValue(allocator, v));
            }
            return Value{ .Array = list };
        },


@@ 127,10 129,10 @@ fn serializePointer(allocator: *Allocator, comptime T: type, value: T) Error!Val
    }
}

fn serializeArray(allocator: *Allocator, comptime T: type, value: T) Error!Value {
    const info = switch (@typeInfo(T)) {
fn serializeArray(allocator: *Allocator, value: var) Error!Value {
    const info = switch (@typeInfo(@typeOf(value))) {
        .Array => |i| i,
        else => @compileError("Expected array found '" ++ @typeName(T) ++ "'"),
        else => @compileError("Expected array found '" ++ @typeName(@typeOf(value)) ++ "'"),
    };

    if (info.child == u8) {


@@ 139,7 141,7 @@ fn serializeArray(allocator: *Allocator, comptime T: type, value: T) Error!Value
        var list = std.ArrayList(Value).init(allocator);
        errdefer list.deinit();
        for (value) |v| {
            try list.append(try serializeValue(allocator, @typeOf(v), v));
            try list.append(try serializeValue(allocator, v));
        }
        return Value{ .Array = list };
    }


@@ 147,35 149,33 @@ fn serializeArray(allocator: *Allocator, comptime T: type, value: T) Error!Value

test "serialize string" {
    const t = std.testing;
    const array_string = try serializeValue(std.heap.direct_allocator, [10]u8, "test array");
    const slice_string = try serializeValue(std.heap.direct_allocator, []u8, &"test non-const");
    const const_slice_string = try serializeValue(std.heap.direct_allocator, []const u8, "test const");
    const array_string = try serializeValue(std.heap.direct_allocator, "test array");
    const slice_string = try serializeValue(std.heap.direct_allocator, &"test non-const");

    t.expectEqual(array_string.String, "test array");
    t.expectEqual(slice_string.String, "test non-const");
    t.expectEqual(const_slice_string.String, "test const");
}

test "serialize primitive" {
    const t = std.testing;

    const serialized_true = try serializeValue(std.heap.direct_allocator, bool, true);
    const serialized_false = try serializeValue(std.heap.direct_allocator, bool, false);
    const serialized_true = try serializeValue(std.heap.direct_allocator, true);
    const serialized_false = try serializeValue(std.heap.direct_allocator, false);
    t.expectEqual(serialized_true.Bool, true);
    t.expectEqual(serialized_false.Bool, false);

    const serialized_optional_null = try serializeValue(std.heap.direct_allocator, ?bool, null);
    const serialized_optional_value = try serializeValue(std.heap.direct_allocator, ?u8, 12);
    const serialized_optional_null = try serializeValue(std.heap.direct_allocator, (?bool)(null));
    const serialized_optional_value = try serializeValue(std.heap.direct_allocator, (?u8)(12));
    t.expect(serialized_optional_null == Value.Null);
    t.expectEqual(serialized_optional_value.Integer, 12);

    const serialized_int = try serializeValue(std.heap.direct_allocator, u32, 12345);
    const serialized_comptime_int = try serializeValue(std.heap.direct_allocator, comptime_int, 67890);
    const serialized_int = try serializeValue(std.heap.direct_allocator, u32(12345));
    const serialized_comptime_int = try serializeValue(std.heap.direct_allocator, 67890);
    t.expectEqual(serialized_int.Integer, 12345);
    t.expectEqual(serialized_comptime_int.Integer, 67890);

    const serialized_float = try serializeValue(std.heap.direct_allocator, f64, 123.456);
    const serialized_comptime_float = try serializeValue(std.heap.direct_allocator, comptime_float, 654.321);
    const serialized_float = try serializeValue(std.heap.direct_allocator, f64(123.456));
    const serialized_comptime_float = try serializeValue(std.heap.direct_allocator, 654.321);
    t.expectEqual(serialized_float.Float, 123.456);
    t.expectEqual(serialized_comptime_float.Float, 654.321);
}


@@ 184,12 184,12 @@ test "serialize array" {
    const t = std.testing;

    const array_float = [_]f64{ 33.2, 16.8, 18.0 };
    const serialized_array_float = try serializeValue(std.heap.direct_allocator, @typeOf(array_float), array_float);
    const serialized_array_float = try serializeValue(std.heap.direct_allocator, array_float);
    const nested_array_float = [_][3]f64{
        [_]f64{ 33.2, 16.8, 18.0 },
        [_]f64{ 18.0, 16.8, 33.2 },
    };
    const serialized_nested_array_float = try serializeValue(std.heap.direct_allocator, @typeOf(nested_array_float), nested_array_float);
    const serialized_nested_array_float = try serializeValue(std.heap.direct_allocator, nested_array_float);

    t.expectEqual(array_float[0], serialized_array_float.Array.toSlice()[0].Float);
    t.expectEqual(array_float[1], serialized_array_float.Array.toSlice()[1].Float);


@@ 232,8 232,8 @@ test "serialize struct" {
        nested: TestStruct,
    };

    const serialized_struct = try serializeValue(std.heap.direct_allocator, TestStruct, TestStruct{ .num = 24, .string = "heyyo" });
    const serialized_nested_struct = try serializeValue(std.heap.direct_allocator, NestedStruct, NestedStruct{ .nested = TestStruct{ .num = 42, .string = "" } });
    const serialized_struct = try serializeValue(std.heap.direct_allocator, TestStruct{ .num = 24, .string = "heyyo" });
    const serialized_nested_struct = try serializeValue(std.heap.direct_allocator, NestedStruct{ .nested = TestStruct{ .num = 42, .string = "" } });

    t.expectEqual(serialized_struct.Object.getValue("num").?.Integer, 24);
    t.expectEqual(serialized_struct.Object.getValue("string").?.String, "heyyo");


@@ 254,7 254,7 @@ test "serialize struct with custom serialize function" {

        pub fn serializeJson(self: Self, allocator: *Allocator) Error!Value {
            var object = ObjectMap.init(allocator);
            _ = try object.put(self.first_name, try serializeValue(allocator, u8, self.age));
            _ = try object.put(self.first_name, try serializeValue(allocator, self.age));
            return Value{ .Object = object };
        }



@@ 271,13 271,13 @@ test "serialize struct with custom serialize function" {

        pub fn serialize(self: Self, allocator: *Allocator) Error!Value {
            var object = ObjectMap.init(allocator);
            _ = try object.put(self.last_name, try serializeValue(allocator, u8, self.age));
            _ = try object.put(self.last_name, try serializeValue(allocator, self.age));
            return Value{ .Object = object };
        }
    };

    const serialized_struct = try serializeValue(std.heap.direct_allocator, TestStruct, TestStruct{ .first_name = "Andre", .last_name = "3000", .age = 44 });
    const serialized_struct_json = try serializeValue(std.heap.direct_allocator, TestStructJson, TestStructJson{ .first_name = "big", .last_name = "boi", .age = 44 });
    const serialized_struct = try serializeValue(std.heap.direct_allocator, TestStruct{ .first_name = "Andre", .last_name = "3000", .age = 44 });
    const serialized_struct_json = try serializeValue(std.heap.direct_allocator, TestStructJson{ .first_name = "big", .last_name = "boi", .age = 44 });
    t.expectEqual(serialized_struct.Object.getValue("3000").?.Integer, 44);
    t.expectEqual(serialized_struct_json.Object.getValue("big").?.Integer, 44);
}


@@ 298,7 298,7 @@ test "serialize enum and union" {
    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");
    t.expectEqual((try serializeValue(std.heap.direct_allocator, ua)).String, "A");
    t.expectEqual((try serializeValue(std.heap.direct_allocator, ub)).Object.getValue("B").?.Integer, 96);
    t.expectEqual((try serializeValue(std.heap.direct_allocator, e)).String, "Optional");
}