From 4f6ba1dc45ced2592e8c71819c2a23fc1be0ae81 Mon Sep 17 00:00:00 2001 From: Jan Jurzitza Date: Mon, 28 Aug 2017 13:59:25 +0200 Subject: [PATCH] Add Json.toJSONValue & Json.fromJSONValue fix #1465 --- data/vibe/data/json.d | 94 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/data/vibe/data/json.d b/data/vibe/data/json.d index 4cb69c6a6e..d97d26334e 100644 --- a/data/vibe/data/json.d +++ b/data/vibe/data/json.d @@ -71,15 +71,16 @@ public import vibe.data.serialization; public import std.json : JSONException; import std.algorithm; import std.array; +import std.bigint; import std.conv; import std.datetime; import std.exception; import std.format; -import std.string; +import std.json : JSONValue, JSON_TYPE; import std.range; +import std.string; import std.traits; import std.typecons : Tuple; -import std.bigint; /******************************************************************************/ /* public types */ @@ -1074,6 +1075,76 @@ struct Json { return ret.data; } + /** + Converts this Json object to a std.json.JSONValue object + */ + JSONValue toJSONValue() + const @safe { + final switch (type) { + case Json.Type.undefined: + case Json.Type.null_: + return JSONValue(null); + case Json.Type.bool_: + return JSONValue(get!bool); + case Json.Type.int_: + return JSONValue(get!long); + case Json.Type.bigInt: + auto bi = get!BigInt; + if (bi > long.max) + return JSONValue((() @trusted => cast(ulong)get!BigInt)()); + else + return JSONValue((() @trusted => cast(long)get!BigInt)()); + case Json.Type.float_: + return JSONValue(get!double); + case Json.Type.string: + return JSONValue(get!string); + case Json.Type.array: + JSONValue[] ret; + foreach (ref const Json e; byValue) + ret ~= e.toJSONValue; + return JSONValue(ret); + case Json.Type.object: + JSONValue[string] ret; + foreach (string k, ref const Json e; byKeyValue) { + if( e.type == Json.Type.undefined ) continue; + ret[k] = e.toJSONValue; + } + return JSONValue(ret); + } + } + + /** + Converts a std.json.JSONValue object to a vibe Json object. + */ + static Json fromJSONValue(in JSONValue value) + @safe { + final switch (value.type) { + case JSON_TYPE.NULL: + return Json(null); + case JSON_TYPE.OBJECT: + return (() @trusted { + Json[string] ret; + foreach (string k, ref const JSONValue v; value.object) + ret[k] = Json.fromJSONValue(v); + return Json(ret); + })(); + case JSON_TYPE.ARRAY: + return (() @trusted => Json(value.array.map!(a => Json.fromJSONValue(a)).array))(); + case JSON_TYPE.STRING: + return Json(value.str); + case JSON_TYPE.INTEGER: + return Json(value.integer); + case JSON_TYPE.UINTEGER: + return Json(BigInt(value.uinteger)); + case JSON_TYPE.FLOAT: + return Json(value.floating); + case JSON_TYPE.TRUE: + return Json(true); + case JSON_TYPE.FALSE: + return Json(false); + } + } + private void checkType(TYPES...)(string op = null) const { bool matched = false; @@ -1795,6 +1866,7 @@ struct JsonStringSerializer(R, bool pretty = false) m_range.put('"'); } else static if (is(T == Json)) m_range.writeJsonString(value); + else static if (is(T == JSONValue)) m_range.writeJsonString(Json.fromJSONValue(value)); else static if (isJsonSerializable!T) { static if (!__traits(compiles, () @safe { return value.toJson(); } ())) pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~T.stringof~".toJson() with @safe."); @@ -1930,6 +2002,7 @@ struct JsonStringSerializer(R, bool pretty = false) } else static if (is(T == string)) return m_range.skipJsonString(&m_line); else static if (is(T == Json)) return m_range.parseJson(&m_line); + else static if (is(T == JSONValue)) return m_range.parseJson(&m_line).toJSONValue; else static if (isJsonSerializable!T) { static if (!__traits(compiles, () @safe { return T.fromJson(Json.init); } ())) pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~T.stringof~".fromJson() with @safe."); @@ -2462,3 +2535,20 @@ private auto trustedRange(R)(R range) assert(b.foos[0].i == 2); assert(b.foos[0].foos.length == 0); } + +@system unittest { // Json <-> std.json.JSONValue + auto a = parseJsonString(`{ + "null": null, + "string": "Hello", + "integer": 123456, + "uinteger": 18446744073709551614, + "float": 12.34, + "object": { "hello": "world" }, + "array": [1, 2, "string"], + "true": true, + "false": false + }`); + assert(Json.fromJSONValue(a.toJSONValue) == a); + auto v = a.toJSONValue; + assert(deserializeJson!JSONValue(serializeToJson(v)) == v); +}