std: @Vector support for std.json.parse

This commit is contained in:
Janne Hellsten
2023-04-26 00:52:17 +03:00
committed by GitHub
parent 5b9e528bc5
commit 61236c2aa1
2 changed files with 71 additions and 20 deletions

View File

@@ -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) {

View File

@@ -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();