aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2024-01-03 19:13:36 +0100
committerGitHub <noreply@github.com>2024-01-03 19:13:36 +0100
commitb59c80d6fd892b0408440e2858782a27c6b28cd1 (patch)
tree250a0d403c2dc888d548f035736eb4411da49d29
parent0cc72b536fe31d75ebb8b73dd3e541f08fff84c1 (diff)
parent8c10f4cdde2a796d2480703a16c8a34cfee5375f (diff)
Merge pull request #3068 from laytan/json-unmarshal-union
encoding/json: try to unmarshal into union variants
-rw-r--r--core/encoding/json/unmarshal.odin37
1 files changed, 27 insertions, 10 deletions
diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin
index 678f2dcfa..afcc43c0c 100644
--- a/core/encoding/json/unmarshal.odin
+++ b/core/encoding/json/unmarshal.odin
@@ -201,20 +201,37 @@ unmarshal_string_token :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.T
unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token}
token := p.curr_token
-
+
v := v
ti := reflect.type_info_base(type_info_of(v.id))
- // NOTE: If it's a union with only one variant, then treat it as that variant
- if u, ok := ti.variant.(reflect.Type_Info_Union); ok && len(u.variants) == 1 && token.kind != .Null {
- variant := u.variants[0]
- v.id = variant.id
- ti = reflect.type_info_base(variant)
- if !reflect.is_pointer_internally(variant) {
- tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
- assign_int(tag, 1)
+ if u, ok := ti.variant.(reflect.Type_Info_Union); ok && token.kind != .Null {
+ // NOTE: If it's a union with only one variant, then treat it as that variant
+ if len(u.variants) == 1 {
+ variant := u.variants[0]
+ v.id = variant.id
+ ti = reflect.type_info_base(variant)
+ if !reflect.is_pointer_internally(variant) {
+ tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
+ assign_int(tag, 1)
+ }
+ } else if v.id != Value {
+ for variant, i in u.variants {
+ variant_any := any{v.data, variant.id}
+ variant_p := p^
+ if err = unmarshal_value(&variant_p, variant_any); err == nil {
+ p^ = variant_p
+
+ raw_tag := i
+ if !u.no_nil { raw_tag += 1 }
+ tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
+ assign_int(tag, raw_tag)
+ return
+ }
+ }
+ return UNSUPPORTED_TYPE
}
}
-
+
switch &dst in v {
// Handle json.Value as an unknown type
case Value: