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.

mir.ion.ser

High level serialization API

string serializeJson(V)(auto ref V value);
JSON serialization function.
Examples:
struct S
{
    string foo;
    uint bar;
}

assert(serializeJson(S("str", 4)) == `{"foo":"str","bar":4}`);
string serializeJsonPretty(string sep = "\x09", V)(auto ref V value);
JSON serialization function with pretty formatting.
Examples:
static struct S { int a; }
assert(S(4).serializeJsonPretty == "{\n\t\"a\": 4\n}");
void serializeJsonPretty(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.
Examples:
static struct Decor
{
    int candles; // 0
    float fluff = float.infinity; // inf 
}

static struct Cake
{
    @serdeIgnoreDefault
    string name = "Chocolate Cake";
    int slices = 8;
    float flavor = 1;
    @serdeIgnoreDefault
    Decor dec = Decor(20); // { 20, inf }
}

assert(Cake("Normal Cake").serializeJson == `{"name":"Normal Cake","slices":8,"flavor":1}`);
auto cake = Cake.init;
cake.dec = Decor.init;
assert(cake.serializeJson == `{"slices":8,"flavor":1,"dec":{"candles":0,"fluff":"inf"}}`);
assert(cake.dec.serializeJson == `{"candles":0,"fluff":"inf"}`);

static struct A
{
    @serdeIgnoreDefault
    string str = "Banana";
    int i = 1;
}
assert(A.init.serializeJson == `{"i":1}`);

static struct S
{
    @serdeIgnoreDefault
    A a;
}
assert(S.init.serializeJson == `{}`);
assert(S(A("Berry")).serializeJson == `{"a":{"str":"Berry","i":1}}`);

static struct D
{
    S s;
}
assert(D.init.serializeJson == `{"s":{}}`);
assert(D(S(A("Berry"))).serializeJson == `{"s":{"a":{"str":"Berry","i":1}}}`);
assert(D(S(A(null, 0))).serializeJson == `{"s":{"a":{"str":null,"i":0}}}`);

static struct F
{
    D d;
}
assert(F.init.serializeJson == `{"d":{"s":{}}}`);
Examples:
static struct S
{
    @serdeIgnoreIn
    string s;
}
// assert(`{"s":"d"}`.deserializeJson!S.s == null, `{"s":"d"}`.deserializeJson!S.s);
assert(S("d").serializeJson == `{"s":"d"}`);
Examples:
import mir.ion.deser;

static struct S
{
    @serdeIgnoreOut
    string s;
}
assert(`{"s":"d"}`.deserializeJson!S.s == "d");
assert(S("d").serializeJson == `{}`);
Examples:
static struct S
{
    @serdeIgnoreOutIf!`a < 0`
    int a;
}

assert(serializeJson(S(3)) == `{"a":3}`, serializeJson(S(3)));
assert(serializeJson(S(-3)) == `{}`);
Examples:
import std.range;
import std.uuid;

static struct S
{
    private int count;
    @serdeLikeList
    auto numbers() @property // uses `foreach`
    {
        return iota(count);
    }

    @serdeLikeList
    @serdeProxy!string // input element type of
    @serdeIgnoreOut
    Appender!(string[]) strings; //`put` method is used
}

assert(S(5).serializeJson == `{"numbers":[0,1,2,3,4]}`);
// assert(`{"strings":["a","b"]}`.deserializeJson!S.strings.data == ["a","b"]);
Examples:
static struct M
{
    private int sum;

    // opApply is used for serialization
    int opApply(int delegate(in char[] key, int val) pure dg) pure
    {
        if(auto r = dg("a", 1)) return r;
        if(auto r = dg("b", 2)) return r;
        if(auto r = dg("c", 3)) return r;
        return 0;
    }

    // opIndexAssign for deserialization
    void opIndexAssign(int val, string key) pure
    {
        sum += val;
    }
}

static struct S
{
    @serdeLikeStruct
    @serdeProxy!int
    M obj;
}

assert(S.init.serializeJson == `{"obj":{"a":1,"b":2,"c":3}}`);
// assert(`{"obj":{"a":1,"b":2,"c":9}}`.deserializeJson!S.obj.sum == 12);
Examples:
import mir.ion.deser;
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"}`);
struct JsonSerializer(string sep, Dg);
JSON serialization back-end
JsonBuffer!Dg sink;
JSON string buffer
this(Dg sink);
uint objectBegin();

void objectEnd(uint state);

uint arrayBegin();

void arrayEnd(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 std.array;
import std.bigint;
import std.format: singleSpec;

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

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

    ser.putEscapedKey("array");
    auto state1 = ser.arrayBegin();
        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.arrayEnd(state1);

ser.objectEnd(state0);
ser.flush;

assert(app.data == `{"null":null,"array":[null,123,1.2300000123e+07,"\t","\r","\n",1234567890]}`);
void serializeValue(S)(ref S serializer, typeof(null));
null value serialization
Examples:
assert(serializeJson(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(serializeJson(BigInt(123)) == `123`);
assert(serializeJson(2.40f) == `2.4`);
assert(serializeJson(float.nan) == `"nan"`);
assert(serializeJson(float.infinity) == `"inf"`);
assert(serializeJson(-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(serializeJson(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(serializeJson(Key.foo) == `"FOO"`);
void serializeValue(S)(ref S serializer, in char[] value);
String serialization
Examples:
assert(serializeJson("\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(serializeJson(filtered1) == `[{"i":1},{"i":3},{"i":17}]`);
assert(serializeJson(filtered2) == `[{"i":4}]`);
Examples:
uint[2] ar = [1, 2];
assert(serializeJson(ar) == `[1,2]`);
assert(serializeJson(ar[]) == `[1,2]`);
assert(serializeJson(ar[0 .. 0]) == `[]`);
assert(serializeJson((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(serializeJson(ar) == `{"a":1}`);
ar.remove("a");
assert(serializeJson(ar) == `{}`);
assert(serializeJson((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(serializeJson(ar) == `{"a":1}`);
ar.remove(E.a);
assert(serializeJson(ar) == `{}`);
assert(serializeJson((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(serializeJson(ar) == `{"256":1}`);
ar.remove(256);
assert(serializeJson(ar) == `{}`);
assert(serializeJson((uint[string]).init) == `null`);
// assert(deserializeJson!(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.serializeJson == `{"str":null,"nested":null}`);
t.str = "txt";
t.nested = Nested(123);
assert(t.serializeJson == `{"str":"txt","nested":{"f":123}}`);
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)).serializeJson == `{"u":3,"b":4}`);
Examples:
Custom serialize
import std.conv: to;

struct S
{
    void serialize(S)(ref S serializer)
    {
        auto state = serializer.objectBegin;
        serializer.putEscapedKey("foo");
        serializer.putValue("bar");
        serializer.objectEnd(state);
    }
}
enum json = `{"foo":"bar"}`;
assert(serializeJson(S()) == json);