authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-03-21 15:00:47+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-21 15:00:47+02:00
logcd3575b0f0c808f6c63a7174d9371f65691428eb
treec59761793250c2913479b91d3652c2ecfc1f5d9a
parent898e4473e8acf664d67474716bb9728ed601c5a0
parentc0789b4814989f2d91d3d2145d227dcdec3e2770
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14848 from r00ster91/json

std.json: fix 2 TODOs

1 files changed, 34 insertions(+), 30 deletions(-)

lib/std/json.zig+34-30
......@@ -1534,30 +1534,25 @@ fn parseInternal(
15341534 child_options.allow_trailing_data = true;
15351535 var found = false;
15361536 inline for (structInfo.fields, 0..) |field, i| {
1537 // TODO: using switches here segfault the compiler (#2727?)
1538 if ((stringToken.escapes == .None and mem.eql(u8, field.name, key_source_slice)) or (stringToken.escapes == .Some and (field.name.len == stringToken.decodedLength() and encodesTo(field.name, key_source_slice)))) {
1539 // if (switch (stringToken.escapes) {
1540 // .None => mem.eql(u8, field.name, key_source_slice),
1541 // .Some => (field.name.len == stringToken.decodedLength() and encodesTo(field.name, key_source_slice)),
1542 // }) {
1537 if (switch (stringToken.escapes) {
1538 .None => mem.eql(u8, field.name, key_source_slice),
1539 .Some => (field.name.len == stringToken.decodedLength() and encodesTo(field.name, key_source_slice)),
1540 }) {
15431541 if (fields_seen[i]) {
1544 // switch (options.duplicate_field_behavior) {
1545 // .UseFirst => {},
1546 // .Error => {},
1547 // .UseLast => {},
1548 // }
1549 if (options.duplicate_field_behavior == .UseFirst) {
1550 // unconditonally ignore value. for comptime fields, this skips check against default_value
1551 parseFree(field.type, try parse(field.type, tokens, child_options), child_options);
1552 found = true;
1553 break;
1554 } else if (options.duplicate_field_behavior == .Error) {
1555 return error.DuplicateJSONField;
1556 } else if (options.duplicate_field_behavior == .UseLast) {
1557 if (!field.is_comptime) {
1558 parseFree(field.type, @field(r, field.name), child_options);
1559 }
1560 fields_seen[i] = false;
1542 switch (options.duplicate_field_behavior) {
1543 .UseFirst => {
1544 // unconditonally ignore value. for comptime fields, this skips check against default_value
1545 parseFree(field.type, try parse(field.type, tokens, child_options), child_options);
1546 found = true;
1547 break;
1548 },
1549 .Error => return error.DuplicateJSONField,
1550 .UseLast => {
1551 if (!field.is_comptime) {
1552 parseFree(field.type, @field(r, field.name), child_options);
1553 }
1554 fields_seen[i] = false;
1555 },
15611556 }
15621557 }
15631558 if (field.is_comptime) {
......@@ -2355,10 +2350,13 @@ pub fn stringify(
23552350 return stringify(value.*, options, out_stream);
23562351 },
23572352 },
2358 // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
2359 .Slice => {
2360 if (ptr_info.child == u8 and options.string == .String and std.unicode.utf8ValidateSlice(value)) {
2361 try encodeJsonString(value, options, out_stream);
2353 .Many, .Slice => {
2354 if (ptr_info.size == .Many and ptr_info.sentinel == null)
2355 @compileError("unable to stringify type '" ++ @typeName(T) ++ "' without sentinel");
2356 const slice = if (ptr_info.size == .Many) mem.span(value) else value;
2357
2358 if (ptr_info.child == u8 and options.string == .String and std.unicode.utf8ValidateSlice(slice)) {
2359 try encodeJsonString(slice, options, out_stream);
23622360 return;
23632361 }
23642362
......@@ -2367,7 +2365,7 @@ pub fn stringify(
23672365 if (child_options.whitespace) |*whitespace| {
23682366 whitespace.indent_level += 1;
23692367 }
2370 for (value, 0..) |x, i| {
2368 for (slice, 0..) |x, i| {
23712369 if (i != 0) {
23722370 try out_stream.writeByte(',');
23732371 }
......@@ -2376,7 +2374,7 @@ pub fn stringify(
23762374 }
23772375 try stringify(x, child_options, out_stream);
23782376 }
2379 if (value.len != 0) {
2377 if (slice.len != 0) {
23802378 if (options.whitespace) |whitespace| {
23812379 try whitespace.outputIndent(out_stream);
23822380 }
......@@ -2531,6 +2529,12 @@ test "stringify string" {
25312529 try teststringify("\"\\/\"", "/", StringifyOptions{ .string = .{ .String = .{ .escape_solidus = true } } });
25322530}
25332531
2532test "stringify many-item sentinel-terminated string" {
2533 try teststringify("\"hello\"", @as([*:0]const u8, "hello"), StringifyOptions{});
2534 try teststringify("\"with\\nescapes\\r\"", @as([*:0]const u8, "with\nescapes\r"), StringifyOptions{ .string = .{ .String = .{ .escape_unicode = true } } });
2535 try teststringify("\"with unicode\\u0001\"", @as([*:0]const u8, "with unicode\u{1}"), StringifyOptions{ .string = .{ .String = .{ .escape_unicode = true } } });
2536}
2537
25342538test "stringify tagged unions" {
25352539 try teststringify("42", union(enum) {
25362540 Foo: u32,
......@@ -2717,7 +2721,7 @@ test "encodesTo" {
27172721 try testing.expectEqual(true, encodesTo("withąunicode😂", "with\\u0105unicode\\ud83d\\ude02"));
27182722}
27192723
2720test "issue 14600" {
2724test "deserializing string with escape sequence into sentinel slice" {
27212725 const json = "\"\\n\"";
27222726 var token_stream = std.json.TokenStream.init(json);
27232727 const options = ParseOptions{ .allocator = std.testing.allocator };