From 14a3ddb9af757b94fd8d3d33f4cb218d98b2aaa1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 25 Sep 2021 18:05:35 +0100 Subject: [PATCH] Allow for `union{T}` like types in `json.unmarshal` --- core/encoding/json/unmarshal.odin | 115 ++++++++++++++++-------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index d63d7415a..ac1ce9b06 100644 --- a/core/encoding/json/unmarshal.odin +++ b/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)