Pārlūkot izejas kodu

Merge pull request #3068 from laytan/json-unmarshal-union

encoding/json: try to unmarshal into union variants
Jeroen van Rijn 1 gadu atpakaļ
vecāks
revīzija
b59c80d6fd
1 mainītis faili ar 27 papildinājumiem un 10 dzēšanām
  1. 27 10
      core/encoding/json/unmarshal.odin

+ 27 - 10
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: