Skip to content

Instantly share code, notes, and snippets.

@not-fl3

not-fl3/json.zig Secret

Last active July 18, 2019 14:55
Show Gist options
  • Save not-fl3/303f408eb5f98fb7b66d140bd80dfc38 to your computer and use it in GitHub Desktop.
Save not-fl3/303f408eb5f98fb7b66d140bd80dfc38 to your computer and use it in GitHub Desktop.
const std = @import("std");
const TypeInfo = @import("builtin").TypeInfo;
const TypeId = @import("builtin").TypeId;
pub fn Deserialzier(comptime T: type) type {
return struct {
const Self = @This();
fn deserialize(allocator: *std.mem.Allocator, string: []const u8) !T {
var p = std.json.Parser.init(allocator, false);
defer p.deinit();
var tree = try p.parse(string);
defer tree.deinit();
return parseValue(allocator, T, tree.root);
}
};
}
fn parseValue(allocator: *std.mem.Allocator, comptime T: type, value: std.json.Value) !T {
switch (@typeId(T)) {
TypeId.Int, TypeId.Float => {
return parseNumber(allocator, T, value);
},
TypeId.Pointer => {
return parseArray(allocator, T, value);
},
TypeId.Struct => {
return parseStruct(allocator, T, value);
},
else => {
std.debug.warn("{}", @typeId(T));
return error.UnsupportedFieldType;
},
}
}
fn parseStruct(allocator: *std.mem.Allocator, comptime T: type, value: std.json.Value) !T {
var res: T = undefined;
inline for (@typeInfo(T).Struct.fields) |field, i| {
const json_field = value.Object.get(field.name) orelse {
return error.UnknownField;
};
@field(res, field.name) = try parseValue(allocator, field.field_type, json_field.value);
}
return res;
}
fn parseArray(allocator: *std.mem.Allocator, comptime T: type, value: std.json.Value) !T {
const type_info = @typeInfo(T);
if (type_info.Pointer.size != TypeInfo.Pointer.Size.Slice) {
return error.InavlidPointerType;
}
if (T == []u8 and std.json.Value(value) == std.json.Value.String) {
return try std.mem.dupe(allocator, u8, value.String);
}
const child_type = type_info.Pointer.child;
var array: T = try allocator.alloc(child_type, value.Array.count());
for (value.Array.toSlice()) |child_value, i| {
array[i] = try parseValue(allocator, child_type, child_value);
}
return array;
}
fn parseNumber(allocator: *std.mem.Allocator, comptime T: type, value: std.json.Value) !T {
switch (T) {
f32, f64 => {
switch (value) {
std.json.Value.Integer => {
return @intToFloat(T, value.Integer);
},
std.json.Value.Float => {
return @floatCast(T, value.Float);
},
else => {
return error.InvalidJsonFieldType;
},
}
},
u8, i8, i16, u16, i32, u32, i64, u64 => {
if (std.json.Value(value) != std.json.Value.Integer) {
return error.InvalidJsonFieldType;
}
return @intCast(T, value.Integer);
},
else => {
value.dump();
return error.UnsupportedFieldType;
},
}
}
test "" {
const Foo = struct {
float: f32,
int: i32,
string: []u8,
array: []u8,
};
const json_string =
\\ {
\\ "float": 0,
\\ "int": 1,
\\ "string": "2 hello",
\\ "array": [3, 4, 5]
\\ }
;
const deserialzier = Deserialzier(Foo);
const foo = try deserialzier.deserialize(std.debug.global_allocator, json_string[0..]);
std.debug.assert(foo.float == 0.0);
std.debug.assert(foo.int == 1);
std.testing.expectEqualSlices(u8, foo.string, "2 hello");
std.testing.expectEqualSlices(u8, foo.array, [_]u8{ 3, 4, 5 });
}
test "" {
const Bar = struct {
x: i32,
y: i32,
};
const Foo = struct {
bar: Bar,
};
const json_string =
\\{
\\ "bar":
\\ {
\\ "x": 1,
\\ "y": 2
\\ }
\\}
;
const deserialzier = Deserialzier(Foo);
const foo = try deserialzier.deserialize(std.debug.global_allocator, json_string[0..]);
std.debug.assert(foo.bar.x == 1);
std.debug.assert(foo.bar.y == 2);
}
test "" {
const Bar = struct {
x: i32,
y: i32,
};
const Foo = struct {
bars: []Bar,
};
const json_string =
\\{
\\ "bars": [
\\ {
\\ "x": 1,
\\ "y": 2
\\ },
\\ {
\\ "x": 3,
\\ "y": 4
\\ }
\\ ]
\\}
;
const deserialzier = Deserialzier(Foo);
const foo = try deserialzier.deserialize(std.debug.global_allocator, json_string[0..]);
std.debug.assert(foo.bars[0].x == 1);
std.debug.assert(foo.bars[0].y == 2);
std.debug.assert(foo.bars[1].x == 3);
std.debug.assert(foo.bars[1].y == 4);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment