Skip to content

Commit 61236c2

Browse files
authored
std: @vector support for std.json.parse
1 parent 5b9e528 commit 61236c2

File tree

2 files changed

+71
-20
lines changed

2 files changed

+71
-20
lines changed

lib/std/json.zig

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,11 @@ fn ParseInternalErrorImpl(comptime T: type, comptime inferred_types: []const typ
13891389
UnescapeValidStringError ||
13901390
ParseInternalErrorImpl(arrayInfo.child, inferred_types ++ [_]type{T});
13911391
},
1392+
.Vector => |vecInfo| {
1393+
return error{ UnexpectedEndOfJson, UnexpectedToken, LengthMismatch } || TokenStream.Error ||
1394+
UnescapeValidStringError ||
1395+
ParseInternalErrorImpl(vecInfo.child, inferred_types ++ [_]type{T});
1396+
},
13921397
.Pointer => |ptrInfo| {
13931398
var errors = error{AllocatorRequired} || std.mem.Allocator.Error;
13941399
switch (ptrInfo.size) {
@@ -1408,6 +1413,35 @@ fn ParseInternalErrorImpl(comptime T: type, comptime inferred_types: []const typ
14081413
unreachable;
14091414
}
14101415

1416+
fn parseInternalArray(
1417+
comptime T: type,
1418+
comptime Elt: type,
1419+
comptime arr_len: usize,
1420+
tokens: *TokenStream,
1421+
options: ParseOptions,
1422+
) ParseInternalError(T)!T {
1423+
var r: T = undefined;
1424+
var i: usize = 0;
1425+
var child_options = options;
1426+
child_options.allow_trailing_data = true;
1427+
errdefer {
1428+
// Without the r.len check `r[i]` is not allowed
1429+
if (arr_len > 0) while (true) : (i -= 1) {
1430+
parseFree(Elt, r[i], options);
1431+
if (i == 0) break;
1432+
};
1433+
}
1434+
if (arr_len > 0) while (i < arr_len) : (i += 1) {
1435+
r[i] = try parse(Elt, tokens, child_options);
1436+
};
1437+
const tok = (try tokens.next()) orelse return error.UnexpectedEndOfJson;
1438+
switch (tok) {
1439+
.ArrayEnd => {},
1440+
else => return error.UnexpectedToken,
1441+
}
1442+
return r;
1443+
}
1444+
14111445
fn parseInternal(
14121446
comptime T: type,
14131447
token: Token,
@@ -1624,26 +1658,8 @@ fn parseInternal(
16241658
.Array => |arrayInfo| {
16251659
switch (token) {
16261660
.ArrayBegin => {
1627-
var r: T = undefined;
1628-
var i: usize = 0;
1629-
var child_options = options;
1630-
child_options.allow_trailing_data = true;
1631-
errdefer {
1632-
// Without the r.len check `r[i]` is not allowed
1633-
if (r.len > 0) while (true) : (i -= 1) {
1634-
parseFree(arrayInfo.child, r[i], options);
1635-
if (i == 0) break;
1636-
};
1637-
}
1638-
while (i < r.len) : (i += 1) {
1639-
r[i] = try parse(arrayInfo.child, tokens, child_options);
1640-
}
1641-
const tok = (try tokens.next()) orelse return error.UnexpectedEndOfJson;
1642-
switch (tok) {
1643-
.ArrayEnd => {},
1644-
else => return error.UnexpectedToken,
1645-
}
1646-
return r;
1661+
const len = @typeInfo(T).Array.len;
1662+
return parseInternalArray(T, arrayInfo.child, len, tokens, options);
16471663
},
16481664
.String => |stringToken| {
16491665
if (arrayInfo.child != u8) return error.UnexpectedToken;
@@ -1659,6 +1675,15 @@ fn parseInternal(
16591675
else => return error.UnexpectedToken,
16601676
}
16611677
},
1678+
.Vector => |vecInfo| {
1679+
switch (token) {
1680+
.ArrayBegin => {
1681+
const len = @typeInfo(T).Vector.len;
1682+
return parseInternalArray(T, vecInfo.child, len, tokens, options);
1683+
},
1684+
else => return error.UnexpectedToken,
1685+
}
1686+
},
16621687
.Pointer => |ptrInfo| {
16631688
const allocator = options.allocator orelse return error.AllocatorRequired;
16641689
switch (ptrInfo.size) {
@@ -1804,6 +1829,13 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void {
18041829
parseFree(arrayInfo.child, v, options);
18051830
}
18061831
},
1832+
.Vector => |vecInfo| {
1833+
var i: usize = 0;
1834+
var v_len: usize = @typeInfo(@TypeOf(value)).Vector.len;
1835+
while (i < v_len) : (i += 1) {
1836+
parseFree(vecInfo.child, value[i], options);
1837+
}
1838+
},
18071839
.Pointer => |ptrInfo| {
18081840
const allocator = options.allocator orelse unreachable;
18091841
switch (ptrInfo.size) {

lib/std/json/test.zig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,6 +2550,25 @@ test "parse into double recursive union definition" {
25502550
try testing.expectEqual(@as(i64, 58), r.values.array[0].array[0].integer);
25512551
}
25522552

2553+
test "parse into vector" {
2554+
const options = ParseOptions{ .allocator = testing.allocator };
2555+
const T = struct {
2556+
vec_i32: @Vector(4, i32),
2557+
vec_f32: @Vector(2, f32),
2558+
};
2559+
var ts = TokenStream.init(
2560+
\\{
2561+
\\ "vec_f32": [1.5, 2.5],
2562+
\\ "vec_i32": [4, 5, 6, 7]
2563+
\\}
2564+
);
2565+
const r = try parse(T, &ts, options);
2566+
defer parseFree(T, r, options);
2567+
try testing.expectApproxEqAbs(@as(f32, 1.5), r.vec_f32[0], 0.0000001);
2568+
try testing.expectApproxEqAbs(@as(f32, 2.5), r.vec_f32[1], 0.0000001);
2569+
try testing.expectEqual(@Vector(4, i32){ 4, 5, 6, 7 }, r.vec_i32);
2570+
}
2571+
25532572
test "json.parser.dynamic" {
25542573
var p = Parser.init(testing.allocator, false);
25552574
defer p.deinit();

0 commit comments

Comments
 (0)