Repository navigation
Expand file tree
/
Copy pathjson_miniparse.zig
More file actions
104 lines (83 loc) · 4.46 KB
/
Copy pathjson_miniparse.zig
File metadata and controls
104 lines (83 loc) · 4.46 KB
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
const std = @import("std");
/// Extract a string field value from a JSON blob (minimal parser — no allocations).
pub fn parseStringField(json: []const u8, key: []const u8) ?[]const u8 {
var needle_buf: [256]u8 = undefined;
const quoted_key = std.fmt.bufPrint(&needle_buf, "\"{s}\"", .{key}) catch return null;
const key_pos = std.mem.indexOf(u8, json, quoted_key) orelse return null;
const after_key = json[key_pos + quoted_key.len ..];
var i: usize = 0;
while (i < after_key.len and (after_key[i] == ' ' or after_key[i] == ':' or after_key[i] == '\t' or after_key[i] == '\n')) : (i += 1) {}
if (i >= after_key.len or after_key[i] != '"') return null;
i += 1;
const start = i;
while (i < after_key.len) : (i += 1) {
if (after_key[i] == '\\' and i + 1 < after_key.len) {
i += 1;
continue;
}
if (after_key[i] == '"') return after_key[start..i];
}
return null;
}
/// Extract a boolean field value from a JSON blob.
pub fn parseBoolField(json: []const u8, key: []const u8) ?bool {
var needle_buf: [256]u8 = undefined;
const quoted_key = std.fmt.bufPrint(&needle_buf, "\"{s}\"", .{key}) catch return null;
const key_pos = std.mem.indexOf(u8, json, quoted_key) orelse return null;
const after_key = json[key_pos + quoted_key.len ..];
var i: usize = 0;
while (i < after_key.len and (after_key[i] == ' ' or after_key[i] == ':' or after_key[i] == '\t' or after_key[i] == '\n')) : (i += 1) {}
if (i + 4 <= after_key.len and std.mem.eql(u8, after_key[i..][0..4], "true")) return true;
if (i + 5 <= after_key.len and std.mem.eql(u8, after_key[i..][0..5], "false")) return false;
return null;
}
/// Extract an integer field value from a JSON blob.
pub fn parseIntField(json: []const u8, key: []const u8) ?i64 {
var needle_buf: [256]u8 = undefined;
const quoted_key = std.fmt.bufPrint(&needle_buf, "\"{s}\"", .{key}) catch return null;
const key_pos = std.mem.indexOf(u8, json, quoted_key) orelse return null;
const after_key = json[key_pos + quoted_key.len ..];
var i: usize = 0;
while (i < after_key.len and (after_key[i] == ' ' or after_key[i] == ':' or after_key[i] == '\t' or after_key[i] == '\n')) : (i += 1) {}
const start = i;
if (i < after_key.len and after_key[i] == '-') i += 1;
while (i < after_key.len and after_key[i] >= '0' and after_key[i] <= '9') : (i += 1) {}
if (i == start) return null;
return std.fmt.parseInt(i64, after_key[start..i], 10) catch null;
}
/// Extract an unsigned integer field value from a JSON blob.
pub fn parseUintField(json: []const u8, key: []const u8) ?u64 {
var needle_buf: [256]u8 = undefined;
const quoted_key = std.fmt.bufPrint(&needle_buf, "\"{s}\"", .{key}) catch return null;
const key_pos = std.mem.indexOf(u8, json, quoted_key) orelse return null;
const after_key = json[key_pos + quoted_key.len ..];
var i: usize = 0;
while (i < after_key.len and (after_key[i] == ' ' or after_key[i] == ':' or after_key[i] == '\t' or after_key[i] == '\n')) : (i += 1) {}
const start = i;
while (i < after_key.len and after_key[i] >= '0' and after_key[i] <= '9') : (i += 1) {}
if (i == start) return null;
return std.fmt.parseInt(u64, after_key[start..i], 10) catch null;
}
test "json_miniparse parseStringField basic" {
const json = "{\"command\": \"echo hello\", \"other\": \"val\"}";
const val = parseStringField(json, "command");
try std.testing.expect(val != null);
try std.testing.expectEqualStrings("echo hello", val.?);
}
test "json_miniparse parseBoolField values" {
try std.testing.expectEqual(true, parseBoolField("{\"enabled\": true}", "enabled").?);
try std.testing.expectEqual(false, parseBoolField("{\"enabled\": false}", "enabled").?);
}
test "json_miniparse parseIntField supports signed numbers" {
try std.testing.expectEqual(@as(i64, 42), parseIntField("{\"n\": 42}", "n").?);
try std.testing.expectEqual(@as(i64, -7), parseIntField("{\"n\": -7}", "n").?);
}
test "json_miniparse parseUintField supports positive numbers" {
try std.testing.expectEqual(@as(u64, 42), parseUintField("{\"n\": 42}", "n").?);
}
test "json_miniparse missing fields return null" {
try std.testing.expect(parseStringField("{\"x\":1}", "name") == null);
try std.testing.expect(parseBoolField("{\"x\":1}", "enabled") == null);
try std.testing.expect(parseIntField("{\"x\":1}", "n") == null);
try std.testing.expect(parseUintField("{\"x\":1}", "n") == null);
}