Skip to content

Commit

Permalink
dom: support user defined jsonParse() method
Browse files Browse the repository at this point in the history
this allows the user to provide a custom parser similar jsonParse() in
std.json

* rename getImpl() to jsonParse() following std.json
  • Loading branch information
travisstaloch committed Oct 7, 2023
1 parent 42ef696 commit 9d996c5
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
24 changes: 15 additions & 9 deletions src/dom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1746,7 +1746,9 @@ const TapeRefIterator = struct {
return .{ .tape = tri.tape };
}
};
const Element = struct {

/// this is public to allow for custom jsonParse() methods
pub const Element = struct {
tape: TapeRef,

pub fn at_pointer(ele: Element, json_pointer: []const u8) cmn.Error!Element {
Expand All @@ -1767,13 +1769,13 @@ const Element = struct {

/// parse from 'ele' into 'out' pointer
pub fn get(ele: Element, out: anytype) cmn.Error!void {
return ele.getImpl(.{ out, null });
return ele.jsonParse(.{ out, null });
}

/// parse from 'ele' into 'out' pointer.
/// to be used inplace of get() when 'out' contains non-string slice types.
pub fn get_alloc(ele: Element, allocator: mem.Allocator, out: anytype) cmn.Error!void {
return ele.getImpl(.{ out, allocator });
return ele.jsonParse(.{ out, allocator });
}

fn readSlice(
Expand Down Expand Up @@ -1801,21 +1803,25 @@ const Element = struct {
var out_ele: Cchild = undefined;
const idx = it.tape.after_element();
// std.debug.print("next_element={}:{}\n", .{ idx, TapeType.from_u64(it.tape.doc.tape.items[idx]) });
try arr_ele.getImpl(.{ &out_ele, args[1] });
try arr_ele.jsonParse(.{ &out_ele, args[1] });
try elems.append(out_ele);
it.tape.idx = idx;
if (it.tape.idx >= it.end_idx) break;
}
out.* = try elems.toOwnedSlice();
}

fn getImpl(ele: Element, args: anytype) cmn.Error!void {
/// this being public allows for custom jsonParse() methods to call back into this method.
pub fn jsonParse(ele: Element, args: anytype) cmn.Error!void {
const out = args[0];
const T = @TypeOf(out);
const info = @typeInfo(T);
switch (info) {
.Pointer => {
const C = std.meta.Child(T);
if (comptime std.meta.trait.hasFn("jsonParse")(C))
return C.jsonParse(ele, args);

const child_info = @typeInfo(C);
switch (info.Pointer.size) {
.One => {
Expand All @@ -1830,17 +1836,17 @@ const Element = struct {
null
else blk: {
var x: std.meta.Child(C) = undefined;
try ele.getImpl(.{ &x, args[1] });
try ele.jsonParse(.{ &x, args[1] });
break :blk x;
},
.Array => try ele.getImpl(.{ @as([]std.meta.Child(C), out), args[1] }),
.Array => try ele.jsonParse(.{ @as([]std.meta.Child(C), out), args[1] }),
.Struct => {
switch (ele.tape.tape_ref_type()) {
.START_OBJECT => {
var obj = ele.get_object() catch unreachable;
inline for (std.meta.fields(C)) |field| {
if (obj.at_key(field.name)) |obj_ele|
try obj_ele.getImpl(.{ &@field(out, field.name), args[1] });
try obj_ele.jsonParse(.{ &@field(out, field.name), args[1] });
}
},
else => return error.INCORRECT_TYPE,
Expand Down Expand Up @@ -1881,7 +1887,7 @@ const Element = struct {
var it = TapeRefIterator.init(arr);
for (out) |*out_ele| {
const arr_ele = Element{ .tape = it.tape };
try arr_ele.getImpl(.{ out_ele, args[1] });
try arr_ele.jsonParse(.{ out_ele, args[1] });
_ = it.next() orelse break;
}
},
Expand Down
24 changes: 22 additions & 2 deletions src/tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ test "get with slice/array" {
// README tests
// ------------

// const dom = @import("dom.zig");
// const dom = @import("simdjzon").dom;
test "get with struct" {
const S = struct { a: u8, b: []const u8, c: struct { d: u8 } };
const input =
Expand Down Expand Up @@ -348,6 +348,26 @@ test "get_alloc struct field slice more field types" {
}
}

test "user defined jsonParse()" {
const input =
\\{ "foo": "bar"}
;
const T = struct {
foo: []const u8,
pub fn jsonParse(ele: dom.Element, args: anytype) !void {
_ = ele;
var out = args[0];
out.foo = "foo";
}
};
var parser = try dom.Parser.initFixedBuffer(allr, input, .{});
defer parser.deinit();
try parser.parse();
var s: T = undefined;
try parser.element().get(&s);
try testing.expectEqualStrings("foo", s.foo);
}

test "get_alloc slice of struct" {
const S = struct { a: u8, b: []const u8 };
const T = []S;
Expand All @@ -372,7 +392,7 @@ test "get_alloc slice of struct" {
}
}

// const ondemand = @import("ondemand.zig");
// const ondemand = simdjzon.ondemand;
test "ondemand get with struct" {
const S = struct { a: struct { b: []const u8 } };
const input =
Expand Down

0 comments on commit 9d996c5

Please sign in to comment.