@@ 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");
+}