summaryrefslogtreecommitdiff
path: root/src/json.zig
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2024-07-20 17:22:25 +0300
committerGravatar Uko Kokņevičs2024-07-20 17:22:25 +0300
commitc70ffd095a6de5cd5b872796a0d82a8c5afc1511 (patch)
tree56183274b05a294e357bad4d06b523472a1c4a4a /src/json.zig
downloadukkobot-c70ffd095a6de5cd5b872796a0d82a8c5afc1511.tar.gz
ukkobot-c70ffd095a6de5cd5b872796a0d82a8c5afc1511.tar.xz
ukkobot-c70ffd095a6de5cd5b872796a0d82a8c5afc1511.zip
Initial commit
Diffstat (limited to 'src/json.zig')
-rw-r--r--src/json.zig108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/json.zig b/src/json.zig
new file mode 100644
index 0000000..9252344
--- /dev/null
+++ b/src/json.zig
@@ -0,0 +1,108 @@
1// TODO: ALSO IMPLEMENT jsonStringify !!!
2
3const std = @import("std");
4
5const Allocator = std.mem.Allocator;
6const ParseError = std.json.ParseError;
7const ParseFromValueError = std.json.ParseFromValueError;
8const ParseOptions = std.json.ParseOptions;
9const Value = std.json.Value;
10
11pub fn JsonParse(T: type) type {
12 const f = struct {
13 pub fn f(allocator: Allocator, source: anytype, options: ParseOptions) ParseError(@TypeOf(source.*))!T {
14 _ = allocator;
15 _ = options;
16 unreachable;
17 }
18 }.f;
19 return @TypeOf(f);
20}
21
22pub fn makeJsonParse(T: type) JsonParse(T) {
23 comptime if (!std.meta.hasFn(T, "jsonParseFromValue")) {
24 @compileError("Did you forget `pub const jsonParseFromValue = json.makeJsonParseFromValue(" ++ @typeName(T) ++ ") ?");
25 };
26
27 return struct {
28 pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) ParseError(@TypeOf(source.*))!T {
29 const value = try std.json.innerParse(Value, allocator, source, options);
30 return try T.jsonParseFromValue(allocator, value, options);
31 }
32 }.jsonParse;
33}
34
35pub fn JsonParseFromValue(T: type) type {
36 const f = struct {
37 pub fn f(allocator: Allocator, source: Value, options: ParseOptions) ParseFromValueError!T {
38 _ = allocator;
39 _ = source;
40 _ = options;
41 unreachable;
42 }
43 }.f;
44 return @TypeOf(f);
45}
46
47pub fn makeJsonParseFromValue(T: type) JsonParseFromValue(T) {
48 return makeJsonParseFromValueWithTag(T, "type");
49}
50
51pub fn makeJsonParseFromValueWithTag(T: type, comptime tag: [:0]const u8) JsonParseFromValue(T) {
52 const union_info = switch (@typeInfo(T)) {
53 .Union => |info| blk: {
54 if (info.tag_type == null) {
55 @compileError("Only tagged unions supported, got '" ++ @typeName(T) ++ "'");
56 }
57 break :blk info;
58 },
59 else => @compileError("Only unions supported, got '" ++ @typeName(T) ++ "'"),
60 };
61
62 const TagType = union_info.tag_type.?;
63
64 const Base = blk: {
65 const info = std.builtin.Type{ .Struct = .{
66 .layout = .auto,
67 .fields = &.{.{
68 .name = tag,
69 .type = TagType,
70 .default_value = null,
71 .is_comptime = false,
72 .alignment = 0,
73 }},
74 .decls = &.{},
75 .is_tuple = false,
76 } };
77 break :blk @Type(info);
78 };
79
80 return struct {
81 pub fn jsonParseFromValue(
82 allocator: Allocator,
83 source: Value,
84 options: ParseOptions,
85 ) ParseFromValueError!T {
86 const new_options = blk: {
87 var opt = options;
88 opt.ignore_unknown_fields = true;
89 break :blk opt;
90 };
91
92 const base = try std.json.innerParseFromValue(Base, allocator, source, new_options);
93 const typeName = @tagName(@field(base, tag));
94 // TODO: Upgrade to StaticStringMap
95 inline for (union_info.fields) |field_info| {
96 if (std.mem.eql(u8, typeName, field_info.name)) {
97 return @unionInit(
98 T,
99 field_info.name,
100 try std.json.innerParseFromValue(field_info.type, allocator, source, new_options),
101 );
102 }
103 }
104
105 unreachable;
106 }
107 }.jsonParseFromValue;
108}