Commit 61236c2aa1

Janne Hellsten <jjhellst@gmail.com>
2023-04-25 23:52:17
std: @Vector support for std.json.parse
1 parent 5b9e528
Changed files (2)
lib
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();
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) {