diff options
| author | Franz Höltermann <Francis_the_cat@gmx.de> | 2024-03-27 15:46:44 +0100 |
|---|---|---|
| committer | Franz Höltermann <Francis_the_cat@gmx.de> | 2024-03-27 15:46:44 +0100 |
| commit | a422aba5786080c9f176cfb0255f81d987b10a08 (patch) | |
| tree | 687d5363aeff0c529df94b75ba8948863604f394 /core/encoding/json | |
| parent | 92a5666c1cc6a5b76d984be4394b5daabdf6fc03 (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.odin | 50 |
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} |