Zig / JSON in 5 minutes
Zig has built-in support for JSON via the std.json
module.
To convert any object into a JSON string, we use std.json.stringify(<input>, <options>, <output stream>)
:
const x = Place{
.lat = 51.997664,
.long = -0.740687,
};
var buf: [100]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
var string = std.ArrayList(u8).init(fba.allocator());
try std.json.stringify(x, .{}, string.writer());
See StringifyOptions
struct◹ for more details about what you can pass into the options.
To parse a JSON string into an object, we can do it in two ways:
Parse into a pre-defined struct with
std.json.parse(<output type>, <tokens>, <options>)
:const Foo = struct { a: i32, b: bool }; const s = \\ { \\ "a": 15, "b": true \\ } ; const stream = std.json.TokenStream.init(s); const parsedData = try std.json.parse(Foo, &stream, .{});
The
TokenStream
is a streaming parser that returns a stream of JSON, so we can pass them intostd.json.parse
.The JSON parser requires an allocator if the input JSON data contains strings or arrays, and we need to free them after use with
std.json.parseFree
:const gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer std.debug.assert(gpa.deinit()); const Foo = struct { a: i32, b: bool, c: []u8 }; const s = \\ { \\ "a": 15, "b": true, \\ "c": "hello world" \\ } ; const stream = std.json.TokenStream.init(s); const parsedData = try std.json.parse(Foo, &stream, .{ .allocator = gpa.allocator() }); defer std.json.parseFree(Foo, parsedData, .{ .allocator = gpa.allocator() });
Try comment out the
defer std.json.parseFree
statement to see how’s the memory leak detection ofGeneralPurposeAllocator
works.Checkout
ParseOptions
struct◹ for more about what options you can pass, for example:- Set
ignore_unknown_fields
totrue
will not return any error if there is a mismatch between the output type and input data. - Set
duplicate_field_behavior
will change the default’s behavior when there is a duplicate field in your JSON input.
- Set
Parse into a dynamic object of type
std.json.ValueTree
with a non-stream parserstd.json.Parser(<allocator>, <copy input string>)
:var parser = std.json.Parser.init(allocator, false); defer parser.deinit(); const s = \\ { \\ "a": 15, "b": true, \\ "c": "hello world" \\ } ; var tree = try parser.parse(s); defer tree.deinit(); // @TypeOf(tree.root) == std.json.Value // Access the fields value via .get() method var a = tree.root.Object.get("a").?; var b = tree.root.Object.get("b").?; var c = tree.root.Object.get("c").?;
There is also a
dump()
method that available on anystd.json.Value
, to stringify an object and print it out to thestderr
, best for debugging purpose:tree.root.dump();
For more details, you should read the implementation of std.json
module◹, also, don’t skip the tests at the bottom of the source file. They’re super useful!