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

This commit is contained in:
gingerBill
2021-09-25 18:05:35 +01:00
parent 6a271355a6
commit 14a3ddb9af

View File

@@ -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)