| ... | ... | @@ -1571,6 +1571,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: |
| 1571 | 1571 | return error.DuplicateJSONField; |
| 1572 | 1572 | } else if (options.duplicate_field_behavior == .UseLast) { |
| 1573 | 1573 | parseFree(field.field_type, @field(r, field.name), options); |
| 1574 | fields_seen[i] = false; |
| 1574 | 1575 | } |
| 1575 | 1576 | } |
| 1576 | 1577 | if (field.is_comptime) { |
| ... | ... | @@ -1642,6 +1643,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: |
| 1642 | 1643 | switch (ptrInfo.size) { |
| 1643 | 1644 | .One => { |
| 1644 | 1645 | const r: T = try allocator.create(ptrInfo.child); |
| 1646 | errdefer allocator.destroy(r); |
| 1645 | 1647 | r.* = try parseInternal(ptrInfo.child, token, tokens, options); |
| 1646 | 1648 | return r; |
| 1647 | 1649 | }, |
| ... | ... | @@ -1988,6 +1990,24 @@ test "parse into struct with misc fields" { |
| 1988 | 1990 | try testing.expectEqual(T.Union{ .float = 100000 }, r.a_union); |
| 1989 | 1991 | } |
| 1990 | 1992 | |
| 1993 | test "parse into struct with duplicate field" { |
| 1994 | // allow allocator to detect double frees by keeping bucket in use |
| 1995 | const ballast = try testing.allocator.alloc(u64, 1); |
| 1996 | defer testing.allocator.free(ballast); |
| 1997 | |
| 1998 | const options = ParseOptions{ |
| 1999 | .allocator = testing.allocator, |
| 2000 | .duplicate_field_behavior = .UseLast, |
| 2001 | }; |
| 2002 | const str = "{ \"a\": 1, \"a\": 0.25 }"; |
| 2003 | |
| 2004 | const T1 = struct { a: *u64 }; |
| 2005 | testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options)); |
| 2006 | |
| 2007 | const T2 = struct { a: f64 }; |
| 2008 | testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options)); |
| 2009 | } |
| 2010 | |
| 1991 | 2011 | /// A non-stream JSON parser which constructs a tree of Value's. |
| 1992 | 2012 | pub const Parser = struct { |
| 1993 | 2013 | allocator: *Allocator, |