1 /** 2 * Contains functions for serializing JSON data. 3 * 4 * Authors: <a href="https://github.com/rcorre">rcorre</a> 5 * License: <a href="http://opensource.org/licenses/MIT">MIT</a> 6 * Copyright: Copyright © 2015, rcorre 7 * Date: 3/23/15 8 */ 9 module jsonizer.tojson; 10 11 import std.json; 12 import std.traits; 13 import std.conv : to; 14 import std.file : write; 15 import std.exception : enforce; 16 import std.typecons : staticIota, Flag; 17 18 // Primitive Type Conversions ----------------------------------------------------------- 19 /// convert a bool to a JSONValue 20 JSONValue toJSON(T : bool)(T val) { 21 return JSONValue(val); 22 } 23 24 /// Serialize a boolean. 25 unittest { 26 assert(false.toJSON == JSONValue(false)); 27 assert(true.toJSON == JSONValue(true)); 28 } 29 30 /// convert a string to a JSONValue 31 JSONValue toJSON(T : string)(T val) { 32 return JSONValue(val); 33 } 34 35 /// Serialize a string. 36 unittest { 37 assert("bork".toJSON == JSONValue("bork")); 38 } 39 40 /// convert a floating point value to a JSONValue 41 JSONValue toJSON(T : real)(T val) if (!is(T == enum)) { 42 return JSONValue(val); 43 } 44 45 /// Serialize a floating-point value. 46 unittest { 47 assert(4.1f.toJSON == JSONValue(4.1f)); 48 } 49 50 /// convert a signed integer to a JSONValue 51 JSONValue toJSON(T : long)(T val) if (isSigned!T && !is(T == enum)) { 52 return JSONValue(val); 53 } 54 55 /// Serialize a signed integer. 56 unittest { 57 auto j3 = toJSON(41); 58 assert(4.toJSON == JSONValue(4)); 59 assert(4L.toJSON == JSONValue(4L)); 60 } 61 62 /// convert an unsigned integer to a JSONValue 63 JSONValue toJSON(T : ulong)(T val) if (isUnsigned!T && !is(T == enum)) { 64 return JSONValue(val); 65 } 66 67 /// Serialize an unsigned integer. 68 unittest { 69 assert(41u.toJSON == JSONValue(41u)); 70 } 71 72 /// convert an enum name to a JSONValue 73 JSONValue toJSON(T)(T val) if (is(T == enum)) { 74 JSONValue json; 75 json.str = to!string(val); 76 return json; 77 } 78 79 /// Enums are serialized by name. 80 unittest { 81 enum Category { one, two } 82 83 assert(Category.one.toJSON.str == "one"); 84 assert(Category.two.toJSON.str == "two"); 85 } 86 87 /// convert a homogenous array into a JSONValue array 88 JSONValue toJSON(T)(T args) if (isArray!T && !isSomeString!T) { 89 static if (isDynamicArray!T) { 90 if (args is null) { return JSONValue(null); } 91 } 92 JSONValue[] jsonVals; 93 foreach(arg ; args) { 94 jsonVals ~= toJSON(arg); 95 } 96 JSONValue json; 97 json.array = jsonVals; 98 return json; 99 } 100 101 /// Serialize a homogenous array. 102 unittest { 103 auto json = [1, 2, 3].toJSON; 104 assert(json.type == JSON_TYPE.ARRAY); 105 assert(json.array[0].integer == 1); 106 assert(json.array[1].integer == 2); 107 assert(json.array[2].integer == 3); 108 } 109 110 /// convert a set of heterogenous values into a JSONValue array 111 JSONValue toJSON(T...)(T args) { 112 JSONValue[] jsonVals; 113 foreach(arg ; args) { 114 jsonVals ~= toJSON(arg); 115 } 116 JSONValue json; 117 json.array = jsonVals; 118 return json; 119 } 120 121 /// Serialize a heterogenous array. 122 unittest { 123 auto json = toJSON(1, "hi", 0.4); 124 assert(json.type == JSON_TYPE.ARRAY); 125 assert(json.array[0].integer == 1); 126 assert(json.array[1].str == "hi"); 127 assert(json.array[2].floating == 0.4); 128 } 129 130 /// convert a associative array into a JSONValue object 131 JSONValue toJSON(T)(T map) if (isAssociativeArray!T) { 132 assert(is(KeyType!T : string), "toJSON requires string keys for associative array"); 133 if (map is null) { return JSONValue(null); } 134 JSONValue[string] obj; 135 foreach(key, val ; map) { 136 obj[key] = toJSON(val); 137 } 138 JSONValue json; 139 json.object = obj; 140 return json; 141 } 142 143 /// Serialize an associative array. 144 unittest { 145 auto json = ["a" : 1, "b" : 2, "c" : 3].toJSON; 146 assert(json.type == JSON_TYPE.OBJECT); 147 assert(json.object["a"].integer == 1); 148 assert(json.object["b"].integer == 2); 149 assert(json.object["c"].integer == 3); 150 } 151 152 /// Convert a user-defined type to json. 153 /// See `jsonizer.jsonize` for info on how to mark your own types for serialization. 154 JSONValue toJSON(T)(T obj) if (!isBuiltinType!T) { 155 static if (is (T == class)) { 156 if (obj is null) { return JSONValue(null); } 157 } 158 return obj.convertToJSON(); 159 } 160 161 /// Serialize an instance of a user-defined type to a json object. 162 unittest { 163 import jsonizer.jsonize; 164 import jsonizer.fromjson; 165 166 static struct Foo { 167 mixin JsonizeMe; 168 169 @jsonize { 170 int i; 171 string[] a; 172 } 173 } 174 175 auto foo = Foo(12, [ "a", "b" ]); 176 auto json = foo.toJSON(); 177 178 assert(json.fromJSON!int("i") == 12); 179 assert(json.fromJSON!(string[])("a") == [ "a", "b" ]); 180 } 181 182 /// Whether to nicely format json string. 183 alias PrettyJson = Flag!"PrettyJson"; 184 185 /// Convert an instance of some type `T` directly into a json-formatted string. 186 /// Params: 187 /// T = type of object to convert 188 /// obj = object to convert to sjon 189 /// pretty = whether to prettify string output 190 string toJSONString(T)(T obj, PrettyJson pretty = PrettyJson.yes) { 191 auto json = obj.toJSON!T; 192 return pretty ? json.toPrettyString : json.toString; 193 } 194 195 unittest { 196 assert([1, 2, 3].toJSONString(PrettyJson.no) == "[1,2,3]"); 197 assert([1, 2, 3].toJSONString(PrettyJson.yes) == "[\n 1,\n 2,\n 3\n]"); 198 } 199 200 /// Write a jsonizeable object to a file. 201 /// Params: 202 /// path = filesystem path to write json to 203 /// obj = object to convert to json and write to path 204 void writeJSON(T)(string path, T obj) { 205 auto json = toJSON!T(obj); 206 path.write(json.toPrettyString); 207 } 208 209 unittest { 210 import std.json : parseJSON; 211 import std.path : buildPath; 212 import std.uuid : randomUUID; 213 import std.file : tempDir, readText, mkdirRecurse; 214 215 auto dir = buildPath(tempDir(), "jsonizer_writejson_test"); 216 mkdirRecurse(dir); 217 auto file = buildPath(dir, randomUUID().toString); 218 219 file.writeJSON([1, 2, 3]); 220 221 auto json = file.readText.parseJSON; 222 assert(json.array[0].integer == 1); 223 assert(json.array[1].integer == 2); 224 assert(json.array[2].integer == 3); 225 }