Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

asdf.serialization

ASDF and JSON Serialization

For aggregate types the order of the (de)serialization is the folowing:
  1. All public fields of alias ? this that are not hidden by members of this (recursively).
  2. All public fields of this.
  3. All public properties of alias ? this that are not hidden by members of this (recursively).
  4. All public properties of this.
Publicly imports mir.serde from the mir-algorithm package.
Examples:
import asdf;
import std.bigint;
import std.datetime;
import mir.conv;

enum E : char
{
    a,
    b,
    c,
}

static class C
{
    private double _foo;
pure:
    this()
    {
        _foo = 4;
    }

    double foo() const @property
    {
        return _foo + 10;
    }

    void foo(double d) @property
    {
        _foo = d - 10;
    }
}

import mir.timestamp: Timestamp;

static struct S
{
    static int staticNotSeialised = 5;
    enum int enumsNotSeialised = 3;

    @serdeProxy!Timestamp
    DateTime time;

    C object;

    string[E] map;

    @serdeKeys("bar_common", "bar")
    string bar;
}

enum json = `{"time":"2016-03-04T00:00:00Z","object":{"foo":14.0},"map":{"a":"A"},"bar_common":"escaped chars = '\\', '\"', '\t', '\r', '\n'"}`;
auto value = S(
    DateTime(2016, 3, 4),
    new C,
    [E.a : "A"],
    "escaped chars = '\\', '\"', '\t', '\r', '\n'");
assert(serializeToJson(cast(const)value) == json, serializeToJson(cast(const)value)); // check serialization of const data
assert(serializeToAsdf(value).to!string == json, serializeToAsdf(value).to!string);
assert(deserialize!S(json).serializeToJson == json);
Examples:
finalizeSerialization method
import asdf;

static struct S
{
    string a;
    int b;

    void finalizeSerialization(Serializer)(ref Serializer serializer)
    {
        serializer.putKey("c");
        serializer.putValue(100);
    }
}
assert(S("bar", 3).serializeToJson == `{"a":"bar","b":3,"c":100}`);
Examples:
finalizeDeserialization method
import asdf;

static struct S
{
    string a;
    int b;

    @serdeIgnoreIn
    double sum;

    void finalizeDeserialization(Asdf data) pure
    {
        auto r = data["c", "d"];
        auto a = r["e"].get(0.0);
        auto b = r["g"].get(0.0);
        sum = a + b;
    }

    void serdeFinalize() pure
    {
        sum *= 2;
    }
}
assert(`{"a":"bar","b":3,"c":{"d":{"e":6,"g":7}}}`.deserialize!S == S("bar", 3, 26));
Examples:
A user may define setter and/or getter properties.
import asdf;
import mir.conv: to;

static struct S
{
    @serdeIgnore string str;
pure:
    string a() @property
    {
        return str;
    }

    void b(int s) @property
    {
        str = s.to!string;
    }
}

assert(S("str").serializeToJson == `{"a":"str"}`);
assert(`{"b":123}`.deserialize!S.str == "123");
Examples:
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)
import asdf;

static struct MyNullable
{
    long value;

    @property
    isNull() const
    {
        return value == 0;
    }

    @property
    get()
    {
        return value;
    }

    @property
    nullify()
    {
        value = 0;
    }

    auto opAssign(long value)
    {
        this.value = value;
    }
}

static struct Foo
{
    MyNullable my_nullable;
    string field;

    bool opEquals()(auto ref const(typeof(this)) rhs)
    {
        if (my_nullable.isNull && rhs.my_nullable.isNull)
            return field == rhs.field;

        if (my_nullable.isNull != rhs.my_nullable.isNull)
            return false;

        return my_nullable == rhs.my_nullable &&
                     field == rhs.field;
    }
}

Foo foo;
foo.field = "it's a foo";

assert (serializeToJson(foo) == `{"my_nullable":null,"field":"it's a foo"}`);

foo.my_nullable = 200;

assert (deserialize!Foo(`{"my_nullable":200,"field":"it's a foo"}`) == Foo(MyNullable(200), "it's a foo"));

import std.typecons : Nullable;

static struct Bar
{
    Nullable!long nullable;
    string field;

    bool opEquals()(auto ref const(typeof(this)) rhs)
    {
        if (nullable.isNull && rhs.nullable.isNull)
            return field == rhs.field;

        if (nullable.isNull != rhs.nullable.isNull)
            return false;

        return nullable == rhs.nullable &&
                     field == rhs.field;
    }
}

Bar bar;
bar.field = "it's a bar";

assert (serializeToJson(bar) == `{"nullable":null,"field":"it's a bar"}`);

bar.nullable = 777;
assert (deserialize!Bar(`{"nullable":777,"field":"it's a bar"}`) == Bar(Nullable!long(777), "it's a bar"));
Examples:
Support for floating point nan and (partial) infinity
import mir.conv: to;
import asdf;

static struct Foo
{
    float f;

    bool opEquals()(auto ref const(typeof(this)) rhs)
    {
        import std.math : isNaN, approxEqual;

        if (f.isNaN && rhs.f.isNaN)
            return true;

        return approxEqual(f, rhs.f);
    }
}

// test for Not a Number
assert (serializeToJson(Foo()).to!string == `{"f":"nan"}`);
assert (serializeToAsdf(Foo()).to!string == `{"f":"nan"}`);

assert (deserialize!Foo(`{"f":null}`)  == Foo());
assert (deserialize!Foo(`{"f":"nan"}`) == Foo());

assert (serializeToJson(Foo(1f/0f)).to!string == `{"f":"inf"}`);
assert (serializeToAsdf(Foo(1f/0f)).to!string == `{"f":"inf"}`);
assert (deserialize!Foo(`{"f":"inf"}`)  == Foo( float.infinity));
assert (deserialize!Foo(`{"f":"-inf"}`) == Foo(-float.infinity));

assert (serializeToJson(Foo(-1f/0f)).to!string == `{"f":"-inf"}`);
assert (serializeToAsdf(Foo(-1f/0f)).to!string == `{"f":"-inf"}`);
assert (deserialize!Foo(`{"f":"-inf"}`) == Foo(-float.infinity));
string serializeToJson(V)(auto ref V value);
JSON serialization function.
Examples:
import asdf;

struct S
{
    string foo;
    uint bar;
}

assert(serializeToJson(S("str", 4)) == `{"foo":"str","bar":4}`);
string serializeToJsonPretty(string sep = "\x09", V)(auto ref V value);
JSON serialization function with pretty formatting.
Examples:
import asdf;

static struct S { int a; }
assert(S(4).serializeToJsonPretty == "{\n\t\"a\": 4\n}");
void serializeToJsonPretty(string sep = "\x09", V, O)(auto ref V value, ref O output)
if (isOutputRange!(O, const(char)[]));
JSON serialization function with pretty formatting and custom output range.
Asdf serializeToAsdf(V)(auto ref V value, size_t initialLength = 32);
ASDF serialization function
Examples:
import asdf;
import mir.conv: to;

struct S
{
    string foo;
    uint bar;
}

assert(serializeToAsdf(S("str", 4)).to!string == `{"foo":"str","bar":4}`);
V deserialize(V)(Asdf data);

V deserialize(V)(in char[] str);
Deserialization function
Examples:
struct S
{
    string foo;
    uint bar;
}

assert(deserialize!S(`{"foo":"str","bar":4}`) == S("str", 4));
Examples:
Proxy for members
struct S
{
    // const(char)[] doesn't reallocate ASDF data.
    @serdeProxy!(const(char)[])
    uint bar;
}

auto json = `{"bar":"4"}`;
assert(serializeToJson(S(4)) == json);
assert(deserialize!S(json) == S(4));
struct JsonSerializer(string sep, Dg);
JSON serialization back-end
JsonBuffer!Dg sink;
JSON string buffer
this(Dg sink);
uint structBegin(size_t length = 0);

void structEnd(uint state);

uint listBegin(size_t length = 0);

void listEnd(uint state);

void putEscapedKey(in char[] key);

void putKey(in char[] key);

void putNumberValue(Num)(Num num, FormatSpec!char fmt = FormatSpec!char.init);

void putValue(typeof(null));

void putValue(bool b);

void putValue(in char[] str);

void putValue(Num)(Num num)
if (isNumeric!Num && !is(Num == enum));

void elemBegin();

void flush();
Serialization primitives
auto jsonSerializer(string sep = "", Dg)(scope Dg sink);
Creates JSON serialization back-end. Use sep equal to "\t" or " " for pretty formatting.
Examples:
import asdf;

import std.array;
import std.bigint;
import std.format: singleSpec;

auto app = appender!string;
auto ser = jsonSerializer(&app.put!(const(char)[]));
auto state0 = ser.structBegin;

    ser.putEscapedKey("null");
    ser.putValue(null);

    ser.putEscapedKey("array");
    auto state1 = ser.listBegin();
        ser.elemBegin; ser.putValue(null);
        ser.elemBegin; ser.putValue(123);
        ser.elemBegin; ser.putNumberValue(12300000.123, singleSpec("%.10e"));
        ser.elemBegin; ser.putValue("\t");
        ser.elemBegin; ser.putValue("\r");
        ser.elemBegin; ser.putValue("\n");
        ser.elemBegin; ser.putNumberValue(BigInt("1234567890"));
    ser.listEnd(state1);

ser.structEnd(state0);
ser.flush;

assert(app.data == `{"null":null,"array":[null,123,1.2300000123e+07,"\t","\r","\n",1234567890]}`);
struct AsdfSerializer;
ASDF serialization back-end
OutputArray app;
Output buffer
pure size_t structBegin(size_t length = 0);

pure void structEnd(size_t state);

pure size_t listBegin(size_t length = 0);

pure void listEnd(size_t state);

alias putEscapedKey = putKey;

pure void putKey(in char[] key);

pure void putNumberValue(Num)(Num num, FormatSpec!char fmt = FormatSpec!char.init);

pure void putValue(typeof(null));

pure void putValue(bool b);

pure void putValue(in char[] str);

void putValue(Num)(Num num)
if (isNumeric!Num && !is(Num == enum));
Serialization primitives
void putValue(Num)(const Num value)
if (isNumeric!Num && !is(Num == enum));

static pure void elemBegin();

static pure void flush();
auto asdfSerializer(size_t initialLength = 32);
Create ASDF serialization back-end
Examples:
import asdf;
import mir.conv: to;
import std.bigint;
import std.format: singleSpec;

auto ser = asdfSerializer();
auto state0 = ser.structBegin;

    ser.putEscapedKey("null");
    ser.putValue(null);

    ser.putKey("array");
    auto state1 = ser.listBegin();
        ser.elemBegin; ser.putValue(null);
        ser.elemBegin; ser.putValue(123);
        ser.elemBegin; ser.putNumberValue(12300000.123, singleSpec("%.10e"));
        ser.elemBegin; ser.putValue("\t");
        ser.elemBegin; ser.putValue("\r");
        ser.elemBegin; ser.putValue("\n");
        ser.elemBegin; ser.putNumberValue(BigInt("1234567890"));
    ser.listEnd(state1);

ser.structEnd(state0);

assert(ser.app.result.to!string == `{"null":null,"array":[null,123,1.2300000123e+07,"\t","\r","\n",1234567890]}`);
void serializeValue(S)(ref S serializer, typeof(null));
null value serialization
Examples:
import asdf;

assert(serializeToJson(null) == `null`);
void serializeValue(S, V)(ref S serializer, in V value, FormatSpec!char fmt = FormatSpec!char.init)
if (isNumeric!V && !is(V == enum) || is(V == BigInt));
Number serialization
Examples:
import std.bigint;

assert(serializeToJson(BigInt(123)) == `123`);
assert(serializeToJson(2.40f) == `2.4`);
assert(serializeToJson(float.nan) == `"nan"`);
assert(serializeToJson(float.infinity) == `"inf"`);
assert(serializeToJson(-float.infinity) == `"-inf"`);
void serializeValue(S, V)(ref S serializer, const V value)
if (is(V == bool) && !is(V == enum));
Boolean serialization
void serializeValue(S, V : char)(ref S serializer, const V value)
if (is(V == char) && !is(V == enum));
Char serialization
Examples:
assert(serializeToJson(true) == `true`);
void serializeValue(S, V)(ref S serializer, in V value)
if (is(V == enum));
Enum serialization
Examples:
enum Key { @serdeKeys("FOO", "foo") foo }
assert(serializeToJson(Key.foo) == `"FOO"`);
void serializeValue(S)(ref S serializer, in char[] value);
String serialization
Examples:
assert(serializeToJson("\t \" \\") == `"\t \" \\"`);
void serializeValue(S, T)(ref S serializer, T[] value)
if (!isSomeChar!T);
Array serialization
void serializeValue(S, R)(ref S serializer, R value)
if (isInputRange!R && !isSomeChar!(ElementType!R) && !isDynamicArray!R && !isNullable!R);
Input range serialization
Examples:
input range serialization
import std.algorithm : filter;

struct Foo
{
    int i;
}

auto ar = [Foo(1), Foo(3), Foo(4), Foo(17)];

auto filtered1 = ar.filter!"a.i & 1";
auto filtered2 = ar.filter!"!(a.i & 1)";

assert(serializeToJson(filtered1) == `[{"i":1},{"i":3},{"i":17}]`);
assert(serializeToJson(filtered2) == `[{"i":4}]`);
Examples:
uint[2] ar = [1, 2];
assert(serializeToJson(ar) == `[1,2]`);
assert(serializeToJson(ar[]) == `[1,2]`);
assert(serializeToJson(ar[0 .. 0]) == `[]`);
assert(serializeToJson((uint[]).init) == `null`);
void serializeValue(S, T)(ref S serializer, auto ref T[string] value);
String-value associative array serialization
Examples:
uint[string] ar = ["a" : 1];
assert(serializeToJson(ar) == `{"a":1}`);
ar.remove("a");
assert(serializeToJson(ar) == `{}`);
assert(serializeToJson((uint[string]).init) == `null`);
void serializeValue(S, V : const(T[K]), T, K)(ref S serializer, V value)
if (is(K == enum));
Enumeration-value associative array serialization
Examples:
enum E { a, b }
uint[E] ar = [E.a : 1];
assert(serializeToJson(ar) == `{"a":1}`);
ar.remove(E.a);
assert(serializeToJson(ar) == `{}`);
assert(serializeToJson((uint[string]).init) == `null`);
void serializeValue(S, V : const(T[K]), T, K)(ref S serializer, V value)
if (isIntegral!K && !is(K == enum));
integral typed value associative array serialization
Examples:
uint[short] ar = [256 : 1];
assert(serializeToJson(ar) == `{"256":1}`);
ar.remove(256);
assert(serializeToJson(ar) == `{}`);
assert(serializeToJson((uint[string]).init) == `null`);
assert(deserialize!(uint[short])(`{"256":1}`) == cast(uint[short]) [256 : 1]);
void serializeValue(S, N)(ref S serializer, auto ref N value)
if (isNullable!N);
Nullable type serialization
Examples:
import std.typecons;

struct Nested
{
    float f;
}

struct T
{
    string str;
    Nullable!Nested nested;
}

T t;
assert(t.serializeToJson == `{"str":null,"nested":null}`);
t.str = "txt";
t.nested = Nested(123);
assert(t.serializeToJson == `{"str":"txt","nested":{"f":123.0}}`);
void serializeValue(S, V)(ref S serializer, auto ref V value)
if (!isNullable!V && isAggregateType!V && !is(V : BigInt) && !isInputRange!V);
Struct and class type serialization
Examples:
Alias this support
struct S
{
    int u;
}

struct C
{
    int b;
    S s;
    alias s this; 
}

assert(C(4, S(3)).serializeToJson == `{"u":3,"b":4}`);
Examples:
Custom serialize
import mir.conv: to;

struct S
{
    void serialize(S)(ref S serializer) const
    {
        auto state = serializer.structBegin;
        serializer.putEscapedKey("foo");
        serializer.putValue("bar");
        serializer.structEnd(state);
    }
}
enum json = `{"foo":"bar"}`;
assert(serializeToJson(S()) == json);
assert(serializeToAsdf(S()).to!string == json);
Examples:
mir.algebraic support.
import mir.algebraic: Variant, Nullable, This;
alias V = Nullable!(double, string, This[], This[string]);
V v;
assert(v.serializeToJson == "null", v.serializeToJson);
v = [V(2), V("str"), V(["key":V(1.0)])];
assert(v.serializeToJson == `[2.0,"str",{"key":1.0}]`);
Examples:
mir.algebraic with manual serialization.
import asdf.asdf;

static struct Response
{
    import mir.algebraic: TaggedVariant;

    alias Union = TaggedVariant!(
        ["double_", "string", "array", "table"],
        double,
        string,
        Response[],
        Response[string],
    );

    Union data;
    alias Tag = Union.Kind;
    // propogates opEquals, opAssign, and other primitives
    alias data this;

    static foreach (T; Union.AllowedTypes)
        this(T v) @safe pure nothrow @nogc { data = v; }

    void serialize(S)(ref S serializer) const
    {
        import asdf: serializeValue;
        import mir.algebraic: visit;

        auto o = serializer.structBegin();
        serializer.putKey("tag");
        serializer.serializeValue(kind);
        serializer.putKey("data");
        data.visit!(
            (double v) => serializer.serializeValue(v), // specialization for double if required
            (const Response[string] v) => serializer.serializeValue(cast(const(Response)[string])v),
            (v) => serializer.serializeValue(v),
        );
        serializer.structEnd(o);
    }

    SerdeException deserializeFromAsdf(Asdf asdfData)
    {
        import asdf : deserializeValue;
        import std.traits : EnumMembers;

        Tag tag;
        if (auto e = asdfData["tag"].deserializeValue(tag))
            return e;
        final switch (tag)
        {
            foreach (m; EnumMembers!Tag)
            {
                case m: {
                    alias T = Union.AllowedTypes[m];
                    data = T.init;
                    if (auto e = asdfData["data"].deserializeValue(data.trustedGet!T))
                        return e;
                    break;
                }
            }
        }
        return null;
    }
}

Response v = 3.0;
assert(v.kind == Response.Tag.double_);
v = "str";
assert(v == "str");

import asdf;
assert(v.serializeToJson == `{"tag":"string","data":"str"}`);
v = Response.init;
v = `{"tag":"array","data":[{"tag":"string","data":"S"}]}`.deserialize!Response;
assert(v.kind == Response.Tag.array);
assert(v.get!(Response[])[0] == "S");
SerdeException deserializeValue(T : typeof(null))(Asdf data, T);
Deserialize null value
Examples:
assert(deserializeValue(serializeToAsdf(null), null) is null);
pure @safe SerdeException deserializeValue(T : bool)(Asdf data, ref T value);
Deserialize boolean value
Examples:
assert(deserialize!bool(serializeToAsdf(true)));
assert(deserialize!bool(serializeToJson(true)));
SerdeException deserializeValue(V)(Asdf data, ref V value)
if (isNumeric!V && !is(V == enum));
Deserialize numeric value.

Special deserialisation string values

"+NAN"
"+NaN"
"+nan"
"-NAN"
"-NaN"
"-nan"
"NAN"
"NaN"
"nan"
"+INF"
"+Inf"
"+inf"
"-INF"
"-Inf"
"-inf"
"INF"
"Inf"
"inf"

Examples:
import std.bigint;

assert(deserialize!ulong (serializeToAsdf(20)) == ulong (20));
assert(deserialize!ulong (serializeToJson(20)) == ulong (20));
assert(deserialize!double(serializeToAsdf(20)) == double(20));
assert(deserialize!double(serializeToJson(20)) == double(20));
assert(deserialize!BigInt(serializeToAsdf(20)) == BigInt(20));
assert(deserialize!BigInt(serializeToJson(20)) == BigInt(20));

assert(deserialize!float (serializeToJson ("2.40")) == float (2.40));
assert(deserialize!double(serializeToJson ("2.40")) == double(2.40));
assert(deserialize!double(serializeToAsdf("-2.40")) == double(-2.40));

import std.math : isNaN, isInfinity;
assert(deserialize!float (serializeToJson  ("+NaN")).isNaN);
assert(deserialize!float (serializeToJson  ("INF")).isInfinity);
assert(deserialize!float (serializeToJson ("-inf")).isInfinity);
SerdeException deserializeValue(V)(Asdf data, ref V value)
if (is(V == enum));
Deserialize enum value
Examples:
@serdeIgnoreCase enum Key { foo }
assert(deserialize!Key(`"FOO"`) == Key.foo);
assert(deserialize!Key(serializeToAsdf("foo")) == Key.foo);
SerdeException deserializeScopedString(V : const(char)[])(Asdf data, ref V value);
Deserializes scoped string value. This function does not allocate a new string and just make a raw cast of ASDF data.
SerdeException deserializeValue(V)(Asdf data, ref V value)
if (is(V : const(char)[]) && !isAggregateType!V && !is(V == enum) && !isNullable!V);
Deserializes string value. This function allocates new string.
Examples:
String enums supports only enum keys
enum SimpleEnum : string
{
    @serdeKeys("se1", "se1value")
    se1 = "se1value",

    @serdeKeys("se2", "se2value")
    se2 = "se2value",

    @serdeKeys("se3", "se3value")
    se3 = "se3value",
}

struct Simple
{
    SimpleEnum en;
    SimpleEnum ex;
}

Simple simple = `{"en":"se2", "ex":"se3value"}`.deserialize!Simple;
assert(simple.en == SimpleEnum.se2);
assert(simple.ex == SimpleEnum.se3);
Examples:
issue #115
import asdf;
import std.typecons;

struct Example
{
    @serdeOptional
    Nullable!string field1;
}

assert(`{}`.deserialize!Example == Example());
assert(Example().serializeToJson == `{"field1":null}`);
Examples:
assert(deserialize!string(serializeToJson(null)) is null);
assert(deserialize!string(serializeToAsdf(null)) is null);
assert(deserialize!string(serializeToJson("\tbar")) == "\tbar");
assert(deserialize!string(serializeToAsdf("\"bar")) == "\"bar");
SerdeException deserializeValue(V)(Asdf data, ref V value)
if (is(V == char) && !is(V == enum));
Deserialize single char
Examples:
assert(deserialize!char(`"a"`) == 'a');
assert(deserialize!byte(`-4`) == -4); // regression control
SerdeException deserializeValue(V : T[], T)(Asdf data, ref V value)
if (!isSomeChar!T && !isStaticArray!V);
Deserialize array
Examples:
assert(deserialize!(int[])(serializeToJson(null)) is null);
assert(deserialize!(int[])(serializeToAsdf(null)) is null);
assert(deserialize!(int[])(serializeToJson([1, 3, 4])) == [1, 3, 4]);
assert(deserialize!(int[])(serializeToAsdf([1, 3, 4])) == [1, 3, 4]);
SerdeException deserializeValue(V : T[N], T, size_t N)(Asdf data, ref V value);
Deserialize static array
Examples:
assert(deserialize!(int[4])(serializeToJson(null)) == [0, 0, 0, 0]);
assert(deserialize!(int[4])(serializeToAsdf(null)) == [0, 0, 0, 0]);
assert(deserialize!(int[4])(serializeToJson([1, 3, 4])) == [1, 3, 4, 0]);
assert(deserialize!(int[4])(serializeToAsdf([1, 3, 4])) == [1, 3, 4, 0]);
assert(deserialize!(int[2])(serializeToJson([1, 3, 4])) == [1, 3]);
assert(deserialize!(int[2])(serializeToAsdf([1, 3, 4])) == [1, 3]);

assert(deserialize!(char[2])(serializeToAsdf(['a','b'])) == ['a','b']);
assert(deserialize!(char[2])(serializeToAsdf(['a','\0'])) == ['a','\0']);
assert(deserialize!(char[2])(serializeToAsdf(['a','\255'])) == ['a','\255']);
assert(deserialize!(char[2])(serializeToAsdf(['\255'])) == ['\255','\0']);
assert(deserialize!(char[2])(serializeToAsdf(['\255', '\255', '\255'])) == ['\255','\255']);
Examples:
AA with value of aggregate type
struct Foo
{

}

assert (deserialize!(Foo[int])(serializeToJson([1: Foo()])) == [1:Foo()]);
SerdeException deserializeValue(V : T[string], T)(Asdf data, ref V value);
Deserialize string-value associative array
Examples:
assert(deserialize!(int[string])(serializeToJson(null)) is null);
assert(deserialize!(int[string])(serializeToAsdf(null)) is null);
assert(deserialize!(int[string])(serializeToJson(["a" : 1, "b" : 2])) == ["a" : 1, "b" : 2]);
assert(deserialize!(int[string])(serializeToAsdf(["a" : 1, "b" : 2])) == ["a" : 1, "b" : 2]);
SerdeException deserializeValue(V : T[E], T, E)(Asdf data, ref V value)
if (is(E == enum));
Deserialize enumeration-value associative array
Examples:
enum E {a, b}
assert(deserialize!(int[E])(serializeToJson(null)) is null);
assert(deserialize!(int[E])(serializeToAsdf(null)) is null);
assert(deserialize!(int[E])(serializeToJson([E.a : 1, E.b : 2])) == [E.a : 1, E.b : 2]);
assert(deserialize!(int[E])(serializeToAsdf([E.a : 1, E.b : 2])) == [E.a : 1, E.b : 2]);
SerdeException deserializeValue(V : T[K], T, K)(Asdf data, ref V value)
if (isIntegral!K && !is(K == enum));
Deserialize associative array with integral type key
Examples:
assert(deserialize!(int[int])(serializeToJson(null)) is null);
assert(deserialize!(int[int])(serializeToAsdf(null)) is null);
assert(deserialize!(int[int])(serializeToJson([2 : 1, 40 : 2])) == [2 : 1, 40 : 2]);
assert(deserialize!(int[int])(serializeToAsdf([2 : 1, 40 : 2])) == [2 : 1, 40 : 2]);
Examples:
import std.typecons;

struct Nested
{
    float f;
}

struct T
{
    string str;
    Nullable!Nested nested;
    @serdeOptional
    Nullable!bool nval;
}

T t;
assert(deserialize!T(`{"str":null,"nested":null}`) == t);
t.str = "txt";
t.nested = Nested(123);
t.nval = false;
assert(deserialize!T(`{"str":"txt","nested":{"f":123},"nval":false}`) == t);
SerdeException deserializeValue(V)(Asdf data, ref V value)
if (isAggregateType!V);
Deserialize aggregate value
Examples:
StringMap support
import mir.string_map;
auto map = `{"b" : 1.0, "a" : 2}`.deserialize!(StringMap!double);
assert(map.keys == ["b", "a"]);
assert(map.values == [1.0, 2.0]);
assert(map.serializeToJson == `{"b":1.0,"a":2.0}`);
Examples:
JsonAlgebraic alias support
import mir.algebraic_alias.json;
auto value = `{"b" : 1.0, "a" : [1, true, false, null, "str"]}`.deserialize!JsonAlgebraic;
assert(value.kind == JsonAlgebraic.Kind.object);

auto object = value.get!(StringMap!JsonAlgebraic);
assert(object.keys == ["b", "a"]); // sequental order
assert(object["b"].get!double == 1.0);
object["b"].get!double += 4;

auto array = object["a"].get!(JsonAlgebraic[]);
assert(array[0].get!long == 1);
array[0].get!long += 10;
assert(array[1].get!bool == true);
assert(array[2].get!bool == false);
assert(array[3].isNull);
assert(array[3].get!(typeof(null)) is null);
assert(array[4].get!string == "str");

assert(value.serializeToJson == `{"b":5.0,"a":[11,true,false,null,"str"]}`);
value = [JsonAlgebraic[].init.JsonAlgebraic, StringMap!JsonAlgebraic.init.JsonAlgebraic, string.init.JsonAlgebraic];
// algebraics have type safe serialization instead of null values
assert(value.serializeToJson == `[[],{},""]`, value.serializeToJson);
Examples:
User defined algebraic types deserialization supports any subset of the following types:
  • typeof(null)
  • bool
  • long
  • double
  • string
  • AnyType[]
  • StringMap!AnyType
  • AnyType[string]
A StringMap has has priority over builtin associative arrays.
Serializations works with any algebraic types.
See_also: mir.algebraic, mir.string_map
import mir.algebraic: Nullable, This; // Nullable, Variant, or TaggedVariant
alias MyJsonAlgebraic = Nullable!(bool, string, double[], This[string]);

auto value = `{"b" : true, "z" : null, "this" : {"c" : "str", "d" : [1, 2, 3, 4]}}`.deserialize!MyJsonAlgebraic;

auto object = value.get!(MyJsonAlgebraic[string]);
assert(object["b"].get!bool == true);
assert(object["z"].isNull);

object = object["this"].get!(MyJsonAlgebraic[string]);
assert(object["c"].get!string == "str");
assert(object["d"].get!(double[]) == [1.0, 2, 3, 4]);
Examples:
static class Turtle
{
    string _metadata;
    long id;
    string species;
}

auto turtles = `
   [{"_metadata":"xyz123", "id":72, "species":"Galapagos"},
    {"_metadata":"tu144", "id":108, "species":"Snapping"},
    null,
    null,
    {"_metadata":"anew1", "id":9314, "species":"Sea Turtle"}]`
      .deserialize!(Turtle[]);
Examples:
Alias this support
struct S
{
    int a;
}

struct C
{
    S s;
    alias s this; 
    int b;
}

assert(`{"a":3, "b":4}`.deserialize!C == C(S(3), 4));
Examples:
serdeOrderedIn supprot
static struct I
{
    @serdeOptional
    int a;
    int m;
}

@serdeOrderedIn
static struct S
{
    import mir.small_string;

    SmallString!8 id;

    int acc;

    I inner = I(1000, 0);

@safe pure nothrow @nogc
@property:

    void add(int v)
    {
        inner.a += v;
        acc += v;
    }

    void mul(int v)
    {
        inner.m += v;
        acc *= v;
    }
}

import mir.reflection;

auto val = `{"mul":2, "id": "str", "add":5,"acc":100, "inner":{"m": 2000}}`.deserialize!S;
assert(val.id == "str");
assert(val.acc == 210);
assert(val.inner.a == 1005);
assert(val.inner.m == 2002);
assert(val.serializeToJson == `{"id":"str","acc":210,"inner":{"a":1005,"m":2002}}`);
Examples:
serdeRealOrderedIn supprot
static struct I
{
    @serdeOptional
    int a;
    int m;
}

@serdeRealOrderedIn
static struct S
{
    import mir.small_string;

    SmallString!8 id;

    int acc;

    I inner = I(1000, 0);

@safe pure nothrow @nogc
@property:

    void add(int v)
    {
        inner.a += v;
        acc += v;
    }

    void mul(int v)
    {
        inner.m += v;
        acc *= v;
    }
}

import mir.reflection;

auto val = `{"mul":2, "id": "str", "add":5,"acc":100, "inner":{"m": 2000}}`.deserialize!S;
assert(val.id == "str");
assert(val.acc == 210);
assert(val.inner.a == 1005);
assert(val.inner.m == 2002);
assert(val.serializeToJson == `{"id":"str","acc":210,"inner":{"a":1005,"m":2002}}`);
Examples:
struct A {
    string str;
}
struct B {
    A a;
    string serialize() const {
        return asdf.serializeToJson(a);
    }
}
assert(B(A("2323")).serialize == `{"str":"2323"}`);