Providing custom `jsonParse` to JSON objects examples

I’m finding it hard to locate good examples of providing custom jsonParse functions for objects. I figured that if I’m having issues locating it, then other people probably are too so it’s a good idea to ask. To be clear, I’m not referring to the jsonStringify.

In the static.zig file, you can see that there are checks for:

if (std.meta.hasFn(T, "jsonParse")) {
     return T.jsonParse(allocator, source, options);
}

Any clear examples of customizing this function that people are aware of?

1 Like

I have found this following tests in static_test.zig but they’re not particularly explanatory:

const Subnamespaces = struct {
    packed_struct: packed struct { a: u32, b: u32 },
    union_enum: union(enum) { i: i32, s: []const u8, v },
    inferred_enum: enum { a, b },
    explicit_enum: enum(u8) { a = 0, b = 1 },

    custom_struct: struct {
        pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) !@This() {
            _ = allocator;
            _ = options;
            try source.skipValue();
            return @This(){};
        }
        pub fn jsonParseFromValue(allocator: Allocator, source: Value, options: ParseOptions) !@This() {
            _ = allocator;
            _ = source;
            _ = options;
            return @This(){};
        }
    },
    custom_union: union(enum) {
        i: i32,
        s: []const u8,
        pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) !@This() {
            _ = allocator;
            _ = options;
            try source.skipValue();
            return @This(){ .i = 0 };
        }
        pub fn jsonParseFromValue(allocator: Allocator, source: Value, options: ParseOptions) !@This() {
            _ = allocator;
            _ = source;
            _ = options;
            return @This(){ .i = 0 };
        }
    },
    custom_enum: enum {
        a,
        b,
        pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) !@This() {
            _ = allocator;
            _ = options;
            try source.skipValue();
            return .a;
        }
        pub fn jsonParseFromValue(allocator: Allocator, source: Value, options: ParseOptions) !@This() {
            _ = allocator;
            _ = source;
            _ = options;
            return .a;
        }
    },
};

Briefly, here’s how I made this work with jsonParse.

The parse is declared as:

pub fn jsonParse(
    allocator: std.mem.Allocator,
    source: anytype // more on this below
    options: std.json.ParseOptions,
) !MyType {

If you’re only trying to be compatible with parseFromSlice then you can instead declare the source variable as source: *std.json.Scanner.

From there, the scanner has a next function that returns tokens. These tokens have information like object begin which implies that you’ve hit something like a curly bracket.

For the type I needed, I just checked to see that the next token is a number:

if (token == .number)

Which means it holds onto a sub-slice of the json which contains the numeric string. From there, you just treat that slice like any other by using token.number.