From cee87c22293ad78b5205eb12dc169fe7e347c1c7 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sun, 11 Jun 2023 22:00:25 -0500 Subject: [PATCH] added: support for optionals in json encoder/decoder --- core/encoding/json/encoder.onyx | 43 +++++++++++++++++++++++++++++++++ core/misc/any_utils.onyx | 2 +- core/runtime/info/helper.onyx | 8 ++++++ tests/json_test | 3 +++ tests/json_test.onyx | 18 +++++++++++++- 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/core/encoding/json/encoder.onyx b/core/encoding/json/encoder.onyx index 60baaf1b..c596fe1e 100644 --- a/core/encoding/json/encoder.onyx +++ b/core/encoding/json/encoder.onyx @@ -230,6 +230,20 @@ encode :: (w: ^io.Writer, data: any) -> Encoding_Error { io.write(w, "}"); } + case .Union { + if !union_constructed_from(data.type, Optional) { + return .Unsupported_Type; + } + + u := info->as_union(); + tag := *cast(&Optional(void).tag_enum) data.data; + if tag != .Some { + io.write(w, "null"); + } else { + encode(w, misc.any_member(data, u.variants[1].type, u.alignment)); + } + } + case #default { return .Unsupported_Type; } @@ -350,6 +364,20 @@ from_any :: (type: type_expr, in: rawptr, allocator := context.allocator) -> Val d_info := cast(^Type_Info_Distinct) t_info; return from_any(d_info.base_type, in); } + + case .Union { + if !union_constructed_from(type, Optional) { + return null_value(); + } + + u := t_info->as_union(); + tag := *cast(&Optional(void).tag_enum) in; + if tag != .Some { + return null_value(); + } else { + return from_any(u.variants[1].type, memory.ptr_add(in, u.alignment), allocator); + } + } } return null_value(); @@ -447,5 +475,20 @@ as_any :: (value: Value, type: type_expr, out: rawptr) { d_info := cast(^Type_Info_Distinct) t_info; to_any(value, d_info.base_type, out); } + + case .Union { + if !union_constructed_from(type, Optional) { + return; + } + + u_info := t_info->as_union(); + if value->is_null() { + *cast(& ? void) out = .{}; + return; + } else { + *cast(&Optional(void).tag_enum) out = .Some; + to_any(value, u_info.variants[1].type, memory.ptr_add(out, u_info.alignment)); + } + } } } diff --git a/core/misc/any_utils.onyx b/core/misc/any_utils.onyx index 4c18a626..b0564b3c 100644 --- a/core/misc/any_utils.onyx +++ b/core/misc/any_utils.onyx @@ -89,7 +89,7 @@ any_nested_selector :: (v: any, member_name: str) -> any { #doc """ """ any_member :: #match #locked { - macro (v: any, member_type: type_expr, member_offset: u32) -> any { + (v: any, member_type: type_expr, member_offset: u32) -> any { return any.{ cast([&] u8, v.data) + member_offset, member_type diff --git a/core/runtime/info/helper.onyx b/core/runtime/info/helper.onyx index d97bbf21..74fb82ae 100644 --- a/core/runtime/info/helper.onyx +++ b/core/runtime/info/helper.onyx @@ -261,6 +261,14 @@ struct_inherits :: (struct_type: type_expr, base_type: type_expr) -> bool { return first_member.used && first_member.type == base_type; } +union_constructed_from :: (union_type: type_expr, base_type: type_expr) -> bool { + union_info := get_type_info(union_type); + if union_info.kind != .Union do return false; + + return (cast(&Type_Info_Union) union_info).constructed_from == base_type; +} + + #operator == (t1: Type_Info_Function, t2: Type_Info_Function) -> bool { if t1.parameter_types.count != t2.parameter_types.count do return false; if t1.return_type != t2.return_type do return false; diff --git a/tests/json_test b/tests/json_test index 29001aa4..2ac867d5 100644 --- a/tests/json_test +++ b/tests/json_test @@ -4,3 +4,6 @@ {"test":"Wow!","working":123,"data":[1,2,3,4,5],"people":[{"name":"Joe"},{"name":"Bob"}],"other":[{"x":1},{"x":2}]} {"foo":{"data":5}} 🂡 +main.Union_Test { v1 = None, v2 = Some(123) } +{"v1":null,"v2":123} +{"v1":null,"v2":123} diff --git a/tests/json_test.onyx b/tests/json_test.onyx index 40320838..c471c0a7 100644 --- a/tests/json_test.onyx +++ b/tests/json_test.onyx @@ -42,7 +42,23 @@ main :: () { json.set(o, "foo", json.from_any(^.{data=5})); json.encode(^core.stdio.print_writer, o); - v := json.decode_with_error("""{ "key1": "\\uD83C\\uDCA1", "key2": "\\u264C" }"""); + v := json.decode_with_error("{ \"key1\": \"\\uD83C\\uDCA1\", \"key2\": \"\\u264C\" }"); core.print("\n"); core.println(v.root["key1"]->as_str()); + + + Union_Test :: struct { + v1: ? i32; + v2: ? i32; + } + + ut_json := json.decode_with_error("""{ "v1": null, "v2": 123 }"""); + ut: Union_Test; + json.as_any(ut_json.root, &ut); + core.println(ut); + + json.encode(&core.stdio.print_writer, ut_json.root); + core.print("\n"); + json.encode(&core.stdio.print_writer, ut); + core.print("\n"); } -- 2.25.1