A user may define setter and/or getter properties.
import mir.ser.json; import mir.deser.json; import mir.conv: to; static struct S { @serdeIgnore string str; @safe pure: string a() const @property { return str; } void b(int s) @property { str = s.to!string; } } assert(S("str").serializeJson == `{"a":"str"}`); assert(`{"b":123}`.deserializeJson!S.str == "123");
Support for custom nullable types (types that has a bool property isNull, non-void property get returning payload and void property nullify that makes nullable type to null value)
1 import mir.ser.json; 2 import mir.deser.json; 3 4 static struct MyNullable 5 { 6 long value; 7 8 @safe pure nothrow @nogc: 9 10 @property 11 isNull() const 12 { 13 return value == 0; 14 } 15 16 @property 17 long get() const 18 { 19 return value; 20 } 21 22 @property 23 nullify() 24 { 25 value = 0; 26 } 27 28 auto opAssign(long value) 29 { 30 this.value = value; 31 } 32 } 33 34 static struct Foo 35 { 36 MyNullable my_nullable; 37 string field; 38 39 bool opEquals()(auto ref const(typeof(this)) rhs) const 40 { 41 if (my_nullable.isNull && rhs.my_nullable.isNull) 42 return field == rhs.field; 43 44 if (my_nullable.isNull != rhs.my_nullable.isNull) 45 return false; 46 47 return my_nullable == rhs.my_nullable && 48 field == rhs.field; 49 } 50 } 51 52 Foo foo; 53 foo.field = "it's a foo"; 54 55 assert (serializeJson(foo) == `{"my_nullable":null,"field":"it's a foo"}`); 56 57 foo.my_nullable = 200; 58 59 assert (deserializeJson!Foo(`{"my_nullable":200,"field":"it's a foo"}`) == Foo(MyNullable(200), "it's a foo")); 60 61 import mir.algebraic: Nullable; 62 63 static struct Bar 64 { 65 Nullable!long nullable; 66 string field; 67 68 bool opEquals()(auto ref const(typeof(this)) rhs) 69 { 70 if (nullable.isNull && rhs.nullable.isNull) 71 return field == rhs.field; 72 73 if (nullable.isNull != rhs.nullable.isNull) 74 return false; 75 76 return nullable == rhs.nullable && 77 field == rhs.field; 78 } 79 } 80 81 Bar bar; 82 bar.field = "it's a bar"; 83 84 assert (serializeJson(bar) == `{"nullable":null,"field":"it's a bar"}`); 85 86 bar.nullable = 777; 87 assert (deserializeJson!Bar(`{"nullable":777,"field":"it's a bar"}`) == Bar(Nullable!long(777), "it's a bar"));
import mir.ser.ion; import mir.ser.json; import mir.ion.stream; IonValueStream[string] map; map["num"] = IonValueStream(serializeIon(124)); map["str"] = IonValueStream(serializeIon("value")); auto json = map.serializeJson; assert(json == `{"str":"value","num":124}` || json == `{"num":124,"str":"value"}`);
Support for floating point nan and (partial) infinity
import mir.conv: to; import mir.ser.ion; import mir.ser.json; import mir.deser.json; import mir.ion.conv; static struct Foo { float f; bool opEquals()(auto ref const(typeof(this)) rhs) { return f != f && rhs.f != rhs.f || f == rhs.f; } } // test for Not a Number assert (serializeJson(Foo()) == `{"f":"nan"}`, serializeJson(Foo())); assert (serializeIon(Foo()).ion2json == `{"f":"nan"}`, serializeIon(Foo()).ion2json); assert (deserializeJson!Foo(`{"f":"nan"}`) == Foo(), deserializeJson!Foo(`{"f":"nan"}`).to!string); assert (serializeJson(Foo(1f/0f)) == `{"f":"+inf"}`); assert (serializeIon(Foo(1f/0f)).ion2json == `{"f":"+inf"}`); assert (deserializeJson!Foo(`{"f":"+inf"}`) == Foo( float.infinity)); assert (deserializeJson!Foo(`{"f":"-inf"}`) == Foo(-float.infinity)); assert (serializeJson(Foo(-1f/0f)) == `{"f":"-inf"}`); assert (serializeIon(Foo(-1f/0f)).ion2json == `{"f":"-inf"}`); assert (deserializeJson!Foo(`{"f":"-inf"}`) == Foo(-float.infinity));
import mir.ser.ion; import mir.ser.json; import mir.deser.json; import mir.ion.conv; static struct S { string foo; uint bar; } static immutable json = `{"foo":"str","bar":4}`; assert(serializeIon(S("str", 4)).ion2json == json); assert(serializeJson(S("str", 4)) == json); assert(deserializeJson!S(json) == S("str", 4));
Proxy for members
import mir.ser.json; import mir.deser.json; struct S { // const(char)[] doesn't reallocate ASDF data. @serdeProxy!(const(char)[]) uint bar; } auto json = `{"bar":"4"}`; assert(serializeJson(S(4)) == json); assert(deserializeJson!S(json) == S(4));
import mir.ser.json; import mir.deser.json; import mir.serde: serdeKeys; static struct S { @serdeKeys("b", "a") string s; } assert(`{"a":"d"}`.deserializeJson!S.serializeJson == `{"b":"d"}`);
import mir.ser.json; import mir.deser.json; import mir.serde: serdeKeys, serdeKeyOut; static struct S { @serdeKeys("a") @serdeKeyOut("s") string s; } assert(`{"a":"d"}`.deserializeJson!S.serializeJson == `{"s":"d"}`);
import mir.ser.json; import mir.deser.json; import std.exception: assertThrown; struct S { string field; } assert(`{"field":"val"}`.deserializeJson!S.field == "val"); // assertThrown(`{"other":"val"}`.deserializeJson!S);
import mir.ser.json; import mir.deser.json; static struct S { @serdeKeyOut("a") string s; } assert(`{"s":"d"}`.deserializeJson!S.serializeJson == `{"a":"d"}`);
import mir.ser.json; import mir.deser.json; import std.exception: assertThrown; static struct S { @serdeIgnore string s; } // assertThrown(`{"s":"d"}`.deserializeJson!S); assert(S("d").serializeJson == `{}`);
1 import mir.ser.json; 2 import mir.deser.json; 3 4 static struct Decor 5 { 6 int candles; // 0 7 float fluff = float.infinity; // inf 8 } 9 10 static struct Cake 11 { 12 @serdeIgnoreDefault string name = "Chocolate Cake"; 13 @serdeIgnoreDefault string nullStr; 14 @serdeIgnoreDefault string emptyStr = ""; 15 int slices = 8; 16 float flavor = 1; 17 @serdeIgnoreDefault 18 Decor dec = Decor(20); // { 20, inf } 19 } 20 21 assert(Cake("Normal Cake", "", null).serializeJson == `{"name":"Normal Cake","slices":8,"flavor":1.0}`); 22 auto cake = Cake.init; 23 cake.dec = Decor.init; 24 assert(cake.serializeJson == `{"slices":8,"flavor":1.0,"dec":{"candles":0,"fluff":"+inf"}}`); 25 assert(cake.dec.serializeJson == `{"candles":0,"fluff":"+inf"}`); 26 27 static struct A 28 { 29 @serdeIgnoreDefault 30 string str = "Banana"; 31 int i = 1; 32 } 33 assert(A.init.serializeJson == `{"i":1}`); 34 35 static struct S 36 { 37 @serdeIgnoreDefault 38 A a; 39 } 40 assert(S.init.serializeJson == `{}`); 41 assert(S(A("Berry")).serializeJson == `{"a":{"str":"Berry","i":1}}`); 42 43 static struct D 44 { 45 S s; 46 } 47 assert(D.init.serializeJson == `{"s":{}}`); 48 assert(D(S(A("Berry"))).serializeJson == `{"s":{"a":{"str":"Berry","i":1}}}`); 49 assert(D(S(A(null, 0))).serializeJson == `{"s":{"a":{"str":"","i":0}}}`); 50 51 static struct F 52 { 53 D d; 54 } 55 assert(F.init.serializeJson == `{"d":{"s":{}}}`);
import mir.ser.json; import mir.deser.json; import mir.serde: serdeIgnoreOut; static struct S { @serdeIgnoreOut string s; } assert(`{"s":"d"}`.deserializeJson!S.s == "d"); assert(S("d").serializeJson == `{}`);
import mir.ser.json; import mir.deser.json; static struct CustomType { int a; // can be part of a type as well (only omits on property keys) auto serdeIgnoreOut() const { return a < 0; } // and use custom serializer to serialize as int void serialize(S)(scope ref S serializer) scope const { import mir.ser : serializeValue; serializeValue(serializer, a); } } static struct S { @serdeIgnoreOutIf!`a < 0` int a; // b is not output if the serdeIgnoreOut property in its type evaluates to false. CustomType b; } assert(serializeJson(S(3, CustomType(2))) == `{"a":3,"b":2}`, serializeJson(S(3, CustomType(2)))); assert(serializeJson(S(-3, CustomType(-2))) == `{}`);
import mir.ser.json; import mir.deser.json; import std.uuid: UUID; static struct S { @serdeScoped @serdeProxy!string UUID id; } enum result = UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46"); assert(`{"id":"8AB3060E-2cba-4f23-b74c-b52db3bdfb46"}`.deserializeJson!S.id == result);
1 import mir.ser.json; 2 import mir.deser.json; 3 import mir.ion.value; 4 import mir.algebraic: Variant; 5 6 static struct ObjectA 7 { 8 string name; 9 } 10 static struct ObjectB 11 { 12 double value; 13 } 14 15 alias MyObject = Variant!(ObjectA, ObjectB); 16 17 static struct MyObjectArrayProxy 18 { 19 MyObject[] array; 20 21 this(inout(MyObject)[] array) @safe pure nothrow @nogc inout 22 { 23 this.array = array; 24 } 25 26 inout(T) opCast(T : MyObject[])() inout 27 { 28 return array; 29 } 30 31 void serialize(S)(scope ref S serializer) scope const 32 { 33 import mir.ser: serializeValue; 34 // mir.algebraic has builtin support for serialization. 35 // For other algebraic libraies one can use thier visitor handlers. 36 serializeValue(serializer, array); 37 } 38 39 /++ 40 Returns: error msg if any 41 +/ 42 @trusted pure scope 43 IonException deserializeFromIon(scope const char[][] symbolTable, scope IonDescribedValue value) 44 { 45 import mir.deser.ion: deserializeIon; 46 import mir.ion.exception; 47 foreach (IonErrorCode error, scope IonDescribedValue elem; value.get!IonList) 48 { 49 if (error) 50 return error.ionException; 51 array ~= "name" in elem.get!IonStruct.withSymbols(symbolTable) 52 ? MyObject(deserializeIon!ObjectA(symbolTable, elem)) 53 : MyObject(deserializeIon!ObjectB(symbolTable, elem)); 54 } 55 return null; 56 } 57 } 58 59 static struct SomeObject 60 { 61 @serdeProxy!MyObjectArrayProxy MyObject[] objects; 62 } 63 64 string data = q{{"objects":[{"name":"test"},{"value":1.5}]}}; 65 66 auto value = data.deserializeJson!SomeObject; 67 assert (value.serializeJson == data, value.serializeJson);
reflectSerde support
import mir.reflection: reflectSerde; static struct S { @reflectSerde enum s = "str"; } import mir.ser.text: serializeText; assert(S().serializeText == `{s:"str"}`);
serdeIgnoreUnexpectedKeys support
import mir.serde: serdeIgnoreUnexpectedKeys; @serdeIgnoreUnexpectedKeys static struct S { int i; } import mir.deser.text: deserializeText; assert(`{s:"str",i:4}`.deserializeText!S == S(4));
Iterable and serdeLikeList
import mir.deser.text: deserializeText; import mir.ser.text: serializeText; import mir.serde: serdeIgnoreOut, serdeLikeList, serdeProxy, serdeKeys; import std.array: Appender; static struct S { @serdeLikeList @serdeProxy!string // input element type of @serdeIgnoreOut @serdeKeys("strings") Appender!(string[]) stringsApp; //`put` method is used this(const(string)[] strings) { stringsApp.put(strings); } auto strings() const @property // Iterable { import mir.ndslice.topology: map; return stringsApp.data.map!((string s) => "_" ~ s); } } assert(S([`a`, `b`]).serializeText == `{strings:["_a","_b"]}`); import mir.test; `{strings:["a","b"]}`.deserializeText!S.stringsApp.data.should == [`a`, `b`]; @serdeLikeList @serdeProxy!string // input element type of static struct C { /// Used to make S deserializable Appender!(string[]) stringsApp; //`put` method is used alias stringsApp this; this(const(string)[] strings) { stringsApp.put(strings); } /// To make C iterable and serializable auto opIndex() const { return stringsApp.data; } } static struct S2 { static prop() @property { return "100"; }; } assert(S2().serializeText == `{prop:"100"}`, S2().serializeText); assert(C([`a`, `b`]).serializeText == `["a","b"]`); assert(`["a","b"]`.deserializeText!C.stringsApp.data == [`a`, `b`]);
serdeLikeStruct
1 import mir.test: should; 2 import mir.ser.text: serializeText; 3 import mir.deser.text: deserializeText; 4 import mir.serde: serdeLikeStruct, serdeProxy; 5 6 // opApply for serialization & and opIndexAssign for deserialization 7 static struct M 8 { 9 private int sum; 10 11 // opApply is used for serialization 12 int opApply(scope int delegate(scope const char[] key, ref const int val) pure @safe dg) const pure @safe 13 { 14 { int var = 1; if (auto r = dg("a", var)) return r; } 15 { int var = 2; if (auto r = dg("b", var)) return r; } 16 { int var = 3; if (auto r = dg("c", var)) return r; } 17 return 0; 18 } 19 20 // opIndexAssign for deserialization 21 void opIndexAssign(int val, string key) pure @safe 22 { 23 sum += val; 24 } 25 } 26 27 // attribute on member + opApply 28 static struct S 29 { 30 @serdeLikeStruct 31 @serdeProxy!int // for deserialization 32 M obj; 33 } 34 35 assert(S().serializeText == `{obj:{a:1,b:2,c:3}}`); 36 `{obj:{a:1,b:2,c:3}}`.deserializeText!S.obj.sum.should == 6; 37 38 // attribute on type + opApply 39 @serdeLikeStruct 40 @serdeProxy!int // for deserialization 41 static struct C 42 { 43 M obj; 44 alias obj this; 45 } 46 47 assert(C().serializeText == `{a:1,b:2,c:3}`); 48 assert(`{a:1,b:2,c:3}`.deserializeText!C.obj.sum == 6); 49 50 // byKeyValue 51 static struct D 52 { 53 static struct KeyValue 54 { 55 string key; 56 int value; 57 } 58 KeyValue[] byKeyValue = [KeyValue("a", 1), KeyValue("b", 2), KeyValue("c", 3)]; 59 } 60 61 // attribute on member + byKeyValue 62 static struct F 63 { 64 @serdeLikeStruct 65 D obj; 66 } 67 68 assert(F().serializeText == `{obj:{a:1,b:2,c:3}}`); 69 70 // attribute on type + byKeyValue 71 @serdeLikeStruct 72 static struct B 73 { 74 D obj; 75 alias obj this; 76 } 77 78 assert(B().serializeText == `{a:1,b:2,c:3}`);
import mir.ser.json; import mir.deser.json; import std.range; import std.algorithm; import std.conv; static struct S { @serdeTransformIn!"a += 2" @serdeTransformOut!(a =>"str".repeat.take(a).joiner("_").to!string) int a; } auto s = deserializeJson!S(`{"a":3}`); assert(s.a == 5); assert(serializeJson(s) == `{"a":"str_str_str_str_str"}`);
static struct Toto { import mir.ndslice.slice: Slice; Slice!(int*, 2) a; Slice!(int*, 1) b; this(int x) @safe pure nothrow { import mir.ndslice.topology: iota, repeat; import mir.ndslice.allocation: slice; a = [2, 3].iota!int.slice; b = repeat(x, [2]).slice; } } auto toto = Toto(5); import mir.ser.json: serializeJson; import mir.deser.json: deserializeJson; auto description = toto.serializeJson!Toto; assert(description == q{{"a":[[0,1,2],[3,4,5]],"b":[5,5]}}); assert(toto == description.deserializeJson!Toto);
static struct Toto { import mir.ndslice.slice: Slice; import mir.rc.array: RCI; Slice!(RCI!int, 2) a; Slice!(RCI!int, 1) b; this(int x) @safe pure nothrow @nogc { import mir.ndslice.topology: iota, repeat; import mir.ndslice.allocation: rcslice; a = [2, 3].iota!int.rcslice; b = repeat(x, [2]).rcslice; } } auto toto = Toto(5); import mir.ser.json: serializeJson; import mir.deser.json: deserializeJson; import mir.format: stringBuf; auto buffer = stringBuf; serializeJson(buffer, toto); auto description = buffer.data; assert(description == q{{"a":[[0,1,2],[3,4,5]],"b":[5,5]}}); assert(toto == description.deserializeJson!Toto);
User defined algebraic types deserialization supports any subset of the following types:
A StringMap has has priority over builtin associative arrays.
Serializations works with any algebraic types.
See_also: $(GMREF mir-core, mir,algebraic), $(GMREF mir-algorithm, mir,string_map)
import mir.string_map; import mir.deser.ion: deserializeIon; import mir.ion.conv: json2ion, ion2text; import mir.algebraic: Algebraic, This; static union Json_ { typeof(null) null_; bool boolean; long integer; immutable(char)[] string; double[] array; StringMap!This object; } alias MyJsonAlgebraic = Algebraic!Json_; auto json = `{"b" : true, "z" : null, "this" : {"c" : "str", "d" : [1, 2, 3, 4]}}`; auto binary = json.json2ion; auto value = binary.deserializeIon!MyJsonAlgebraic; auto object = value.get!(StringMap!MyJsonAlgebraic); assert(object["b"].get!bool == true); assert(object["z"].isNull); object = object["this"].get!(StringMap!MyJsonAlgebraic); assert(object["c"].get!string == "str"); assert(object["d"].get!(double[]) == [1.0, 2, 3, 4]);
import mir.algebraic_alias.json; import mir.ser.json: serializeJson; auto value = [JsonAlgebraic[].init.JsonAlgebraic, StringMap!JsonAlgebraic.init.JsonAlgebraic, string.init.JsonAlgebraic]; assert(value.serializeJson == `[[],{},""]`, value.serializeJson);
import mir.test; import mir.serde : serdeFallbackStruct; import mir.algebraic; import mir.deser.text; import mir.deser.json; @serdeFallbackStruct struct S { string path; } alias V = Variant!(string, S); static immutable res = [V("str"), V(S("root"))]; q{["str", {path: root}]}.deserializeText!(V[]).should == res; q{ [ "str" , { "path" : "root" } ] }.deserializeJson!(V[]).should == res;
Date serialization
import mir.date; import mir.ion.conv: ion2text; import mir.ser.ion: serializeIon; import mir.ser.json: serializeJson; import mir.ser.text: serializeText; assert(Date(2021, 4, 24).serializeIon.ion2text == `2021-04-24`); assert(Date(2021, 4, 24).serializeText == `2021-04-24`); assert(Date(2021, 4, 24).serializeJson == `"2021-04-24"`);
Timestamp and LOB support in algebraic types
import mir.algebraic; import mir.deser.ion: deserializeIon; import mir.ser.ion: serializeIon; import mir.lob; import mir.string_map; import mir.timestamp; static union Ion_ { typeof(null) null_; bool boolean; long integer; double float_; immutable(char)[] string; Blob blob; Clob clob; Timestamp timestamp; This[] array; StringMap!This object; } alias IonAlgebraic = Algebraic!Ion_; StringMap!IonAlgebraic map; map["ts"] = Timestamp(2021, 4, 24); map["clob"] = Clob("Some clob"); map["blob"] = Blob([0x32, 0x52]); assert(map.serializeIon.deserializeIon!(StringMap!IonAlgebraic) == map);
Phobos date-time serialization
import core.time : hnsecs, minutes; import mir.ion.conv: ion2text; import mir.ser.ion: serializeIon; import mir.ser.json: serializeJson; import mir.ser.text: serializeText; import mir.deser.ion: deserializeIon; import mir.deser.json: deserializeJson; import std.datetime.date : Date, DateTime; import std.datetime.systime : SysTime; import std.datetime.timezone : SimpleTimeZone; auto date = Date(2021, 4, 24); assert(date.serializeIon.ion2text == `2021-04-24`); assert(date.serializeText == `2021-04-24`); assert(date.serializeJson == `"2021-04-24"`); assert(`"2021-04-24"`.deserializeJson!Date == date); auto datetime = DateTime(1982, 4, 1, 20, 59, 22); assert(datetime.serializeIon.ion2text == `1982-04-01T20:59:22-00:00`); assert(datetime.serializeText == `1982-04-01T20:59:22-00:00`); assert(datetime.serializeJson == `"1982-04-01T20:59:22-00:00"`); assert(`"1982-04-01T20:59:22Z"`.deserializeJson!DateTime == datetime); auto dt = DateTime(1982, 4, 1, 20, 59, 22); auto tz = new immutable SimpleTimeZone(-330.minutes); auto st = SysTime(dt, 1234567.hnsecs, tz); assert(st.serializeIon.ion2text == `1982-04-01T20:59:22.1234567-05:30`); assert(st.serializeText == `1982-04-01T20:59:22.1234567-05:30`); assert(st.serializeJson == `"1982-04-01T20:59:22.1234567-05:30"`); assert(st.serializeIon.deserializeIon!SysTime == st); assert(`"1982-04-01T20:59:22.1234567-05:30"`.deserializeJson!SysTime == st);
Static array support
import mir.ser.json; import mir.deser.json; int[3] value = [1, 2, 3]; assert(`[1,2,3]`.deserializeJson!(int[3]) == value); assert(value.serializeJson == `[1,2,3]`);
ditto
import mir.ser.json; import mir.deser.json; static struct S { int v; } S[3] value = [S(1), S(2), S(3)]; auto text = `[{"v":1},{"v":2},{"v":3}]`; assert(text.deserializeJson!(S[3]) == value); assert(value.serializeJson == text);
auto json = q{{ "a": [ 0.0031 ], "b": [ 0.999475, 0.999425 ] }}; import mir.deser.json; static struct S { double[] a; void serdeUnexpectedKeyHandler(scope const(char)[] key) scope @safe pure nothrow @nogc { assert(key == "b"); } } auto value = json.deserializeJson!(double[][string]); auto partialStruct = json.deserializeJson!S;
auto json = q{{ "index": 0.9962125, "data": 0.0001 }}; import mir.deser.json; import mir.series; alias T = Observation!(double, double); auto value = json.deserializeJson!T; assert(value.index == 0.9962125); assert(value.data == 0.0001);
1 static class MyHugeRESTString 2 { 3 string s; 4 5 this(string s) @safe pure nothrow @nogc 6 { 7 this.s = s; 8 } 9 10 void serialize(S)(scope ref S serializer) scope const 11 { 12 auto state = serializer.stringBegin; 13 // putStringPart is usefull in the loop and with buffers 14 serializer.putStringPart(s); 15 serializer.putStringPart(" Another chunk."); 16 serializer.stringEnd(state); 17 } 18 @safe const scope pure nothrow @nogc: 19 20 bool opEquals(scope const typeof(this) rhs) 21 { 22 return s == rhs.s; 23 } 24 25 int opCmp(scope const typeof(this) rhs) 26 { 27 return __cmp(s, rhs.s); 28 } 29 30 override size_t toHash() 31 { 32 return hashOf(s); 33 } 34 } 35 36 import mir.algebraic: Algebraic, This; 37 import mir.string_map; 38 39 // Your JSON DOM Type 40 static union Json_ 41 { 42 typeof(null) null_; 43 bool boolean; 44 long integer; 45 double float_; 46 immutable(char)[] string; 47 MyHugeRESTString restString; 48 This[] array; 49 StringMap!This object; 50 } 51 alias Json = Algebraic!Json_; 52 53 /// ordered 54 StringMap!Json response; 55 response["type"] = Json("response"); 56 response["data"] = Json(new MyHugeRESTString("First chunk.")); 57 58 import mir.ion.conv: ion2text; 59 import mir.ser.ion; 60 import mir.ser.json; 61 import mir.ser.text; 62 63 assert(response.serializeJson == `{"type":"response","data":"First chunk. Another chunk."}`); 64 assert(response.serializeText == `{type:"response",data:"First chunk. Another chunk."}`); 65 assert(response.serializeIon.ion2text == `{type:"response",data:"First chunk. Another chunk."}`);
Float proxy for integer types
import mir.deser.json; static struct S { @serdeProxy!double long integralValue; } assert(`{"integralValue":1.23e+2}`.deserializeJson!S.integralValue == 123);
Annotated variant
import mir.algebraic; import mir.deser.json; import mir.deser.text; import mir.ser.json; import mir.ser.text; @serdeAlgebraicAnnotation("s1") static struct S1 { string key; } @serdeAlgebraicAnnotation("s2") static struct S2 { long key; } alias V = Variant!(S1, S2); auto v = [V(123), V("124")]; auto ion = `[s2::{key:123},s1::{key:"124"}]`; auto json = `[{"s2":{"key":123}},{"s1":{"key":"124"}}]`; assert(v.serializeText == ion); assert(ion.deserializeText!(V[2]) == v); assert(v.serializeJson == json); assert(json.deserializeJson!(V[2]) == v);
Annotated arrays
import mir.algebraic; import mir.deser.ion; import mir.ser.ion; import mir.ser.text; import mir.serde; @serdeAlgebraicAnnotation("annotation") @serdeProxy!(long[]) static struct St3 { long[] arr; alias arr this; } alias V = Variant!St3; assert(V(St3([123])).serializeText == `annotation::[123]`); assert(V(St3([123])).serializeIon.deserializeIon!V == St3([123]));
DRAFT