aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authordaurnimator <quae@daurnimator.com>2020-05-18 02:51:02 +1000
committerAndrew Kelley <andrew@ziglang.org>2020-07-24 20:35:47 +0000
commit978a38ee40e13c3eed625f2df7b36be49fd049e0 (patch)
tree60596022f326a9f62e07618863ae6f3b668739aa /lib/std
parentd3ebd428650748e60db70dd2171cc044855814b1 (diff)
downloadzig-978a38ee40e13c3eed625f2df7b36be49fd049e0.tar.gz
zig-978a38ee40e13c3eed625f2df7b36be49fd049e0.zip
std: fix json parsing into unions
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/json.zig13
1 files changed, 12 insertions, 1 deletions
diff --git a/lib/std/json.zig b/lib/std/json.zig
index f1b91fc829..3a94ceec37 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -1418,7 +1418,10 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
if (unionInfo.tag_type) |_| {
// try each of the union fields until we find one that matches
inline for (unionInfo.fields) |u_field| {
- if (parseInternal(u_field.field_type, token, tokens, options)) |value| {
+ // take a copy of tokens so we can withhold mutations until success
+ var tokens_copy = tokens.*;
+ if (parseInternal(u_field.field_type, token, &tokens_copy, options)) |value| {
+ tokens.* = tokens_copy;
return @unionInit(T, u_field.name, value);
} else |err| {
// Bubble up error.OutOfMemory
@@ -1733,6 +1736,14 @@ test "parse into tagged union" {
};
testing.expectEqual(T{ .x = 42 }, try parse(T, &TokenStream.init("42"), ParseOptions{}));
}
+
+ { // needs to back out when first union member doesn't match
+ const T = union(enum) {
+ A: struct { x: u32 },
+ B: struct { y: u32 },
+ };
+ testing.expectEqual(T{ .B = .{.y = 42} }, try parse(T, &TokenStream.init("{\"y\":42}"), ParseOptions{}));
+ }
}
test "parseFree descends into tagged union" {