Browse Source

Allow for `union{T}` like types in `json.unmarshal`

gingerBill 3 years ago
parent
commit
14a3ddb9af
1 changed files with 61 additions and 54 deletions
  1. 61 54
      core/encoding/json/unmarshal.odin

+ 61 - 54
core/encoding/json/unmarshal.odin

@@ -1,6 +1,5 @@
 package json
 
-import "core:fmt"
 import "core:mem"
 import "core:math"
 import "core:reflect"
@@ -37,7 +36,6 @@ unmarshal_any :: proc(data: []byte, v: any, spec := DEFAULT_SPECIFICATION, alloc
 		return .Non_Pointer_Parameter
 	}
 	
-	
 	if !is_valid(data, spec, true) {
 		return .Invalid_Data
 	}
@@ -47,6 +45,8 @@ unmarshal_any :: proc(data: []byte, v: any, spec := DEFAULT_SPECIFICATION, alloc
 	if v.data == nil {
 		return .Invalid_Parameter
 	}
+	
+	context.allocator = p.allocator
 	return unmarsal_value(&p, data)
 }
 
@@ -64,11 +64,11 @@ unmarshal_string :: proc(data: string, ptr: ^$T, spec := DEFAULT_SPECIFICATION,
 assign_bool :: proc(val: any, b: bool) -> bool {
 	v := reflect.any_core(val)
 	switch dst in &v {
-	case bool: dst = auto_cast b
-	case b8:   dst = auto_cast b
-	case b16:  dst = auto_cast b
-	case b32:  dst = auto_cast b
-	case b64:  dst = auto_cast b
+	case bool: dst = bool(b)
+	case b8:   dst = b8  (b)
+	case b16:  dst = b16 (b)
+	case b32:  dst = b32 (b)
+	case b64:  dst = b64 (b)
 	case: return false
 	}
 	return true
@@ -77,35 +77,35 @@ assign_bool :: proc(val: any, b: bool) -> bool {
 assign_int :: proc(val: any, i: $T) -> bool {
 	v := reflect.any_core(val)
 	switch dst in &v {
-	case i8:      dst = auto_cast i
-	case i16:     dst = auto_cast i
-	case i16le:   dst = auto_cast i
-	case i16be:   dst = auto_cast i
-	case i32:     dst = auto_cast i
-	case i32le:   dst = auto_cast i
-	case i32be:   dst = auto_cast i
-	case i64:     dst = auto_cast i
-	case i64le:   dst = auto_cast i
-	case i64be:   dst = auto_cast i
-	case i128:    dst = auto_cast i
-	case i128le:  dst = auto_cast i
-	case i128be:  dst = auto_cast i
-	case u8:      dst = auto_cast i
-	case u16:     dst = auto_cast i
-	case u16le:   dst = auto_cast i
-	case u16be:   dst = auto_cast i
-	case u32:     dst = auto_cast i
-	case u32le:   dst = auto_cast i
-	case u32be:   dst = auto_cast i
-	case u64:     dst = auto_cast i
-	case u64le:   dst = auto_cast i
-	case u64be:   dst = auto_cast i
-	case u128:    dst = auto_cast i
-	case u128le:  dst = auto_cast i
-	case u128be:  dst = auto_cast i
-	case int:     dst = auto_cast i
-	case uint:    dst = auto_cast i
-	case uintptr: dst = auto_cast i
+	case i8:      dst = i8     (i)
+	case i16:     dst = i16    (i)
+	case i16le:   dst = i16le  (i)
+	case i16be:   dst = i16be  (i)
+	case i32:     dst = i32    (i)
+	case i32le:   dst = i32le  (i)
+	case i32be:   dst = i32be  (i)
+	case i64:     dst = i64    (i)
+	case i64le:   dst = i64le  (i)
+	case i64be:   dst = i64be  (i)
+	case i128:    dst = i128   (i)
+	case i128le:  dst = i128le (i)
+	case i128be:  dst = i128be (i)
+	case u8:      dst = u8     (i)
+	case u16:     dst = u16    (i)
+	case u16le:   dst = u16le  (i)
+	case u16be:   dst = u16be  (i)
+	case u32:     dst = u32    (i)
+	case u32le:   dst = u32le  (i)
+	case u32be:   dst = u32be  (i)
+	case u64:     dst = u64    (i)
+	case u64le:   dst = u64le  (i)
+	case u64be:   dst = u64be  (i)
+	case u128:    dst = u128   (i)
+	case u128le:  dst = u128le (i)
+	case u128be:  dst = u128be (i)
+	case int:     dst = int    (i)
+	case uint:    dst = uint   (i)
+	case uintptr: dst = uintptr(i)
 	case: return false
 	}
 	return true
@@ -114,15 +114,15 @@ assign_int :: proc(val: any, i: $T) -> bool {
 assign_float :: proc(val: any, i: $T) -> bool {
 	v := reflect.any_core(val)
 	switch dst in &v {
-	case f16:     dst = auto_cast i
-	case f16le:   dst = auto_cast i
-	case f16be:   dst = auto_cast i
-	case f32:     dst = auto_cast i
-	case f32le:   dst = auto_cast i
-	case f32be:   dst = auto_cast i
-	case f64:     dst = auto_cast i
-	case f64le:   dst = auto_cast i
-	case f64be:   dst = auto_cast i
+	case f16:     dst = f16  (i)
+	case f16le:   dst = f16le(i)
+	case f16be:   dst = f16be(i)
+	case f32:     dst = f32  (i)
+	case f32le:   dst = f32le(i)
+	case f32be:   dst = f32be(i)
+	case f64:     dst = f64  (i)
+	case f64le:   dst = f64le(i)
+	case f64be:   dst = f64be(i)
 	case: return false
 	}
 	return true
@@ -133,11 +133,24 @@ assign_float :: proc(val: any, i: $T) -> bool {
 @(private)
 unmarsal_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 !(u.maybe && reflect.is_pointer(variant)) {
+			tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
+			assign_int(tag, 1)
+		}
+	}
+	
+	
 	#partial switch token.kind {
 	case .Null:
-		ti := type_info_of(v.id)
 		mem.zero(v.data, ti.size)
 		advance_token(p)
 		return
@@ -175,7 +188,7 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
 	case .String:
 		advance_token(p)
 		str := unquote_string(token, p.spec, p.allocator) or_return
-		val := reflect.any_base(v)
+		val := any{v.data, ti.id}
 		switch dst in &val {
 		case string:
 			dst = str
@@ -191,7 +204,6 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
 		}
 		defer delete(str, p.allocator)
 		
-		ti := type_info_of(val.id)
 		#partial switch variant in ti.variant {
 		case reflect.Type_Info_Enum:
 			for name, i in variant.names {
@@ -280,7 +292,6 @@ unmarsal_expect_token :: proc(p: ^Parser, kind: Token_Kind, loc := #caller_locat
 
 @(private)
 unmarsal_object :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
-	original_val := v
 	UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token}
 	
 	assert(expect_token(p, .Open_Brace) == nil)
@@ -374,11 +385,7 @@ unmarsal_object :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
 		
 		map_backing_value := any{raw_data(elem_backing), t.value.id}
 		
-		pass := 0
-		
 		map_loop: for p.curr_token.kind != .Close_Brace {
-			defer pass += 1
-			
 			key, _ := parse_object_key(p, p.allocator)
 			unmarsal_expect_token(p, .Colon)