pub fn innerParse(comptime T: type, allocator: Allocator, source: anytype, options: ParseOptions) ParseError(@TypeOf(source .*))!TThis is an internal function called recursively during the implementation of parseFromTokenSourceLeaky and similar. It is exposed primarily to enable custom jsonParse() methods to call back into the parseFrom* system, such as if you're implementing a custom container of type T; you can call innerParse(T, ...) for each of the container's items. Note that null fields are not allowed on the options when calling this function. (The options you get in your jsonParse method has no null fields.)
pub fn innerParseFromValue(comptime T: type, allocator: Allocator, source: Value, options: ParseOptions) ParseFromValueError!TThis is an internal function called recursively during the implementation of parseFromValueLeaky. It is exposed primarily to enable custom jsonParseFromValue() methods to call back into the parseFromValue* system, such as if you're implementing a custom container of type T; you can call innerParseFromValue(T, ...) for each of the container's items.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80const std = @import("std");
const Allocator = std.mem.Allocator;
const ParseOptions = @import("static.zig").ParseOptions;
const innerParse = @import("static.zig").innerParse;
const innerParseFromValue = @import("static.zig").innerParseFromValue;
const Value = @import("dynamic.zig").Value;
/// A thin wrapper around `std.array_hash_map.String` that implements
/// `jsonParse`, `jsonParseFromValue`, and `jsonStringify`.
/// This is useful when your JSON schema has an object with arbitrary data keys
/// instead of comptime-known struct field names.
pub fn ArrayHashMap(comptime T: type) type {
return struct {
map: std.array_hash_map.String(T) = .empty,
pub fn deinit(self: *@This(), allocator: Allocator) void {
self.map.deinit(allocator);
}
pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) !@This() {
var map: std.array_hash_map.String(T) = .empty;
errdefer map.deinit(allocator);
if (.object_begin != try source.next()) return error.UnexpectedToken;
while (true) {
const token = try source.nextAlloc(allocator, options.allocate.?);
switch (token) {
inline .string, .allocated_string => |k| {
const gop = try map.getOrPut(allocator, k);
if (gop.found_existing) {
switch (options.duplicate_field_behavior) {
.use_first => {
// Parse and ignore the redundant value.
// We don't want to skip the value, because we want type checking.
_ = try innerParse(T, allocator, source, options);
continue;
},
.@"error" => return error.DuplicateField,
.use_last => {},
}
}
gop.value_ptr.* = try innerParse(T, allocator, source, options);
},
.object_end => break,
else => unreachable,
}
}
return .{ .map = map };
}
pub fn jsonParseFromValue(allocator: Allocator, source: Value, options: ParseOptions) !@This() {
if (source != .object) return error.UnexpectedToken;
var map: std.array_hash_map.String(T) = .empty;
errdefer map.deinit(allocator);
var it = source.object.iterator();
while (it.next()) |kv| {
try map.put(allocator, kv.key_ptr.*, try innerParseFromValue(T, allocator, kv.value_ptr.*, options));
}
return .{ .map = map };
}
pub fn jsonStringify(self: @This(), jws: anytype) !void {
try jws.beginObject();
var it = self.map.iterator();
while (it.next()) |kv| {
try jws.objectField(kv.key_ptr.*);
try jws.write(kv.value_ptr.*);
}
try jws.endObject();
}
};
}
test {
_ = @import("hashmap_test.zig");
}