authorgravatar for marcus@ramse.seMarcus Ramse <marcus@ramse.se> 2023-03-08 16:04:57+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-03-21 15:01:45+02:00
log1e087d3a64e6b504524c32f72b22faffef78b41e
tree792f887aebef9f3e6ac6c1310a953b1e883ecf20
parentcd3575b0f0c808f6c63a7174d9371f65691428eb

std.json: support tuples


2 files changed, 91 insertions(+), 7 deletions(-)

lib/std/json.zig+41-7
......@@ -1511,6 +1511,34 @@ fn parseInternal(
15111511 }
15121512 },
15131513 .Struct => |structInfo| {
1514 if (structInfo.is_tuple) {
1515 switch (token) {
1516 .ArrayBegin => {},
1517 else => return error.UnexpectedToken,
1518 }
1519 var r: T = undefined;
1520 var child_options = options;
1521 child_options.allow_trailing_data = true;
1522 var fields_seen: usize = 0;
1523 errdefer {
1524 inline for (0..structInfo.fields.len) |i| {
1525 if (i < fields_seen) {
1526 parseFree(structInfo.fields[i].type, r[i], options);
1527 }
1528 }
1529 }
1530 inline for (0..structInfo.fields.len) |i| {
1531 r[i] = try parse(structInfo.fields[i].type, tokens, child_options);
1532 fields_seen = i + 1;
1533 }
1534 const tok = (try tokens.next()) orelse return error.UnexpectedEndOfJson;
1535 switch (tok) {
1536 .ArrayEnd => {},
1537 else => return error.UnexpectedToken,
1538 }
1539 return r;
1540 }
1541
15141542 switch (token) {
15151543 .ObjectBegin => {},
15161544 else => return error.UnexpectedToken,
......@@ -2290,7 +2318,7 @@ pub fn stringify(
22902318 return value.jsonStringify(options, out_stream);
22912319 }
22922320
2293 try out_stream.writeByte('{');
2321 try out_stream.writeByte(if (S.is_tuple) '[' else '{');
22942322 var field_output = false;
22952323 var child_options = options;
22962324 if (child_options.whitespace) |*child_whitespace| {
......@@ -2320,11 +2348,13 @@ pub fn stringify(
23202348 if (child_options.whitespace) |child_whitespace| {
23212349 try child_whitespace.outputIndent(out_stream);
23222350 }
2323 try encodeJsonString(Field.name, options, out_stream);
2324 try out_stream.writeByte(':');
2325 if (child_options.whitespace) |child_whitespace| {
2326 if (child_whitespace.separator) {
2327 try out_stream.writeByte(' ');
2351 if (!S.is_tuple) {
2352 try encodeJsonString(Field.name, options, out_stream);
2353 try out_stream.writeByte(':');
2354 if (child_options.whitespace) |child_whitespace| {
2355 if (child_whitespace.separator) {
2356 try out_stream.writeByte(' ');
2357 }
23282358 }
23292359 }
23302360 try stringify(@field(value, Field.name), child_options, out_stream);
......@@ -2335,7 +2365,7 @@ pub fn stringify(
23352365 try whitespace.outputIndent(out_stream);
23362366 }
23372367 }
2338 try out_stream.writeByte('}');
2368 try out_stream.writeByte(if (S.is_tuple) ']' else '}');
23392369 return;
23402370 },
23412371 .ErrorSet => return stringify(@as([]const u8, @errorName(value)), options, out_stream),
......@@ -2649,6 +2679,10 @@ test "stringify vector" {
26492679 try teststringify("[1,1]", @splat(2, @as(u32, 1)), StringifyOptions{});
26502680}
26512681
2682test "stringify tuple" {
2683 try teststringify("[\"foo\",42]", std.meta.Tuple(&.{ []const u8, usize }){ "foo", 42 }, StringifyOptions{});
2684}
2685
26522686fn teststringify(expected: []const u8, value: anytype, options: StringifyOptions) !void {
26532687 const ValidationWriter = struct {
26542688 const Self = @This();
lib/std/json/test.zig+50
......@@ -2459,6 +2459,56 @@ test "parse into struct ignoring unknown fields" {
24592459 try testing.expectEqualSlices(u8, "zig", r.language);
24602460}
24612461
2462test "parse into tuple" {
2463 const options = ParseOptions{ .allocator = testing.allocator };
2464 const Union = union(enum) {
2465 char: u8,
2466 float: f64,
2467 string: []const u8,
2468 };
2469 const T = std.meta.Tuple(&.{
2470 i64,
2471 f64,
2472 bool,
2473 []const u8,
2474 ?bool,
2475 struct {
2476 foo: i32,
2477 bar: []const u8,
2478 },
2479 std.meta.Tuple(&.{ u8, []const u8, u8 }),
2480 Union,
2481 });
2482 var ts = TokenStream.init(
2483 \\[
2484 \\ 420,
2485 \\ 3.14,
2486 \\ true,
2487 \\ "zig",
2488 \\ null,
2489 \\ {
2490 \\ "foo": 1,
2491 \\ "bar": "zero"
2492 \\ },
2493 \\ [4, "två", 42],
2494 \\ 12.34
2495 \\]
2496 );
2497 const r = try parse(T, &ts, options);
2498 defer parseFree(T, r, options);
2499 try testing.expectEqual(@as(i64, 420), r[0]);
2500 try testing.expectEqual(@as(f64, 3.14), r[1]);
2501 try testing.expectEqual(true, r[2]);
2502 try testing.expectEqualSlices(u8, "zig", r[3]);
2503 try testing.expectEqual(@as(?bool, null), r[4]);
2504 try testing.expectEqual(@as(i32, 1), r[5].foo);
2505 try testing.expectEqualSlices(u8, "zero", r[5].bar);
2506 try testing.expectEqual(@as(u8, 4), r[6][0]);
2507 try testing.expectEqualSlices(u8, "två", r[6][1]);
2508 try testing.expectEqual(@as(u8, 42), r[6][2]);
2509 try testing.expectEqual(Union{ .float = 12.34 }, r[7]);
2510}
2511
24622512const ParseIntoRecursiveUnionDefinitionValue = union(enum) {
24632513 integer: i64,
24642514 array: []const ParseIntoRecursiveUnionDefinitionValue,