Commit 8f7b50e2c4
Changed files (3)
lib
lib/std/json/dynamic.zig
@@ -147,7 +147,19 @@ fn handleCompleteValue(stack: *Array, allocator: Allocator, source: anytype, val
// stack: [..., .object]
var object = &stack.items[stack.items.len - 1].object;
- try object.put(key, value);
+
+ const gop = try object.getOrPut(key);
+ if (gop.found_existing) {
+ switch (options.duplicate_field_behavior) {
+ .use_first => {},
+ .@"error" => return error.DuplicateField,
+ .use_last => {
+ gop.value_ptr.* = value;
+ },
+ }
+ } else {
+ gop.value_ptr.* = value;
+ }
// This is an invalid state to leave the stack in,
// so we have to process the next token before we return.
lib/std/json/dynamic_test.zig
@@ -181,6 +181,34 @@ test "escaped characters" {
try testing.expectEqualSlices(u8, obj.get("surrogatepair").?.string, "๐");
}
+test "Value with duplicate fields" {
+ var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena_allocator.deinit();
+
+ const doc =
+ \\{
+ \\ "abc": 0,
+ \\ "abc": 1
+ \\}
+ ;
+
+ try testing.expectError(error.DuplicateField, parseFromSliceLeaky(std.json.Value, arena_allocator.allocator(), doc, .{
+ .duplicate_field_behavior = .@"error",
+ }));
+
+ const first = try parseFromSliceLeaky(std.json.Value, arena_allocator.allocator(), doc, .{
+ .duplicate_field_behavior = .use_first,
+ });
+ try testing.expectEqual(@as(usize, 1), first.object.count());
+ try testing.expectEqual(@as(i64, 0), first.object.get("abc").?.integer);
+
+ const last = try parseFromSliceLeaky(std.json.Value, arena_allocator.allocator(), doc, .{
+ .duplicate_field_behavior = .use_last,
+ });
+ try testing.expectEqual(@as(usize, 1), last.object.count());
+ try testing.expectEqual(@as(i64, 1), last.object.get("abc").?.integer);
+}
+
test "Value.jsonStringify" {
var vals = [_]Value{
.{ .integer = 1 },
lib/std/json/test.zig
@@ -28,7 +28,9 @@ fn testLowLevelScanner(s: []const u8) !void {
}
}
fn testHighLevelDynamicParser(s: []const u8) !void {
- var parsed = try parseFromSlice(Value, testing.allocator, s, .{});
+ var parsed = try parseFromSlice(Value, testing.allocator, s, .{
+ .duplicate_field_behavior = .use_first,
+ });
defer parsed.deinit();
}