aboutsummaryrefslogtreecommitdiff
path: root/core/encoding/json
diff options
context:
space:
mode:
authorFranz Höltermann <Francis_the_cat@gmx.de>2024-03-27 15:46:44 +0100
committerFranz Höltermann <Francis_the_cat@gmx.de>2024-03-27 15:46:44 +0100
commita422aba5786080c9f176cfb0255f81d987b10a08 (patch)
tree687d5363aeff0c529df94b75ba8948863604f394 /core/encoding/json
parent92a5666c1cc6a5b76d984be4394b5daabdf6fc03 (diff)
Json: improved unmarshalling of `using _: T` fields.
`using _: T` fields will now have their members unmarshalled to their parent types reflecting the new behaviour of json.marshall. Example: ```go A :: struct { using _: B, } B :: struct { field: string, } data := `{"field": "Hello World"}` a: A json.unmarshal_string(data, &a) ```
Diffstat (limited to 'core/encoding/json')
-rw-r--r--core/encoding/json/unmarshal.odin50
1 files changed, 41 insertions, 9 deletions
diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin
index ba646b0b7..8c21098fb 100644
--- a/core/encoding/json/unmarshal.odin
+++ b/core/encoding/json/unmarshal.odin
@@ -370,13 +370,13 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
fields := reflect.struct_fields_zipped(ti.id)
- field_test :: #force_inline proc "contextless" (field_used: [^]byte, index: int) -> bool {
- prev_set := field_used[index/8] & byte(index&7) != 0
- field_used[index/8] |= byte(index&7)
+ field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool {
+ prev_set := field_used[offset/8] & byte(offset&7) != 0
+ field_used[offset/8] |= byte(offset&7)
return prev_set
}
- field_used_bytes := (len(fields)+7)/8
+ field_used_bytes := (reflect.size_of_typeid(ti.id)+7)/8
field_used := intrinsics.alloca(field_used_bytes, 1)
intrinsics.mem_zero(field_used, field_used_bytes)
@@ -399,13 +399,45 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
}
}
- if use_field_idx >= 0 {
- if field_test(field_used, use_field_idx) {
+ check_children_using_fields :: proc(key: string, parent: typeid) -> (
+ offset: uintptr,
+ type: ^reflect.Type_Info,
+ found: bool,
+ ) {
+ for field in reflect.struct_fields_zipped(parent) {
+ if field.is_using && field.name == "_" {
+ offset, type, found = check_children_using_fields(key, field.type.id)
+ if found {
+ offset += field.offset
+ return
+ }
+ }
+
+ if field.name == key {
+ offset = field.offset
+ type = field.type
+ found = true
+ return
+ }
+ }
+ return
+ }
+
+ offset: uintptr
+ type: ^reflect.Type_Info
+ field_found: bool = use_field_idx >= 0
+
+ if field_found {
+ offset = fields[use_field_idx].offset
+ type = fields[use_field_idx].type
+ } else {
+ offset, type, field_found = check_children_using_fields(key, ti.id)
+ }
+
+ if field_found {
+ if field_test(field_used, offset) {
return .Multiple_Use_Field
}
- offset := fields[use_field_idx].offset
- type := fields[use_field_idx].type
- name := fields[use_field_idx].name
field_ptr := rawptr(uintptr(v.data) + offset)
field := any{field_ptr, type.id}