diff --git a/lib/std/json.zig b/lib/std/json.zig index 096bed8d06..ca7fb5ad20 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1389,6 +1389,11 @@ fn ParseInternalErrorImpl(comptime T: type, comptime inferred_types: []const typ UnescapeValidStringError || ParseInternalErrorImpl(arrayInfo.child, inferred_types ++ [_]type{T}); }, + .Vector => |vecInfo| { + return error{ UnexpectedEndOfJson, UnexpectedToken, LengthMismatch } || TokenStream.Error || + UnescapeValidStringError || + ParseInternalErrorImpl(vecInfo.child, inferred_types ++ [_]type{T}); + }, .Pointer => |ptrInfo| { var errors = error{AllocatorRequired} || std.mem.Allocator.Error; switch (ptrInfo.size) { @@ -1408,6 +1413,35 @@ fn ParseInternalErrorImpl(comptime T: type, comptime inferred_types: []const typ unreachable; } +fn parseInternalArray( + comptime T: type, + comptime Elt: type, + comptime arr_len: usize, + tokens: *TokenStream, + options: ParseOptions, +) ParseInternalError(T)!T { + var r: T = undefined; + var i: usize = 0; + var child_options = options; + child_options.allow_trailing_data = true; + errdefer { + // Without the r.len check `r[i]` is not allowed + if (arr_len > 0) while (true) : (i -= 1) { + parseFree(Elt, r[i], options); + if (i == 0) break; + }; + } + if (arr_len > 0) while (i < arr_len) : (i += 1) { + r[i] = try parse(Elt, tokens, child_options); + }; + const tok = (try tokens.next()) orelse return error.UnexpectedEndOfJson; + switch (tok) { + .ArrayEnd => {}, + else => return error.UnexpectedToken, + } + return r; +} + fn parseInternal( comptime T: type, token: Token, @@ -1624,26 +1658,8 @@ fn parseInternal( .Array => |arrayInfo| { switch (token) { .ArrayBegin => { - var r: T = undefined; - var i: usize = 0; - var child_options = options; - child_options.allow_trailing_data = true; - errdefer { - // Without the r.len check `r[i]` is not allowed - if (r.len > 0) while (true) : (i -= 1) { - parseFree(arrayInfo.child, r[i], options); - if (i == 0) break; - }; - } - while (i < r.len) : (i += 1) { - r[i] = try parse(arrayInfo.child, tokens, child_options); - } - const tok = (try tokens.next()) orelse return error.UnexpectedEndOfJson; - switch (tok) { - .ArrayEnd => {}, - else => return error.UnexpectedToken, - } - return r; + const len = @typeInfo(T).Array.len; + return parseInternalArray(T, arrayInfo.child, len, tokens, options); }, .String => |stringToken| { if (arrayInfo.child != u8) return error.UnexpectedToken; @@ -1659,6 +1675,15 @@ fn parseInternal( else => return error.UnexpectedToken, } }, + .Vector => |vecInfo| { + switch (token) { + .ArrayBegin => { + const len = @typeInfo(T).Vector.len; + return parseInternalArray(T, vecInfo.child, len, tokens, options); + }, + else => return error.UnexpectedToken, + } + }, .Pointer => |ptrInfo| { const allocator = options.allocator orelse return error.AllocatorRequired; switch (ptrInfo.size) { @@ -1804,6 +1829,13 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { parseFree(arrayInfo.child, v, options); } }, + .Vector => |vecInfo| { + var i: usize = 0; + var v_len: usize = @typeInfo(@TypeOf(value)).Vector.len; + while (i < v_len) : (i += 1) { + parseFree(vecInfo.child, value[i], options); + } + }, .Pointer => |ptrInfo| { const allocator = options.allocator orelse unreachable; switch (ptrInfo.size) { diff --git a/lib/std/json/test.zig b/lib/std/json/test.zig index ce4b4ea7e8..452341535b 100644 --- a/lib/std/json/test.zig +++ b/lib/std/json/test.zig @@ -2550,6 +2550,25 @@ test "parse into double recursive union definition" { try testing.expectEqual(@as(i64, 58), r.values.array[0].array[0].integer); } +test "parse into vector" { + const options = ParseOptions{ .allocator = testing.allocator }; + const T = struct { + vec_i32: @Vector(4, i32), + vec_f32: @Vector(2, f32), + }; + var ts = TokenStream.init( + \\{ + \\ "vec_f32": [1.5, 2.5], + \\ "vec_i32": [4, 5, 6, 7] + \\} + ); + const r = try parse(T, &ts, options); + defer parseFree(T, r, options); + try testing.expectApproxEqAbs(@as(f32, 1.5), r.vec_f32[0], 0.0000001); + try testing.expectApproxEqAbs(@as(f32, 2.5), r.vec_f32[1], 0.0000001); + try testing.expectEqual(@Vector(4, i32){ 4, 5, 6, 7 }, r.vec_i32); +} + test "json.parser.dynamic" { var p = Parser.init(testing.allocator, false); defer p.deinit();