added: support for optionals in json encoder/decoder
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 12 Jun 2023 03:00:25 +0000 (22:00 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 12 Jun 2023 03:00:25 +0000 (22:00 -0500)
core/encoding/json/encoder.onyx
core/misc/any_utils.onyx
core/runtime/info/helper.onyx
tests/json_test
tests/json_test.onyx

index 60baaf1bcca942ff81f065a1cc2e1689ea894261..c596fe1e4929a33c6b3408a35ca6f269a3f576d6 100644 (file)
@@ -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));
+            }
+        }
     }
 }
index 4c18a626b71755f3d03803fa9accb7714aed88eb..b0564b3cbf77d75638deee631c93f66b08a7ed0f 100644 (file)
@@ -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
index d97bbf214b340e2005a67c396780e8212e6709c5..74fb82ae112f019137fb68660b87b14fee995d6c 100644 (file)
@@ -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;
index 29001aa44cccf2bdc08481b1a3099e0a3a79b572..2ac867d535d7e1db07861ab46b811f4af55fad68 100644 (file)
@@ -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}
index 403208384f77ad191a26a242abed4746ed06f53c..c471c0a70126d78a466d44ad66708044227d9c5e 100644 (file)
@@ -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");
 }