Skip to content

Instantly share code, notes, and snippets.

@PetarKirov
Last active September 30, 2021 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PetarKirov/42917ad92bb11882d58bf35897ac749a to your computer and use it in GitHub Desktop.
Save PetarKirov/42917ad92bb11882d58bf35897ac749a to your computer and use it in GitHub Desktop.
JSON Deserialization in D
import std.json : JSONValue, parseJSON;
T fromJson(T)(JSONValue j)
{
import std.traits : isNumeric;
// Handle JSON number and boolean values:
static if (is(typeof(j.get!T)))
return j.get!T;
// Handle JSON object values -> struct:
else static if (is(T == struct))
{
T result;
static foreach (idx, member; T.tupleof)
result.tupleof[idx] = j.object[__traits(identifier, member)].fromJson!(typeof(member));
return result;
}
// Handle JSON object values -> assosiative array:
else static if (is(T == V[K], K, V))
{
if (j.isNull)
return null;
T result;
foreach (key, value; j.object)
result[key] = value.fromJson!V;
return result;
}
// Handle JSON array values:
else static if (is(T : U[], U))
{
if (j.isNull)
return null;
T result = new U[j.array.length];
foreach (i, ref jArrayElem; j.array)
result[i] = jArrayElem.fromJson!U;
return result;
}
// Handle null JSON values:
else static if (__traits(compiles, { T t = null; }))
{
if (j.isNull)
return null;
else
assert(0, "Expected null convertible to `" ~ T.stringof ~ "` but got: " ~ j.toString());
}
else
static assert(0, "Unsupported type: `" ~ T.stringof ~ "`");
}
unittest
{
import std.meta : AliasSeq;
assert(`true`.parseJSON.fromJson!bool == true);
assert(`false`.parseJSON.fromJson!bool == false);
static foreach (Num; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real))
{
assert(`42`.parseJSON.fromJson!Num == Num(42));
assert(`[1, 2, 3]`.parseJSON.fromJson!(Num[]) == [1, 2, 3]);
assert(`[[1], [2], [3]]`.parseJSON.fromJson!(Num[][]) == [[1], [2], [3]]);
assert(`[[[[1]], [[2]], [[3]]]]`.parseJSON.fromJson!(Num[][][][]) == [[[[1]], [[2]], [[3]]]]);
assert(`{"a": 1, "b": 2}`.parseJSON.fromJson!(Num[string]) == ["a": Num(1), "b": Num(2)]);
}
static foreach (Nullable; AliasSeq!(int[], Object, Object[], int[string], Object[string]))
{
assert(`null`.parseJSON.fromJson!Nullable is null);
}
assert(`{"a": 1, "b": 2}`.parseJSON.fromJson!(int[string]) == ["a": 1, "b": 2]);
assert(`{"a": [1], "b": [2]}`.parseJSON.fromJson!(int[][string]) == ["a": [1], "b": [2]]);
assert(
`{"a": { "a1": ["11", "12"], "a2": ["21", "22"] }, "b": null }`
.parseJSON.fromJson!(string[][string][string]) ==
["a": [ "a1": ["11", "12"], "a2": ["21", "22"] ], "b": null ]
);
}
unittest
{
const json = `{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
},
{
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": [
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
},
{
"name": "Eternal Flame",
"age": 1000000,
"secretIdentity": "Unknown",
"powers": [
"Immortality",
"Heat Immunity",
"Inferno",
"Teleportation",
"Interdimensional travel"
]
}
]
}`;
struct Squad
{
string squadName;
string homeTown;
int formed;
string secretBase;
bool active;
Hero[] members;
struct Hero
{
string name;
int age;
string secretIdentity;
string[] powers;
}
}
Squad s = json.parseJSON.fromJson!Squad;
assert(s.squadName == "Super hero squad");
assert(s.homeTown == "Metro City");
assert(s.formed == 2016);
assert(s.secretBase == "Super tower");
assert(s.active == true);
assert(s.members == [
Squad.Hero(
"Molecule Man",
29,
"Dan Jukes",
[
"Radiation resistance",
"Turning tiny",
"Radiation blast"
]
),
Squad.Hero(
"Madame Uppercut",
39,
"Jane Wilson",
[
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
),
Squad.Hero(
"Eternal Flame",
1000000,
"Unknown",
[
"Immortality",
"Heat Immunity",
"Inferno",
"Teleportation",
"Interdimensional travel"
]
)
]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment