1 /**
2 	Generic serialization framework.
3 
4 	This module provides general means for implementing (de-)serialization with
5 	a standardized behavior.
6 
7 	Supported_types:
8 		The following rules are applied in order when serializing or
9 		deserializing a certain type:
10 
11 		$(OL
12 			$(LI An `enum` type is serialized as its raw value, except if
13 				`@byName` is used, in which case the name of the enum value
14 				is serialized.)
15 			$(LI Any type that is specifically supported by the serializer
16 				is directly serialized. For example, the BSON serializer
17 				supports `BsonObjectID` directly.)
18 			$(LI Arrays and tuples (`std.typecons.Tuple`) are serialized
19 				using the array serialization functions where each element is
20 				serialized again according to these rules.)
21 			$(LI Associative arrays are serialized similar to arrays. The key
22 				type of the AA must satisfy the `isStringSerializable` trait
23 				and will always be serialized as a string.)
24 			$(LI Any `Nullable!T` will be serialized as either `null`, or
25 				as the contained value (subject to these rules again).)
26 			$(LI Any `Typedef!T` will be serialized as if it were just `T`.)
27 			$(LI Any `BitFlags!T` value will be serialized as `T[]`)
28 			$(LI Types satisfying the `isPolicySerializable` trait for the
29 				supplied `Policy` will be serialized as the value returned
30 				by the policy `toRepresentation` function (again subject to
31 				these rules).)
32 			$(LI Types satisfying the `isCustomSerializable` trait will be
33 				serialized as the value returned by their `toRepresentation`
34 				method (again subject to these rules).)
35 			$(LI Types satisfying the `isISOExtStringSerializable` trait will be
36 				serialized as a string, as returned by their `toISOExtString`
37 				method. This causes types such as `SysTime` to be serialized
38 				as strings.)
39 			$(LI Types satisfying the `isStringSerializable` trait will be
40 				serialized as a string, as returned by their `toString`
41 				method.)
42 			$(LI Struct and class types by default will be serialized as
43 				associative arrays, where the key is the name of the
44 				corresponding field (can be overridden using the `@name`
45 				attribute). If the struct/class is annotated with `@asArray`,
46 				it will instead be serialized as a flat array of values in the
47 				order of declaration. Null class references will be serialized
48 				as `null`.)
49 			$(LI Pointer types will be serialized as either `null`, or as
50 				the value they point to.)
51 			$(LI Built-in integers and floating point values, as well as
52 				boolean values will be converted to strings, if the serializer
53 				doesn't support them directly.)
54 		)
55 
56 		Note that no aliasing detection is performed, so that pointers, class
57 		references and arrays referencing the same memory will be serialized
58 		as multiple copies. When in turn deserializing the data, they will also
59 		end up as separate copies in memory.
60 
61 	Field_names:
62 		By default, the field name of the serialized D type (for `struct` and
63 		`class` aggregates) is represented as-is in the serialized result. To
64 		circumvent name clashes with D's keywords, a single trailing underscore of
65 		any field name is stipped, so that a field name of `version_` results in
66 		just `"version"` as the serialized value. Names can also be freely
67 		customized using the `@name` annotation.
68 
69 		Associative array keys are always represented using their direct string
70 		representation.
71 
72 	Serializer_implementation:
73 		Serializers are implemented in terms of a struct with template methods that
74 		get called by the serialization framework:
75 
76 		---
77 		struct ExampleSerializer {
78 			enum isSupportedValueType(T) = is(T == string) || is(T == typeof(null));
79 
80 			// serialization
81 			auto getSerializedResult();
82 			void beginWriteDocument(TypeTraits)();
83 			void endWriteDocument(TypeTraits)();
84 			void beginWriteDictionary(TypeTraits)();
85 			void endWriteDictionary(TypeTraits)();
86 			void beginWriteDictionaryEntry(ElementTypeTraits)(string name);
87 			void endWriteDictionaryEntry(ElementTypeTraits)(string name);
88 			void beginWriteArray(TypeTraits)(size_t length);
89 			void endWriteArray(TypeTraits)();
90 			void beginWriteArrayEntry(ElementTypeTraits)(size_t index);
91 			void endWriteArrayEntry(ElementTypeTraits)(size_t index);
92 			void writeValue(TypeTraits, T)(T value);
93 
94 			// deserialization
95 			void readDictionary(TypeTraits)(scope void delegate(string) entry_callback);
96 			void beginReadDictionaryEntry(ElementTypeTraits)(string);
97 			void endReadDictionaryEntry(ElementTypeTraits)(string);
98 			void readArray(TypeTraits)(scope void delegate(size_t) size_callback, scope void delegate() entry_callback);
99 			void beginReadArrayEntry(ElementTypeTraits)(size_t index);
100 			void endReadArrayEntry(ElementTypeTraits)(size_t index);
101 			T readValue(TypeTraits, T)();
102 			bool tryReadNull(TypeTraits)();
103 		}
104 		---
105 
106 		The `TypeTraits` type passed to the individual methods has the following members:
107 		$(UL
108 			$(LI `Type`: The original type of the field to serialize)
109 			$(LI `Attributes`: User defined attributes attached to the field)
110 			$(LI `Policy`: An alias to the policy used for the serialization process)
111 		)
112 
113 		`ElementTypeTraits` have the following additional members:
114 		$(UL
115 			$(LI `ContainerType`: The original type of the enclosing container type)
116 			$(LI `ContainerAttributes`: User defined attributes attached to the enclosing container)
117 		)
118 
119 	Copyright: © 2013-2016 rejectedsoftware e.K.
120 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
121 	Authors: Sönke Ludwig
122 */
123 module vibe.data.serialization;
124 
125 import vibe.internal.meta.traits;
126 import vibe.internal.meta.uda;
127 
128 import std.array : Appender, appender;
129 import std.conv : to;
130 import std.exception : enforce;
131 import std.traits;
132 import std.typetuple;
133 
134 
135 /**
136 	Serializes a value with the given serializer.
137 
138 	The serializer must have a value result for the first form
139 	to work. Otherwise, use the range based form.
140 
141 	See_Also: `vibe.data.json.JsonSerializer`, `vibe.data.json.JsonStringSerializer`, `vibe.data.bson.BsonSerializer`
142 */
143 auto serialize(Serializer, T, ARGS...)(T value, ARGS args)
144 {
145 	auto serializer = Serializer(args);
146 	serialize(serializer, value);
147 	return serializer.getSerializedResult();
148 }
149 /// ditto
150 void serialize(Serializer, T)(ref Serializer serializer, T value)
151 {
152 	serializeWithPolicy!(Serializer, DefaultPolicy)(serializer, value);
153 }
154 
155 /** Note that there is a convenience function `vibe.data.json.serializeToJson`
156 	that can be used instead of manually invoking `serialize`.
157 */
158 unittest {
159 	import vibe.data.json;
160 
161 	struct Test {
162 		int value;
163 		string text;
164 	}
165 
166 	Test test;
167 	test.value = 12;
168 	test.text = "Hello";
169 
170 	Json serialized = serialize!JsonSerializer(test);
171 	assert(serialized["value"].get!int == 12);
172 	assert(serialized["text"].get!string == "Hello");
173 }
174 
175 unittest {
176 	import vibe.data.json;
177 
178 	// Make sure that immutable(char[]) works just like string
179 	// (i.e., immutable(char)[]).
180 	immutable key = "answer";
181 	auto ints = [key: 42];
182 	auto serialized = serialize!JsonSerializer(ints);
183 	assert(serialized[key].get!int == 42);
184 }
185 
186 /**
187 	Serializes a value with the given serializer, representing values according to `Policy` when possible.
188 
189 	The serializer must have a value result for the first form
190 	to work. Otherwise, use the range based form.
191 
192 	See_Also: `vibe.data.json.JsonSerializer`, `vibe.data.json.JsonStringSerializer`, `vibe.data.bson.BsonSerializer`
193 */
194 auto serializeWithPolicy(Serializer, alias Policy, T, ARGS...)(T value, ARGS args)
195 {
196 	auto serializer = Serializer(args);
197 	serializeWithPolicy!(Serializer, Policy)(serializer, value);
198 	return serializer.getSerializedResult();
199 }
200 /// ditto
201 void serializeWithPolicy(Serializer, alias Policy, T)(ref Serializer serializer, T value)
202 {
203 	static if (is(typeof(serializer.beginWriteDocument!T())))
204 		serializer.beginWriteDocument!T();
205 	serializeValueImpl!(Serializer, Policy).serializeValue!T(serializer, value);
206 	static if (is(typeof(serializer.endWriteDocument!T())))
207 		serializer.endWriteDocument!T();
208 }
209 ///
210 version (unittest)
211 {
212 }
213 
214 ///
215 unittest {
216 	import vibe.data.json;
217 
218 	template SizePol(T)
219 		if (__traits(allMembers, T) == TypeTuple!("x", "y"))
220 	{
221 		import std.conv;
222 		import std.array;
223 
224 		static string toRepresentation(T value) @safe {
225 			return to!string(value.x) ~ "x" ~ to!string(value.y);
226 		}
227 
228 		static T fromRepresentation(string value) {
229 			string[] fields = value.split('x');
230 			alias fieldT = typeof(T.x);
231 			auto x = to!fieldT(fields[0]);
232 			auto y = to!fieldT(fields[1]);
233 			return T(x, y);
234 		}
235 	}
236 
237 	static struct SizeI {
238 		int x;
239 		int y;
240 	}
241 	SizeI sizeI = SizeI(1,2);
242 	Json serializedI = serializeWithPolicy!(JsonSerializer, SizePol)(sizeI);
243 	assert(serializedI.get!string == "1x2");
244 
245 	static struct SizeF {
246 		float x;
247 		float y;
248 	}
249 	SizeF sizeF = SizeF(0.1f,0.2f);
250 	Json serializedF = serializeWithPolicy!(JsonSerializer, SizePol)(sizeF);
251 	assert(serializedF.get!string == "0.1x0.2");
252 }
253 
254 
255 /**
256 	Deserializes and returns a serialized value.
257 
258 	serialized_data can be either an input range or a value containing
259 	the serialized data, depending on the type of serializer used.
260 
261 	See_Also: `vibe.data.json.JsonSerializer`, `vibe.data.json.JsonStringSerializer`, `vibe.data.bson.BsonSerializer`
262 */
263 T deserialize(Serializer, T, ARGS...)(ARGS args)
264 {
265 	return deserializeWithPolicy!(Serializer, DefaultPolicy, T)(args);
266 }
267 
268 /** Note that there is a convenience function `vibe.data.json.deserializeJson`
269 	that can be used instead of manually invoking `deserialize`.
270 */
271 unittest {
272 	import vibe.data.json;
273 
274 	struct Test {
275 		int value;
276 		string text;
277 	}
278 
279 	Json serialized = Json.emptyObject;
280 	serialized["value"] = 12;
281 	serialized["text"] = "Hello";
282 
283 	Test test = deserialize!(JsonSerializer, Test)(serialized);
284 	assert(test.value == 12);
285 	assert(test.text == "Hello");
286 }
287 
288 /**
289 	Deserializes and returns a serialized value, interpreting values according to `Policy` when possible.
290 
291 	serialized_data can be either an input range or a value containing
292 	the serialized data, depending on the type of serializer used.
293 
294 	See_Also: `vibe.data.json.JsonSerializer`, `vibe.data.json.JsonStringSerializer`, `vibe.data.bson.BsonSerializer`
295 */
296 T deserializeWithPolicy(Serializer, alias Policy, T, ARGS...)(ARGS args)
297 {
298 	auto deserializer = Serializer(args);
299 	return deserializeValueImpl!(Serializer, Policy).deserializeValue!T(deserializer);
300 }
301 
302 ///
303 unittest {
304 	import vibe.data.json;
305 
306 	template SizePol(T)
307 		if (__traits(allMembers, T) == TypeTuple!("x", "y"))
308 	{
309 		import std.conv;
310 		import std.array;
311 
312 		static string toRepresentation(T value)
313 		@safe {
314 			return to!string(value.x) ~ "x" ~ to!string(value.y);
315 		}
316 
317 		static T fromRepresentation(string value)
318 		@safe {
319 			string[] fields = value.split('x');
320 			alias fieldT = typeof(T.x);
321 			auto x = to!fieldT(fields[0]);
322 			auto y = to!fieldT(fields[1]);
323 			return T(x, y);
324 		}
325 	}
326 
327 	static struct SizeI {
328 		int x;
329 		int y;
330 	}
331 
332 	Json serializedI = "1x2";
333 	SizeI sizeI = deserializeWithPolicy!(JsonSerializer, SizePol, SizeI)(serializedI);
334 	assert(sizeI.x == 1);
335 	assert(sizeI.y == 2);
336 
337 	static struct SizeF {
338 		float x;
339 		float y;
340 	}
341 	Json serializedF = "0.1x0.2";
342 	SizeF sizeF = deserializeWithPolicy!(JsonSerializer, SizePol, SizeF)(serializedF);
343 	assert(sizeF.x == 0.1f);
344 	assert(sizeF.y == 0.2f);
345 }
346 
347 private template serializeValueImpl(Serializer, alias Policy) {
348 	alias _Policy = Policy;
349 	static assert(Serializer.isSupportedValueType!string, "All serializers must support string values.");
350 	static assert(Serializer.isSupportedValueType!(typeof(null)), "All serializers must support null values.");
351 
352 	// work around https://issues.dlang.org/show_bug.cgi?id=16528
353 	static if (isSafeSerializer!Serializer) {
354 		void serializeValue(T, ATTRIBUTES...)(ref Serializer ser, T value) @safe { serializeValueDeduced!(T, ATTRIBUTES)(ser, value); }
355 	} else {
356 		void serializeValue(T, ATTRIBUTES...)(ref Serializer ser, T value) { serializeValueDeduced!(T, ATTRIBUTES)(ser, value); }
357 	}
358 
359 	private void serializeValueDeduced(T, ATTRIBUTES...)(ref Serializer ser, T value)
360 	{
361 		import std.typecons : BitFlags, Nullable, Tuple, Typedef, TypedefType, tuple;
362 
363 		alias TU = Unqual!T;
364 
365 		alias Traits = .Traits!(TU, _Policy, ATTRIBUTES);
366 
367 		static if (isPolicySerializable!(Policy, TU)) {
368 			alias CustomType = typeof(Policy!TU.toRepresentation(TU.init));
369 			ser.serializeValue!(CustomType, ATTRIBUTES)(Policy!TU.toRepresentation(value));
370 		} else static if (is(TU == enum)) {
371 			static if (hasPolicyAttributeL!(ByNameAttribute, Policy, ATTRIBUTES)) {
372 				ser.serializeValue!(string)(value.to!string());
373 			} else {
374 				ser.serializeValue!(OriginalType!TU)(cast(OriginalType!TU)value);
375 			}
376 		} else static if (Serializer.isSupportedValueType!TU) {
377 			static if (is(TU == typeof(null))) ser.writeValue!Traits(null);
378 			else ser.writeValue!(Traits, TU)(value);
379 		} else static if (/*isInstanceOf!(Tuple, TU)*/is(T == Tuple!TPS, TPS...)) {
380 			import std.algorithm.searching: all;
381 			static if (all!"!a.empty"([TU.fieldNames]) &&
382 					   !hasPolicyAttributeL!(AsArrayAttribute, Policy, ATTRIBUTES)) {
383 				static if (__traits(compiles, ser.beginWriteDictionary!TU(0))) {
384 					auto nfields = value.length;
385 					ser.beginWriteDictionary!Traits(nfields);
386 				} else {
387 					ser.beginWriteDictionary!Traits();
388 				}
389 				foreach (i, TV; TU.Types) {
390 					alias STraits = SubTraits!(Traits, TV);
391 					ser.beginWriteDictionaryEntry!STraits(underscoreStrip(TU.fieldNames[i]));
392 					ser.serializeValue!(TV, ATTRIBUTES)(value[i]);
393 					ser.endWriteDictionaryEntry!STraits(underscoreStrip(TU.fieldNames[i]));
394 				}
395 				static if (__traits(compiles, ser.endWriteDictionary!TU(0))) {
396 					ser.endWriteDictionary!Traits(nfields);
397 				} else {
398 					ser.endWriteDictionary!Traits();
399 				}
400 			} else static if (TU.Types.length == 1) {
401 				ser.serializeValue!(typeof(value[0]), ATTRIBUTES)(value[0]);
402 			} else {
403 				ser.beginWriteArray!Traits(value.length);
404 				foreach (i, TV; T.Types) {
405 					alias STraits = SubTraits!(Traits, TV);
406 					ser.beginWriteArrayEntry!STraits(i);
407 					ser.serializeValue!(TV, ATTRIBUTES)(value[i]);
408 					ser.endWriteArrayEntry!STraits(i);
409 				}
410 				ser.endWriteArray!Traits();
411 			}
412 		} else static if (isArray!TU) {
413 			alias TV = typeof(value[0]);
414 			alias STraits = SubTraits!(Traits, TV);
415 			ser.beginWriteArray!Traits(value.length);
416 			foreach (i, ref el; value) {
417 				ser.beginWriteArrayEntry!STraits(i);
418 				ser.serializeValue!(TV, ATTRIBUTES)(el);
419 				ser.endWriteArrayEntry!STraits(i);
420 			}
421 			ser.endWriteArray!Traits();
422 		} else static if (isAssociativeArray!TU) {
423 			alias TK = KeyType!TU;
424 			alias TV = ValueType!TU;
425 			alias STraits = SubTraits!(Traits, TV);
426 
427 			static if (__traits(compiles, ser.beginWriteDictionary!TU(0))) {
428 				auto nfields = value.length;
429 				ser.beginWriteDictionary!Traits(nfields);
430 			} else {
431 				ser.beginWriteDictionary!Traits();
432 			}
433 			foreach (key, ref el; value) {
434 				string keyname;
435 				static if (is(TK : string)) keyname = key;
436 				else static if (is(TK : real) || is(TK : long) || is(TK == enum)) keyname = key.to!string;
437 				else static if (isStringSerializable!TK) keyname = key.toString();
438 				else static assert(false, "Associative array keys must be strings, numbers, enums, or have toString/fromString methods.");
439 				ser.beginWriteDictionaryEntry!STraits(keyname);
440 				ser.serializeValue!(TV, ATTRIBUTES)(el);
441 				ser.endWriteDictionaryEntry!STraits(keyname);
442 			}
443 			static if (__traits(compiles, ser.endWriteDictionary!TU(0))) {
444 				ser.endWriteDictionary!Traits(nfields);
445 			} else {
446 				ser.endWriteDictionary!Traits();
447 			}
448 		} else static if (/*isInstanceOf!(Nullable, TU)*/is(T == Nullable!TPS, TPS...)) {
449 			if (value.isNull()) ser.serializeValue!(typeof(null))(null);
450 			else ser.serializeValue!(typeof(value.get()), ATTRIBUTES)(value.get());
451 		} else static if (isInstanceOf!(Typedef, TU)) {
452 			ser.serializeValue!(TypedefType!TU, ATTRIBUTES)(cast(TypedefType!TU)value);
453 		} else static if (is(TU == BitFlags!E, E)) {
454 			alias STraits = SubTraits!(Traits, E);
455 
456 			size_t cnt = 0;
457 			foreach (v; EnumMembers!E)
458 				if (value & v)
459 					cnt++;
460 
461 			ser.beginWriteArray!Traits(cnt);
462 			cnt = 0;
463 			foreach (v; EnumMembers!E)
464 				if (value & v) {
465 					ser.beginWriteArrayEntry!STraits(cnt);
466 					ser.serializeValue!(E, ATTRIBUTES)(v);
467 					ser.endWriteArrayEntry!STraits(cnt);
468 					cnt++;
469 				}
470 			ser.endWriteArray!Traits();
471 		} else static if (isCustomSerializable!TU) {
472 			alias CustomType = typeof(T.init.toRepresentation());
473 			ser.serializeValue!(CustomType, ATTRIBUTES)(value.toRepresentation());
474 		} else static if (isISOExtStringSerializable!TU) {
475 			ser.serializeValue!(string, ATTRIBUTES)(value.toISOExtString());
476 		} else static if (isStringSerializable!TU) {
477 			ser.serializeValue!(string, ATTRIBUTES)(value.toString());
478 		} else static if (is(TU == struct) || is(TU == class)) {
479 			static if (!hasSerializableFields!(TU, Policy))
480 				pragma(msg, "Serializing composite type "~T.stringof~" which has no serializable fields");
481 			static if (is(TU == class)) {
482 				if (value is null) {
483 					ser.serializeValue!(typeof(null))(null);
484 					return;
485 				}
486 			}
487 			static if (hasPolicyAttributeL!(AsArrayAttribute, Policy, ATTRIBUTES)) {
488 				enum nfields = getExpandedFieldCount!(TU, SerializableFields!(TU, Policy));
489 				ser.beginWriteArray!Traits(nfields);
490 				size_t fcount = 0;
491 				foreach (mname; SerializableFields!(TU, Policy)) {
492 					alias TMS = TypeTuple!(typeof(__traits(getMember, value, mname)));
493 					foreach (j, TM; TMS) {
494 						alias TA = TypeTuple!(__traits(getAttributes, TypeTuple!(__traits(getMember, T, mname))[j]));
495 						alias STraits = SubTraits!(Traits, TM, TA);
496 						ser.beginWriteArrayEntry!STraits(fcount);
497 						ser.serializeValue!(TM, TA)(tuple(__traits(getMember, value, mname))[j]);
498 						ser.endWriteArrayEntry!STraits(fcount);
499 						fcount++;
500 					}
501 				}
502 				ser.endWriteArray!Traits();
503 			} else {
504 				static if (__traits(compiles, ser.beginWriteDictionary!Traits(0))) {
505 					enum nfields = getExpandedFieldCount!(TU, SerializableFields!(TU, Policy));
506 					ser.beginWriteDictionary!Traits(nfields);
507 				} else {
508 					ser.beginWriteDictionary!Traits();
509 				}
510 				foreach (mname; SerializableFields!(TU, Policy)) {
511 					alias TM = TypeTuple!(typeof(__traits(getMember, TU, mname)));
512 					alias TA = TypeTuple!(__traits(getAttributes, TypeTuple!(__traits(getMember, T, mname))[0]));
513 					enum name = getPolicyAttribute!(TU, mname, NameAttribute, Policy)(NameAttribute!DefaultPolicy(underscoreStrip(mname))).name;
514 					static if (TM.length == 1) {
515 						auto vt = __traits(getMember, value, mname);
516 					} else {
517 						auto vt = tuple!TM(__traits(getMember, value, mname));
518 					}
519 					alias STraits = SubTraits!(Traits, typeof(vt), TA);
520 					ser.beginWriteDictionaryEntry!STraits(name);
521 					ser.serializeValue!(typeof(vt), TA)(vt);
522 					ser.endWriteDictionaryEntry!STraits(name);
523 				}
524 				static if (__traits(compiles, ser.endWriteDictionary!Traits(0))) {
525 					ser.endWriteDictionary!Traits(nfields);
526 				} else {
527 					ser.endWriteDictionary!Traits();
528 				}
529 			}
530 		} else static if (isPointer!TU) {
531 			if (value is null) {
532 				ser.writeValue!Traits(null);
533 				return;
534 			}
535 			ser.serializeValue!(PointerTarget!TU)(*value);
536 		} else static if (is(TU == bool) || is(TU : real) || is(TU : long)) {
537 			ser.serializeValue!(string, ATTRIBUTES)(to!string(value));
538 		} else static assert(false, "Unsupported serialization type: " ~ T.stringof);
539 	}
540 }
541 
542 private struct Traits(T, alias POL, ATTRIBUTES...)
543 {
544 	alias Type = T;
545 	alias Policy = POL;
546 	alias Attributes = TypeTuple!ATTRIBUTES;
547 }
548 
549 private struct SubTraits(Traits, T, A...)
550 {
551 	alias Type = Unqual!T;
552 	alias Attributes = TypeTuple!A;
553 	alias Policy = Traits.Policy;
554 	alias ContainerType = Traits.Type;
555 	alias ContainerAttributes = Traits.Attributes;
556 }
557 
558 private template deserializeValueImpl(Serializer, alias Policy) {
559 	alias _Policy = Policy;
560 	static assert(Serializer.isSupportedValueType!string, "All serializers must support string values.");
561 	static assert(Serializer.isSupportedValueType!(typeof(null)), "All serializers must support null values.");
562 
563 	// work around https://issues.dlang.org/show_bug.cgi?id=16528
564 	static if (isSafeSerializer!Serializer) {
565 		T deserializeValue(T, ATTRIBUTES...)(ref Serializer ser) @safe { return deserializeValueDeduced!(T, ATTRIBUTES)(ser); }
566 	} else {
567 		T deserializeValue(T, ATTRIBUTES...)(ref Serializer ser) { return deserializeValueDeduced!(T, ATTRIBUTES)(ser); }
568 	}
569 
570 	T deserializeValueDeduced(T, ATTRIBUTES...)(ref Serializer ser) if(!isMutable!T)
571 	{
572 		import std.algorithm.mutation : move;
573 		auto ret = deserializeValue!(Unqual!T, ATTRIBUTES)(ser);
574 		return () @trusted { return cast(T)ret.move; } ();
575 	}
576 
577 	T deserializeValueDeduced(T, ATTRIBUTES...)(ref Serializer ser) if(isMutable!T)
578 	{
579 		import std.typecons : BitFlags, Nullable, Typedef, TypedefType, Tuple;
580 
581 		alias Traits = .Traits!(T, _Policy, ATTRIBUTES);
582 
583 		static if (isPolicySerializable!(Policy, T)) {
584 			alias CustomType = typeof(Policy!T.toRepresentation(T.init));
585 			return Policy!T.fromRepresentation(ser.deserializeValue!(CustomType, ATTRIBUTES));
586 		} else static if (is(T == enum)) {
587 			static if (hasPolicyAttributeL!(ByNameAttribute, Policy, ATTRIBUTES)) {
588 				return ser.deserializeValue!(string, ATTRIBUTES).to!T();
589 			} else {
590 				return cast(T)ser.deserializeValue!(OriginalType!T);
591 			}
592 		} else static if (Serializer.isSupportedValueType!T) {
593 			return ser.readValue!(Traits, T)();
594 		} else static if (/*isInstanceOf!(Tuple, TU)*/is(T == Tuple!TPS, TPS...)) {
595 			enum fieldsCount = T.Types.length;
596 			import std.algorithm.searching: all;
597 			static if (all!"!a.empty"([T.fieldNames]) &&
598 					   !hasPolicyAttributeL!(AsArrayAttribute, Policy, ATTRIBUTES)) {
599 				T ret;
600 				bool[fieldsCount] set;
601 				ser.readDictionary!Traits((name) {
602 					switch (name) {
603 						default: break;
604 						foreach (i, TV; T.Types) {
605 							enum fieldName = underscoreStrip(T.fieldNames[i]);
606 							alias STraits = SubTraits!(Traits, TV);
607 							case fieldName: {
608 								ser.beginReadDictionaryEntry!STraits(fieldName);
609 								ret[i] = ser.deserializeValue!(TV, ATTRIBUTES);
610 								ser.endReadDictionaryEntry!STraits(fieldName);
611 								set[i] = true;
612 							} break;
613 						}
614 					}
615 				});
616 				foreach (i, fieldName; T.fieldNames)
617 					enforce(set[i], "Missing tuple field '"~fieldName~"' of type '"~T.Types[i].stringof~"' ("~Policy.stringof~").");
618 				return ret;
619 			} else static if (fieldsCount == 1) {
620 				return T(ser.deserializeValue!(T.Types[0], ATTRIBUTES)());
621 			} else {
622 				T ret;
623 				size_t currentField = 0;
624 				ser.readArray!Traits((sz) { assert(sz == 0 || sz == fieldsCount); }, {
625 					switch (currentField++) {
626 						default: break;
627 						foreach (i, TV; T.Types) {
628 							alias STraits = SubTraits!(Traits, TV);
629 							case i: {
630 								ser.beginReadArrayEntry!STraits(i);
631 								ret[i] = ser.deserializeValue!(TV, ATTRIBUTES);
632 								ser.endReadArrayEntry!STraits(i);
633 							} break;
634 						}
635 					}
636 				});
637 				enforce(currentField == fieldsCount, "Missing tuple field(s) - expected '"~fieldsCount.stringof~"', received '"~currentField.stringof~"' ("~Policy.stringof~").");
638 				return ret;
639 			}
640 		} else static if (isStaticArray!T) {
641 			alias TV = typeof(T.init[0]);
642 			alias STraits = SubTraits!(Traits, TV);
643 			T ret;
644 			size_t i = 0;
645 			ser.readArray!Traits((sz) { assert(sz == 0 || sz == T.length); }, {
646 				assert(i < T.length);
647 				ser.beginReadArrayEntry!STraits(i);
648 				ret[i] = ser.deserializeValue!(TV, ATTRIBUTES);
649 				ser.endReadArrayEntry!STraits(i);
650 				i++;
651 			});
652 			return ret;
653 		} else static if (isDynamicArray!T) {
654 			alias TV = typeof(T.init[0]);
655 			alias STraits = SubTraits!(Traits, TV);
656 			//auto ret = appender!T();
657 			T ret; // Cannot use appender because of DMD BUG 10690/10859/11357
658 			ser.readArray!Traits((sz) @safe { ret.reserve(sz); }, () @safe {
659 				size_t i = ret.length;
660 				ser.beginReadArrayEntry!STraits(i);
661 				static if (__traits(compiles, () @safe { ser.deserializeValue!(TV, ATTRIBUTES); }))
662 					ret ~= ser.deserializeValue!(TV, ATTRIBUTES);
663 				else // recursive array https://issues.dlang.org/show_bug.cgi?id=16528
664 					ret ~= (() @trusted => ser.deserializeValue!(TV, ATTRIBUTES))();
665 				ser.endReadArrayEntry!STraits(i);
666 			});
667 			return ret;//cast(T)ret.data;
668 		} else static if (isAssociativeArray!T) {
669 			alias TK = KeyType!T;
670 			alias TV = ValueType!T;
671 			alias STraits = SubTraits!(Traits, TV);
672 
673 			T ret;
674 			ser.readDictionary!Traits((name) @safe {
675 				TK key;
676 				static if (is(TK == string) || (is(TK == enum) && is(OriginalType!TK == string))) key = cast(TK)name;
677 				else static if (is(TK : real) || is(TK : long) || is(TK == enum)) key = name.to!TK;
678 				else static if (isStringSerializable!TK) key = TK.fromString(name);
679 				else static assert(false, "Associative array keys must be strings, numbers, enums, or have toString/fromString methods.");
680 				ser.beginReadDictionaryEntry!STraits(name);
681 				ret[key] = ser.deserializeValue!(TV, ATTRIBUTES);
682 				ser.endReadDictionaryEntry!STraits(name);
683 			});
684 			return ret;
685 		} else static if (isInstanceOf!(Nullable, T)) {
686 			if (ser.tryReadNull!Traits()) return T.init;
687 			return T(ser.deserializeValue!(typeof(T.init.get()), ATTRIBUTES));
688 		} else static if (isInstanceOf!(Typedef, T)) {
689 			return T(ser.deserializeValue!(TypedefType!T, ATTRIBUTES));
690 		} else static if (is(T == BitFlags!E, E)) {
691 			alias STraits = SubTraits!(Traits, E);
692 			T ret;
693 			size_t i = 0;
694 			ser.readArray!Traits((sz) {}, {
695 				ser.beginReadArrayEntry!STraits(i);
696 				ret |= ser.deserializeValue!(E, ATTRIBUTES);
697 				ser.endReadArrayEntry!STraits(i);
698 				i++;
699 			});
700 			return ret;
701 		} else static if (isCustomSerializable!T) {
702 			alias CustomType = typeof(T.init.toRepresentation());
703 			return T.fromRepresentation(ser.deserializeValue!(CustomType, ATTRIBUTES));
704 		} else static if (isISOExtStringSerializable!T) {
705 			return T.fromISOExtString(ser.readValue!(Traits, string)());
706 		} else static if (isStringSerializable!T) {
707 			return T.fromString(ser.readValue!(Traits, string)());
708 		} else static if (is(T == struct) || is(T == class)) {
709 			static if (is(T == class)) {
710 				if (ser.tryReadNull!Traits()) return null;
711 			}
712 
713 			T ret;
714 			string name;
715 			bool[getExpandedFieldsData!(T, SerializableFields!(T, Policy)).length] set;
716 			static if (is(T == class)) ret = new T;
717 
718 			static if (hasPolicyAttributeL!(AsArrayAttribute, Policy, ATTRIBUTES)) {
719 				size_t idx = 0;
720 				ser.readArray!Traits((sz){}, {
721 					static if (hasSerializableFields!(T, Policy)) {
722 						switch (idx++) {
723 							default: break;
724 							foreach (i, FD; getExpandedFieldsData!(T, SerializableFields!(T, Policy))) {
725 								enum mname = FD[0];
726 								enum msindex = FD[1];
727 								alias MT = TypeTuple!(__traits(getMember, T, mname));
728 								alias MTI = MT[msindex];
729 								alias TMTI = typeof(MTI);
730 								alias TMTIA = TypeTuple!(__traits(getAttributes, MTI));
731 								alias STraits = SubTraits!(Traits, TMTI, TMTIA);
732 
733 							case i:
734 								static if (hasPolicyAttribute!(OptionalAttribute, Policy, MTI))
735 									if (ser.tryReadNull!STraits()) return;
736 								set[i] = true;
737 								ser.beginReadArrayEntry!STraits(i);
738 								static if (MT.length == 1) {
739 									__traits(getMember, ret, mname) = ser.deserializeValue!(TMTI, TMTIA);
740 								} else {
741 									__traits(getMember, ret, mname)[msindex] = ser.deserializeValue!(TMTI, TMTIA);
742 								}
743 								ser.endReadArrayEntry!STraits(i);
744 								break;
745 							}
746 						}
747 					} else {
748 						pragma(msg, "Deserializing composite type "~T.stringof~" which has no serializable fields.");
749 					}
750 				});
751 			} else {
752 				ser.readDictionary!Traits((name) {
753 					static if (hasSerializableFields!(T, Policy)) {
754 						switch (name) {
755 							default: break;
756 							foreach (i, mname; SerializableFields!(T, Policy)) {
757 								alias TM = TypeTuple!(typeof(__traits(getMember, T, mname)));
758 								alias TA = TypeTuple!(__traits(getAttributes, TypeTuple!(__traits(getMember, T, mname))[0]));
759 								alias STraits = SubTraits!(Traits, TM, TA);
760 								enum fname = getPolicyAttribute!(T, mname, NameAttribute, Policy)(NameAttribute!DefaultPolicy(underscoreStrip(mname))).name;
761 								case fname:
762 									static if (hasPolicyAttribute!(OptionalAttribute, Policy, TypeTuple!(__traits(getMember, T, mname))[0]))
763 										if (ser.tryReadNull!STraits()) return;
764 									set[i] = true;
765 									ser.beginReadDictionaryEntry!STraits(fname);
766 									static if (TM.length == 1) {
767 										__traits(getMember, ret, mname) = ser.deserializeValue!(TM, TA);
768 									} else {
769 										__traits(getMember, ret, mname) = ser.deserializeValue!(Tuple!TM, TA);
770 									}
771 									ser.endReadDictionaryEntry!STraits(fname);
772 									break;
773 							}
774 						}
775 					} else {
776 						pragma(msg, "Deserializing composite type "~T.stringof~" which has no serializable fields.");
777 					}
778 				});
779 			}
780 			foreach (i, mname; SerializableFields!(T, Policy))
781 				static if (!hasPolicyAttribute!(OptionalAttribute, Policy, TypeTuple!(__traits(getMember, T, mname))[0]))
782 					enforce(set[i], "Missing non-optional field '"~mname~"' of type '"~T.stringof~"' ("~Policy.stringof~").");
783 			return ret;
784 		} else static if (isPointer!T) {
785 			if (ser.tryReadNull!Traits()) return null;
786 			alias PT = PointerTarget!T;
787 			auto ret = new PT;
788 			*ret = ser.deserializeValue!(PT, ATTRIBUTES);
789 			return ret;
790 		} else static if (is(T == bool) || is(T : real) || is(T : long)) {
791 			return to!T(ser.deserializeValue!string());
792 		} else static assert(false, "Unsupported serialization type: " ~ T.stringof);
793 	}
794 }
795 
796 
797 /**
798 	Attribute for overriding the field name during (de-)serialization.
799 
800 	Note that without the `@name` attribute there is a shorter alternative
801 	for using names that collide with a D keyword. A single trailing
802 	underscore will automatically be stripped when determining a field
803 	name.
804 */
805 NameAttribute!Policy name(alias Policy = DefaultPolicy)(string name)
806 {
807 	return NameAttribute!Policy(name);
808 }
809 ///
810 unittest {
811 	struct CustomPolicy {}
812 
813 	struct Test {
814 		// serialized as "screen-size":
815 		@name("screen-size") int screenSize;
816 
817 		// serialized as "print-size" by default,
818 		// but as "PRINTSIZE" if CustomPolicy is used for serialization.
819 		@name("print-size")
820 		@name!CustomPolicy("PRINTSIZE")
821 		int printSize;
822 
823 		// serialized as "version"
824 		int version_;
825 	}
826 }
827 
828 
829 /**
830 	Attribute marking a field as optional during deserialization.
831 */
832 @property OptionalAttribute!Policy optional(alias Policy = DefaultPolicy)()
833 {
834 	return OptionalAttribute!Policy();
835 }
836 ///
837 unittest {
838 	struct Test {
839 		// does not need to be present during deserialization
840 		@optional int screenSize = 100;
841 	}
842 }
843 
844 
845 /**
846 	Attribute for marking non-serialized fields.
847 */
848 @property IgnoreAttribute!Policy ignore(alias Policy = DefaultPolicy)()
849 {
850 	return IgnoreAttribute!Policy();
851 }
852 ///
853 unittest {
854 	struct Test {
855 		// is neither serialized not deserialized
856 		@ignore int screenSize;
857 	}
858 }
859 ///
860 unittest {
861 	template CustomPolicy(T) {
862 		// ...
863 	}
864 
865 	struct Test {
866 		// not (de)serialized for serializeWithPolicy!(Test, CustomPolicy)
867 		// but for other policies or when serialized without a policy
868 		@ignore!CustomPolicy int screenSize;
869 	}
870 }
871 
872 
873 /**
874 	Attribute for forcing serialization of enum fields by name instead of by value.
875 */
876 @property ByNameAttribute!Policy byName(alias Policy = DefaultPolicy)()
877 {
878 	return ByNameAttribute!Policy();
879 }
880 ///
881 unittest {
882 	enum Color {
883 		red,
884 		green,
885 		blue
886 	}
887 
888 	struct Test {
889 		// serialized as an int (e.g. 1 for Color.green)
890 		Color color;
891 		// serialized as a string (e.g. "green" for Color.green)
892 		@byName Color namedColor;
893 		// serialized as array of ints
894 		Color[] colorArray;
895 		// serialized as array of strings
896 		@byName Color[] namedColorArray;
897 	}
898 }
899 
900 
901 /**
902 	Attribute for representing a struct/class as an array instead of an object.
903 
904 	Usually structs and class objects are serialized as dictionaries mapping
905 	from field name to value. Using this attribute, they will be serialized
906 	as a flat array instead. Note that changing the layout will make any
907 	already serialized data mismatch when this attribute is used.
908 */
909 @property AsArrayAttribute!Policy asArray(alias Policy = DefaultPolicy)()
910 {
911 	return AsArrayAttribute!Policy();
912 }
913 ///
914 unittest {
915 	struct Fields {
916 		int f1;
917 		string f2;
918 		double f3;
919 	}
920 
921 	struct Test {
922 		// serialized as name:value pairs ["f1": int, "f2": string, "f3": double]
923 		Fields object;
924 		// serialized as a sequential list of values [int, string, double]
925 		@asArray Fields array;
926 	}
927 
928 	import vibe.data.json;
929 	static assert(is(typeof(serializeToJson(Test()))));
930 }
931 
932 
933 ///
934 enum FieldExistence
935 {
936 	missing,
937 	exists,
938 	defer
939 }
940 
941 /// User defined attribute (not intended for direct use)
942 struct NameAttribute(alias POLICY) { alias Policy = POLICY; string name; }
943 /// ditto
944 struct OptionalAttribute(alias POLICY) { alias Policy = POLICY; }
945 /// ditto
946 struct IgnoreAttribute(alias POLICY) { alias Policy = POLICY; }
947 /// ditto
948 struct ByNameAttribute(alias POLICY) { alias Policy = POLICY; }
949 /// ditto
950 struct AsArrayAttribute(alias POLICY) { alias Policy = POLICY; }
951 
952 /**
953 	Checks if a given type has a custom serialization representation.
954 
955 	A class or struct type is custom serializable if it defines a pair of
956 	`toRepresentation`/`fromRepresentation` methods. Any class or
957 	struct type that has this trait will be serialized by using the return
958 	value of it's `toRepresentation` method instead of the original value.
959 
960 	This trait has precedence over `isISOExtStringSerializable` and
961 	`isStringSerializable`.
962 */
963 template isCustomSerializable(T)
964 {
965 	enum bool isCustomSerializable = is(typeof(T.init.toRepresentation())) && is(typeof(T.fromRepresentation(T.init.toRepresentation())) == T);
966 }
967 ///
968 unittest {
969 	// represented as a single uint when serialized
970 	static struct S {
971 		ushort x, y;
972 
973 		uint toRepresentation() const { return x + (y << 16); }
974 		static S fromRepresentation(uint i) { return S(i & 0xFFFF, i >> 16); }
975 	}
976 
977 	static assert(isCustomSerializable!S);
978 }
979 
980 
981 /**
982 	Checks if a given type has an ISO extended string serialization representation.
983 
984 	A class or struct type is ISO extended string serializable if it defines a
985 	pair of `toISOExtString`/`fromISOExtString` methods. Any class or
986 	struct type that has this trait will be serialized by using the return
987 	value of it's `toISOExtString` method instead of the original value.
988 
989 	This is mainly useful for supporting serialization of the the date/time
990 	types in `std.datetime`.
991 
992 	This trait has precedence over `isStringSerializable`.
993 */
994 template isISOExtStringSerializable(T)
995 {
996 	enum bool isISOExtStringSerializable = is(typeof(T.init.toISOExtString()) == string) && is(typeof(T.fromISOExtString("")) == T);
997 }
998 ///
999 unittest {
1000 	import std.datetime;
1001 
1002 	static assert(isISOExtStringSerializable!DateTime);
1003 	static assert(isISOExtStringSerializable!SysTime);
1004 
1005 	// represented as an ISO extended string when serialized
1006 	static struct S {
1007 		// dummy example implementations
1008 		string toISOExtString() const { return ""; }
1009 		static S fromISOExtString(string s) { return S.init; }
1010 	}
1011 
1012 	static assert(isISOExtStringSerializable!S);
1013 }
1014 
1015 
1016 /**
1017 	Checks if a given type has a string serialization representation.
1018 
1019 	A class or struct type is string serializable if it defines a pair of
1020 	`toString`/`fromString` methods. Any class or struct type that
1021 	has this trait will be serialized by using the return value of it's
1022 	`toString` method instead of the original value.
1023 */
1024 template isStringSerializable(T)
1025 {
1026 	enum bool isStringSerializable = is(typeof(T.init.toString()) == string) && is(typeof(T.fromString("")) == T);
1027 }
1028 ///
1029 unittest {
1030 	import std.conv;
1031 
1032 	// represented as a string when serialized
1033 	static struct S {
1034 		int value;
1035 
1036 		// dummy example implementations
1037 		string toString() const { return value.to!string(); }
1038 		static S fromString(string s) { return S(s.to!int()); }
1039 	}
1040 
1041 	static assert(isStringSerializable!S);
1042 }
1043 
1044 
1045 /** Default policy (performs no customization).
1046 */
1047 template DefaultPolicy(T)
1048 {
1049 }
1050 
1051 /**
1052 	Checks if a given policy supports custom serialization for a given type.
1053 
1054 	A class or struct type is custom serializable according to a policy if
1055 	the policy defines a pair of `toRepresentation`/`fromRepresentation`
1056 	functions. Any class or struct type that has this trait for the policy supplied to
1057 	`serializeWithPolicy` will be serialized by using the return value of the
1058 	policy `toRepresentation` function instead of the original value.
1059 
1060 	This trait has precedence over `isCustomSerializable`,
1061 	`isISOExtStringSerializable` and `isStringSerializable`.
1062 
1063 	See_Also: `vibe.data.serialization.serializeWithPolicy`
1064 */
1065 template isPolicySerializable(alias Policy, T)
1066 {
1067 	enum bool isPolicySerializable = is(typeof(Policy!T.toRepresentation(T.init))) &&
1068 		is(typeof(Policy!T.fromRepresentation(Policy!T.toRepresentation(T.init))) == T);
1069 }
1070 ///
1071 unittest {
1072 	import std.conv;
1073 
1074 	// represented as the boxed value when serialized
1075 	static struct Box(T) {
1076 		T value;
1077 	}
1078 
1079 	template BoxPol(S)
1080 	{
1081 		auto toRepresentation(S s) {
1082 			return s.value;
1083 		}
1084 
1085 		S fromRepresentation(typeof(S.init.value) v) {
1086 			return S(v);
1087 		}
1088 	}
1089 	static assert(isPolicySerializable!(BoxPol, Box!int));
1090 }
1091 
1092 
1093 /**
1094 	Chains serialization policy.
1095 
1096 	Constructs a serialization policy that given a type `T` will apply the
1097 	first compatible policy `toRepresentation` and `fromRepresentation`
1098 	functions. Policies are evaluated left-to-right according to
1099 	`isPolicySerializable`.
1100 
1101 	See_Also: `vibe.data.serialization.serializeWithPolicy`
1102 */
1103 template ChainedPolicy(alias Primary, Fallbacks...)
1104 {
1105 	static if (Fallbacks.length == 0) {
1106 		alias ChainedPolicy = Primary;
1107 	} else {
1108 		alias ChainedPolicy = ChainedPolicy!(ChainedPolicyImpl!(Primary, Fallbacks[0]), Fallbacks[1..$]);
1109 	}
1110 }
1111 ///
1112 unittest {
1113 	import std.conv;
1114 
1115 	// To be represented as the boxed value when serialized
1116 	static struct Box(T) {
1117 		T value;
1118 	}
1119 	// Also to berepresented as the boxed value when serialized, but has
1120 	// a different way to access the value.
1121 	static struct Box2(T) {
1122 		private T v;
1123 		ref T get() {
1124 			return v;
1125 		}
1126 	}
1127 	template BoxPol(S)
1128 	{
1129 		auto toRepresentation(S s) {
1130 			return s.value;
1131 		}
1132 
1133 		S fromRepresentation(typeof(toRepresentation(S.init)) v) {
1134 			return S(v);
1135 		}
1136 	}
1137 	template Box2Pol(S)
1138 	{
1139 		auto toRepresentation(S s) {
1140 			return s.get();
1141 		}
1142 
1143 		S fromRepresentation(typeof(toRepresentation(S.init)) v) {
1144 			S s;
1145 			s.get() = v;
1146 			return s;
1147 		}
1148 	}
1149 	alias ChainPol = ChainedPolicy!(BoxPol, Box2Pol);
1150 	static assert(!isPolicySerializable!(BoxPol, Box2!int));
1151 	static assert(!isPolicySerializable!(Box2Pol, Box!int));
1152 	static assert(isPolicySerializable!(ChainPol, Box!int));
1153 	static assert(isPolicySerializable!(ChainPol, Box2!int));
1154 }
1155 
1156 private template ChainedPolicyImpl(alias Primary, alias Fallback)
1157 {
1158 	template Pol(T)
1159 	{
1160 		static if (isPolicySerializable!(Primary, T)) {
1161 			alias toRepresentation = Primary!T.toRepresentation;
1162 			alias fromRepresentation = Primary!T.fromRepresentation;
1163 		} else {
1164 			alias toRepresentation = Fallback!T.toRepresentation;
1165 			alias fromRepresentation = Fallback!T.fromRepresentation;
1166 		}
1167 	}
1168 	alias ChainedPolicyImpl = Pol;
1169 }
1170 
1171 // heuristically determines @safe'ty of the serializer by testing readValue and writeValue for type int
1172 private enum isSafeSerializer(S) = __traits(compiles, (S s) @safe {
1173 	alias T = Traits!(int, DefaultPolicy);
1174 	s.writeValue!T(42);
1175 	s.readValue!(T, int)();
1176 });
1177 
1178 private template hasAttribute(T, alias decl) { enum hasAttribute = findFirstUDA!(T, decl).found; }
1179 
1180 unittest {
1181 	@asArray int i1;
1182 	static assert(hasAttribute!(AsArrayAttribute!DefaultPolicy, i1));
1183 	int i2;
1184 	static assert(!hasAttribute!(AsArrayAttribute!DefaultPolicy, i2));
1185 }
1186 
1187 private template hasPolicyAttribute(alias T, alias POLICY, alias decl)
1188 {
1189 	enum hasPolicyAttribute = hasAttribute!(T!POLICY, decl) || hasAttribute!(T!DefaultPolicy, decl);
1190 }
1191 
1192 unittest {
1193 	template CP(T) {}
1194 	@asArray!CP int i1;
1195 	@asArray int i2;
1196 	int i3;
1197 	static assert(hasPolicyAttribute!(AsArrayAttribute, CP, i1));
1198 	static assert(hasPolicyAttribute!(AsArrayAttribute, CP, i2));
1199 	static assert(!hasPolicyAttribute!(AsArrayAttribute, CP, i3));
1200 	static assert(!hasPolicyAttribute!(AsArrayAttribute, DefaultPolicy, i1));
1201 	static assert(hasPolicyAttribute!(AsArrayAttribute, DefaultPolicy, i2));
1202 	static assert(!hasPolicyAttribute!(AsArrayAttribute, DefaultPolicy, i3));
1203 }
1204 
1205 
1206 private template hasAttributeL(T, ATTRIBUTES...) {
1207 	static if (ATTRIBUTES.length == 1) {
1208 		enum hasAttributeL = is(typeof(ATTRIBUTES[0]) == T);
1209 	} else static if (ATTRIBUTES.length > 1) {
1210 		enum hasAttributeL = hasAttributeL!(T, ATTRIBUTES[0 .. $/2]) || hasAttributeL!(T, ATTRIBUTES[$/2 .. $]);
1211 	} else {
1212 		enum hasAttributeL = false;
1213 	}
1214 }
1215 
1216 unittest {
1217 	static assert(hasAttributeL!(AsArrayAttribute!DefaultPolicy, byName, asArray));
1218 	static assert(!hasAttributeL!(AsArrayAttribute!DefaultPolicy, byName));
1219 }
1220 
1221 private template hasPolicyAttributeL(alias T, alias POLICY, ATTRIBUTES...)
1222 {
1223 	enum hasPolicyAttributeL = hasAttributeL!(T!POLICY, ATTRIBUTES) || hasAttributeL!(T!DefaultPolicy, ATTRIBUTES);
1224 }
1225 
1226 private static T getAttribute(TT, string mname, T)(T default_value)
1227 {
1228 	enum val = findFirstUDA!(T, __traits(getMember, TT, mname));
1229 	static if (val.found) return val.value;
1230 	else return default_value;
1231 }
1232 
1233 private static auto getPolicyAttribute(TT, string mname, alias Attribute, alias Policy)(Attribute!DefaultPolicy default_value)
1234 {
1235 	enum val = findFirstUDA!(Attribute!Policy, TypeTuple!(__traits(getMember, TT, mname))[0]);
1236 	static if (val.found) return val.value;
1237 	else {
1238 		enum val2 = findFirstUDA!(Attribute!DefaultPolicy, TypeTuple!(__traits(getMember, TT, mname))[0]);
1239 		static if (val2.found) return val2.value;
1240 		else return default_value;
1241 	}
1242 }
1243 
1244 private string underscoreStrip(string field_name)
1245 @safe nothrow @nogc {
1246 	if( field_name.length < 1 || field_name[$-1] != '_' ) return field_name;
1247 	else return field_name[0 .. $-1];
1248 }
1249 
1250 
1251 private template hasSerializableFields(T, alias POLICY, size_t idx = 0)
1252 {
1253 	enum hasSerializableFields = SerializableFields!(T, POLICY).length > 0;
1254 	/*static if (idx < __traits(allMembers, T).length) {
1255 		enum mname = __traits(allMembers, T)[idx];
1256 		static if (!isRWPlainField!(T, mname) && !isRWField!(T, mname)) enum hasSerializableFields = hasSerializableFields!(T, idx+1);
1257 		else static if (hasAttribute!(IgnoreAttribute, __traits(getMember, T, mname))) enum hasSerializableFields = hasSerializableFields!(T, idx+1);
1258 		else enum hasSerializableFields = true;
1259 	} else enum hasSerializableFields = false;*/
1260 }
1261 
1262 private template SerializableFields(COMPOSITE, alias POLICY)
1263 {
1264 	alias SerializableFields = FilterSerializableFields!(COMPOSITE, POLICY, __traits(allMembers, COMPOSITE));
1265 }
1266 
1267 private template FilterSerializableFields(COMPOSITE, alias POLICY, FIELDS...)
1268 {
1269 	static if (FIELDS.length > 1) {
1270 		alias FilterSerializableFields = TypeTuple!(
1271 			FilterSerializableFields!(COMPOSITE, POLICY, FIELDS[0 .. $/2]),
1272 			FilterSerializableFields!(COMPOSITE, POLICY, FIELDS[$/2 .. $]));
1273 	} else static if (FIELDS.length == 1) {
1274 		alias T = COMPOSITE;
1275 		enum mname = FIELDS[0];
1276 		static if (isRWPlainField!(T, mname) || isRWField!(T, mname)) {
1277 			alias Tup = TypeTuple!(__traits(getMember, COMPOSITE, FIELDS[0]));
1278 			static if (Tup.length != 1) {
1279 				alias FilterSerializableFields = TypeTuple!(mname);
1280 			} else {
1281 				static if (!hasPolicyAttribute!(IgnoreAttribute, POLICY, __traits(getMember, T, mname)))
1282 				{
1283 					alias FilterSerializableFields = TypeTuple!(mname);
1284 				} else alias FilterSerializableFields = TypeTuple!();
1285 			}
1286 		} else alias FilterSerializableFields = TypeTuple!();
1287 	} else alias FilterSerializableFields = TypeTuple!();
1288 }
1289 
1290 private size_t getExpandedFieldCount(T, FIELDS...)()
1291 {
1292 	size_t ret = 0;
1293 	foreach (F; FIELDS) ret += TypeTuple!(__traits(getMember, T, F)).length;
1294 	return ret;
1295 }
1296 
1297 private template getExpandedFieldsData(T, FIELDS...)
1298 {
1299 	import std.meta : aliasSeqOf, staticMap;
1300 	import std.range : repeat, zip, iota;
1301 
1302 	enum subfieldsCount(alias F) = TypeTuple!(__traits(getMember, T, F)).length;
1303 	alias processSubfield(alias F) = aliasSeqOf!(zip(repeat(F), iota(subfieldsCount!F)));
1304 	alias getExpandedFieldsData = staticMap!(processSubfield, FIELDS);
1305 }
1306 
1307 /******************************************************************************/
1308 /* General serialization unit testing                                         */
1309 /******************************************************************************/
1310 
1311 version (unittest) {
1312 	static assert(isSafeSerializer!TestSerializer);
1313 
1314 	private struct TestSerializer {
1315 		import std.array, std.conv, std.string;
1316 
1317 		string result;
1318 
1319 		enum isSupportedValueType(T) = is(T == string) || is(T == typeof(null)) || is(T == float) || is (T == int);
1320 
1321 		string getSerializedResult() @safe { return result; }
1322 		void beginWriteDictionary(Traits)() { result ~= "D("~Traits.Type.mangleof~"){"; }
1323 		void endWriteDictionary(Traits)() { result ~= "}D("~Traits.Type.mangleof~")"; }
1324 		void beginWriteDictionaryEntry(Traits)(string name) { result ~= "DE("~Traits.Type.mangleof~","~name~")("; }
1325 		void endWriteDictionaryEntry(Traits)(string name) { result ~= ")DE("~Traits.Type.mangleof~","~name~")"; }
1326 		void beginWriteArray(Traits)(size_t length) { result ~= "A("~Traits.Type.mangleof~")["~length.to!string~"]["; }
1327 		void endWriteArray(Traits)() { result ~= "]A("~Traits.Type.mangleof~")"; }
1328 		void beginWriteArrayEntry(Traits)(size_t i) { result ~= "AE("~Traits.Type.mangleof~","~i.to!string~")("; }
1329 		void endWriteArrayEntry(Traits)(size_t i) { result ~= ")AE("~Traits.Type.mangleof~","~i.to!string~")"; }
1330 		void writeValue(Traits, T)(T value) {
1331 			if (is(T == typeof(null))) result ~= "null";
1332 			else {
1333 				assert(isSupportedValueType!T);
1334 				result ~= "V("~T.mangleof~")("~value.to!string~")";
1335 			}
1336 		}
1337 
1338 		// deserialization
1339 		void readDictionary(Traits)(scope void delegate(string) @safe entry_callback)
1340 		{
1341 			skip("D("~Traits.Type.mangleof~"){");
1342 			while (result.startsWith("DE(")) {
1343 				result = result[3 .. $];
1344 				auto idx = result.indexOf(',');
1345 				auto idx2 = result.indexOf(")(");
1346 				assert(idx > 0 && idx2 > idx);
1347 				auto t = result[0 .. idx];
1348 				auto n = result[idx+1 .. idx2];
1349 				result = result[idx2+2 .. $];
1350 				entry_callback(n);
1351 				skip(")DE("~t~","~n~")");
1352 			}
1353 			skip("}D("~Traits.Type.mangleof~")");
1354 		}
1355 
1356 		void beginReadDictionaryEntry(Traits)(string name) {}
1357 		void endReadDictionaryEntry(Traits)(string name) {}
1358 
1359 		void readArray(Traits)(scope void delegate(size_t) @safe size_callback, scope void delegate() @safe entry_callback)
1360 		{
1361 			skip("A("~Traits.Type.mangleof~")[");
1362 			auto bidx = result.indexOf("][");
1363 			assert(bidx > 0);
1364 			auto cnt = result[0 .. bidx].to!size_t;
1365 			result = result[bidx+2 .. $];
1366 
1367 			size_t i = 0;
1368 			while (result.startsWith("AE(")) {
1369 				result = result[3 .. $];
1370 				auto idx = result.indexOf(',');
1371 				auto idx2 = result.indexOf(")(");
1372 				assert(idx > 0 && idx2 > idx);
1373 				auto t = result[0 .. idx];
1374 				auto n = result[idx+1 .. idx2];
1375 				result = result[idx2+2 .. $];
1376 				assert(n == i.to!string);
1377 				entry_callback();
1378 				skip(")AE("~t~","~n~")");
1379 				i++;
1380 			}
1381 			skip("]A("~Traits.Type.mangleof~")");
1382 
1383 			assert(i == cnt);
1384 		}
1385 
1386 		void beginReadArrayEntry(Traits)(size_t index) {}
1387 		void endReadArrayEntry(Traits)(size_t index) {}
1388 
1389 		T readValue(Traits, T)()
1390 		{
1391 			skip("V("~T.mangleof~")(");
1392 			auto idx = result.indexOf(')');
1393 			assert(idx >= 0);
1394 			auto ret = result[0 .. idx].to!T;
1395 			result = result[idx+1 .. $];
1396 			return ret;
1397 		}
1398 
1399 		void skip(string prefix)
1400 		@safe {
1401 			assert(result.startsWith(prefix), prefix ~ " vs. " ~result);
1402 			result = result[prefix.length .. $];
1403 		}
1404 
1405 		bool tryReadNull(Traits)()
1406 		{
1407 			if (result.startsWith("null")) {
1408 				result = result[4 .. $];
1409 				return true;
1410 			} else return false;
1411 		}
1412 	}
1413 }
1414 
1415 unittest { // basic serialization behavior
1416 	import std.typecons : Nullable;
1417 
1418 	static void test(T)(T value, string expected) {
1419 		assert(serialize!TestSerializer(value) == expected, serialize!TestSerializer(value));
1420 		static if (isPointer!T) {
1421 			if (value) assert(*deserialize!(TestSerializer, T)(expected) == *value);
1422 			else assert(deserialize!(TestSerializer, T)(expected) is null);
1423 		} else static if (is(T == Nullable!U, U)) {
1424 			if (value.isNull()) assert(deserialize!(TestSerializer, T)(expected).isNull);
1425 			else assert(deserialize!(TestSerializer, T)(expected) == value);
1426 		} else assert(deserialize!(TestSerializer, T)(expected) == value);
1427 	}
1428 
1429 	test("hello", "V(Aya)(hello)");
1430 	test(12, "V(i)(12)");
1431 	test(12.0, "V(Aya)(12)");
1432 	test(12.0f, "V(f)(12)");
1433 	assert(serialize!TestSerializer(null) ==  "null");
1434 	test(["hello", "world"], "A(AAya)[2][AE(Aya,0)(V(Aya)(hello))AE(Aya,0)AE(Aya,1)(V(Aya)(world))AE(Aya,1)]A(AAya)");
1435 	string mangleOfAA = (string[string]).mangleof;
1436 	test(["hello": "world"], "D(" ~ mangleOfAA ~ "){DE(Aya,hello)(V(Aya)(world))DE(Aya,hello)}D(" ~ mangleOfAA ~ ")");
1437 	test(cast(int*)null, "null");
1438 	int i = 42;
1439 	test(&i, "V(i)(42)");
1440 	Nullable!int j;
1441 	test(j, "null");
1442 	j = 42;
1443 	test(j, "V(i)(42)");
1444 }
1445 
1446 unittest { // basic user defined types
1447 	static struct S { string f; }
1448 	enum Sm = S.mangleof;
1449 	auto s = S("hello");
1450 	enum s_ser = "D("~Sm~"){DE(Aya,f)(V(Aya)(hello))DE(Aya,f)}D("~Sm~")";
1451 	assert(serialize!TestSerializer(s) == s_ser, serialize!TestSerializer(s));
1452 	assert(deserialize!(TestSerializer, S)(s_ser) == s);
1453 
1454 	static class C { string f; }
1455 	enum Cm = C.mangleof;
1456 	C c;
1457 	assert(serialize!TestSerializer(c) == "null");
1458 	c = new C;
1459 	c.f = "hello";
1460 	enum c_ser = "D("~Cm~"){DE(Aya,f)(V(Aya)(hello))DE(Aya,f)}D("~Cm~")";
1461 	assert(serialize!TestSerializer(c) == c_ser);
1462 	assert(deserialize!(TestSerializer, C)(c_ser).f == c.f);
1463 
1464 	enum E { hello, world }
1465 	assert(serialize!TestSerializer(E.hello) == "V(i)(0)");
1466 	assert(serialize!TestSerializer(E.world) == "V(i)(1)");
1467 }
1468 
1469 unittest { // tuple serialization
1470 	import std.typecons : Tuple;
1471 
1472 	static struct S(T...) { T f; }
1473 	enum Sm = S!(int, string).mangleof;
1474 	enum Tum = Tuple!(int, string).mangleof;
1475 	const s = S!(int, string)(42, "hello");
1476 
1477 	const ss = serialize!TestSerializer(s);
1478 	const es = "D("~Sm~"){DE("~Tum~",f)(A("~Tum~")[2][AE(i,0)(V(i)(42))AE(i,0)AE(Aya,1)(V(Aya)(hello))AE(Aya,1)]A("~Tum~"))DE("~Tum~",f)}D("~Sm~")";
1479 	assert(ss == es);
1480 
1481 	const dss = deserialize!(TestSerializer, typeof(s))(ss);
1482 	assert(dss == s);
1483 
1484 	static struct T { @asArray S!(int, string) g; }
1485 	enum Tm = T.mangleof;
1486 	const t = T(s);
1487 
1488 	const st = serialize!TestSerializer(t);
1489 	const et = "D("~Tm~"){DE("~Sm~",g)(A("~Sm~")[2][AE(i,0)(V(i)(42))AE(i,0)AE(Aya,1)(V(Aya)(hello))AE(Aya,1)]A("~Sm~"))DE("~Sm~",g)}D("~Tm~")";
1490 	assert(st == et);
1491 
1492 	const dst = deserialize!(TestSerializer, typeof(t))(st);
1493 	assert(dst == t);
1494 }
1495 
1496 unittest { // named tuple serialization
1497 	import std.typecons : tuple;
1498 
1499 	static struct I {
1500 		int i;
1501 	}
1502 
1503 	static struct S {
1504 		int x;
1505 		string s_;
1506 	}
1507 
1508 	static struct T {
1509 		@asArray
1510 		typeof(tuple!(FieldNameTuple!I)(I.init.tupleof)) tuple1AsArray;
1511 
1512 		@name(fullyQualifiedName!I)
1513 		typeof(tuple!(FieldNameTuple!I)(I.init.tupleof)) tuple1AsDictionary;
1514 
1515 		@asArray
1516 		typeof(tuple!(FieldNameTuple!S)(S.init.tupleof)) tuple2AsArray;
1517 
1518 		@name(fullyQualifiedName!S)
1519 		typeof(tuple!(FieldNameTuple!S)(S.init.tupleof)) tuple2AsDictionary;
1520 	}
1521 
1522 	const i = I(42);
1523 	const s = S(42, "hello");
1524 	const T t = { i.tupleof, i.tupleof, s.tupleof, s.tupleof };
1525 
1526 	const st = serialize!TestSerializer(t);
1527 
1528 	enum Tm = T.mangleof;
1529 	enum TuIm = typeof(T.tuple1AsArray).mangleof;
1530 	enum TuSm = typeof(T.tuple2AsArray).mangleof;
1531 
1532 	const et =
1533 		"D("~Tm~")"~
1534 		"{"~
1535 			"DE("~TuIm~",tuple1AsArray)"~
1536 			"("~
1537 				"V(i)(42)"~
1538 			")"~
1539 			"DE("~TuIm~",tuple1AsArray)"~
1540 			"DE("~TuIm~","~fullyQualifiedName!I~")"~
1541 			"("~
1542 				"D("~TuIm~")"~
1543 				"{"~
1544 					"DE(i,i)"~
1545 					"("~
1546 						"V(i)(42)"~
1547 					")"~
1548 					"DE(i,i)"~
1549 				"}"~
1550 				"D("~TuIm~")"~
1551 			")"~
1552 			"DE("~TuIm~","~fullyQualifiedName!I~")"~
1553 			"DE("~TuSm~",tuple2AsArray)"~
1554 			"("~
1555 				"A("~TuSm~")[2]"~
1556 				"["~
1557 					"AE(i,0)"~
1558 					"("~
1559 						"V(i)(42)"~
1560 					")"~
1561 					"AE(i,0)"~
1562 					"AE(Aya,1)"~
1563 					"("~
1564 						"V(Aya)(hello)"~
1565 					")"~
1566 					"AE(Aya,1)"~
1567 				"]"~
1568 				"A("~TuSm~")"~
1569 			")"~
1570 			"DE("~TuSm~",tuple2AsArray)"~
1571 			"DE("~TuSm~","~fullyQualifiedName!S~")"~
1572 			"("~
1573 				"D("~TuSm~")"~
1574 				"{"~
1575 					"DE(i,x)"~
1576 					"("~
1577 						"V(i)(42)"~
1578 					")"~
1579 					"DE(i,x)"~
1580 					"DE(Aya,s)"~
1581 					"("~
1582 						"V(Aya)(hello)"~
1583 					")"~
1584 					"DE(Aya,s)"~
1585 				"}"~
1586 				"D("~TuSm~")"~
1587 			")"~
1588 			"DE("~TuSm~","~fullyQualifiedName!S~")"~
1589 		"}"~
1590 		"D("~Tm~")";
1591 	assert(st == et);
1592 
1593 	const dst = deserialize!(TestSerializer, typeof(t))(st);
1594 	assert(dst == t);
1595 }
1596 
1597 unittest { // testing the various UDAs
1598 	enum E { hello, world }
1599 	enum Em = E.mangleof;
1600 	static struct S {
1601 		@byName E e;
1602 		@ignore int i;
1603 		@optional float f;
1604 	}
1605 	enum Sm = S.mangleof;
1606 	auto s = S(E.world, 42, 1.0f);
1607 	assert(serialize!TestSerializer(s) ==
1608 		"D("~Sm~"){DE("~Em~",e)(V(Aya)(world))DE("~Em~",e)DE(f,f)(V(f)(1))DE(f,f)}D("~Sm~")");
1609 }
1610 
1611 unittest { // custom serialization support
1612 	// iso-ext
1613 	import std.datetime;
1614 	auto t = TimeOfDay(6, 31, 23);
1615 	assert(serialize!TestSerializer(t) == "V(Aya)(06:31:23)");
1616 	auto d = Date(1964, 1, 23);
1617 	assert(serialize!TestSerializer(d) == "V(Aya)(1964-01-23)");
1618 	auto dt = DateTime(d, t);
1619 	assert(serialize!TestSerializer(dt) == "V(Aya)(1964-01-23T06:31:23)");
1620 	auto st = SysTime(dt, UTC());
1621 	assert(serialize!TestSerializer(st) == "V(Aya)(1964-01-23T06:31:23Z)");
1622 }
1623 
1624 @safe unittest { // custom serialization support
1625 	// string
1626 	static struct S1 { int i; string toString() const @safe { return "hello"; } static S1 fromString(string) @safe { return S1.init; } }
1627 	static struct S2 { int i; string toString() const { return "hello"; } }
1628 	enum S2m = S2.mangleof;
1629 	static struct S3 { int i; static S3 fromString(string) { return S3.init; } }
1630 	enum S3m = S3.mangleof;
1631 	assert(serialize!TestSerializer(S1.init) == "V(Aya)(hello)");
1632 	assert(serialize!TestSerializer(S2.init) == "D("~S2m~"){DE(i,i)(V(i)(0))DE(i,i)}D("~S2m~")");
1633 	assert(serialize!TestSerializer(S3.init) == "D("~S3m~"){DE(i,i)(V(i)(0))DE(i,i)}D("~S3m~")");
1634 
1635 	// custom
1636 	static struct C1 { int i; float toRepresentation() const @safe { return 1.0f; } static C1 fromRepresentation(float f) @safe { return C1.init; } }
1637 	static struct C2 { int i; float toRepresentation() const { return 1.0f; } }
1638 	enum C2m = C2.mangleof;
1639 	static struct C3 { int i; static C3 fromRepresentation(float f) { return C3.init; } }
1640 	enum C3m = C3.mangleof;
1641 	assert(serialize!TestSerializer(C1.init) == "V(f)(1)");
1642 	assert(serialize!TestSerializer(C2.init) == "D("~C2m~"){DE(i,i)(V(i)(0))DE(i,i)}D("~C2m~")");
1643 	assert(serialize!TestSerializer(C3.init) == "D("~C3m~"){DE(i,i)(V(i)(0))DE(i,i)}D("~C3m~")");
1644 }
1645 
1646 unittest // Testing corner case: member function returning by ref
1647 {
1648 	import vibe.data.json;
1649 
1650 	static struct S
1651 	{
1652 		int i;
1653 		ref int foo() { return i; }
1654 	}
1655 
1656 	static assert(__traits(compiles, { S().serializeToJson(); }));
1657 	static assert(__traits(compiles, { Json().deserializeJson!S(); }));
1658 
1659 	auto s = S(1);
1660 	assert(s.serializeToJson().deserializeJson!S() == s);
1661 }
1662 
1663 unittest // Testing corner case: Variadic template constructors and methods
1664 {
1665 	import vibe.data.json;
1666 
1667 	static struct S
1668 	{
1669 		int i;
1670 		this(Args...)(Args args) {}
1671 		int foo(Args...)(Args args) { return i; }
1672 		ref int bar(Args...)(Args args) { return i; }
1673 	}
1674 
1675 	static assert(__traits(compiles, { S().serializeToJson(); }));
1676 	static assert(__traits(compiles, { Json().deserializeJson!S(); }));
1677 
1678 	auto s = S(1);
1679 	assert(s.serializeToJson().deserializeJson!S() == s);
1680 }
1681 
1682 @safe unittest // Make sure serializing through properties still works
1683 {
1684 	import vibe.data.json;
1685 
1686 	static struct S
1687 	{
1688 		@safe:
1689 		public int i;
1690 		private int privateJ;
1691 
1692 		@property int j() @safe { return privateJ; }
1693 		@property void j(int j) @safe { privateJ = j; }
1694 	}
1695 
1696 	auto s = S(1, 2);
1697 	assert(s.serializeToJson().deserializeJson!S() == s);
1698 }
1699 
1700 @safe unittest // Immutable data deserialization
1701 {
1702 	import vibe.data.json;
1703 
1704 	static struct S {
1705 		int a;
1706 	}
1707 	static class C {
1708 		immutable(S)[] arr;
1709 	}
1710 
1711 	auto c = new C;
1712 	c.arr ~= S(10);
1713 	auto d = c.serializeToJson().deserializeJson!(immutable C);
1714 	static assert(is(typeof(d) == immutable C));
1715 	assert(d.arr == c.arr);
1716 }
1717 
1718 unittest { // test BitFlags serialization
1719 	import std.typecons : BitFlags;
1720 
1721 	enum Flag {
1722 		a = 1<<0,
1723 		b = 1<<1,
1724 		c = 1<<2
1725 	}
1726 	enum Flagm = Flag.mangleof;
1727 
1728 	alias Flags = BitFlags!Flag;
1729 	enum Flagsm = Flags.mangleof;
1730 
1731 	enum Fi_ser = "A("~Flagsm~")[0][]A("~Flagsm~")";
1732 	assert(serialize!TestSerializer(Flags.init) == Fi_ser);
1733 
1734 	enum Fac_ser = "A("~Flagsm~")[2][AE("~Flagm~",0)(V(i)(1))AE("~Flagm~",0)AE("~Flagm~",1)(V(i)(4))AE("~Flagm~",1)]A("~Flagsm~")";
1735 	assert(serialize!TestSerializer(Flags(Flag.a, Flag.c)) == Fac_ser);
1736 
1737 	struct S { @byName Flags f; }
1738 	enum Sm = S.mangleof;
1739 	enum Sac_ser = "D("~Sm~"){DE("~Flagsm~",f)(A("~Flagsm~")[2][AE("~Flagm~",0)(V(Aya)(a))AE("~Flagm~",0)AE("~Flagm~",1)(V(Aya)(c))AE("~Flagm~",1)]A("~Flagsm~"))DE("~Flagsm~",f)}D("~Sm~")";
1740 
1741 	assert(serialize!TestSerializer(S(Flags(Flag.a, Flag.c))) == Sac_ser);
1742 
1743 	assert(deserialize!(TestSerializer, Flags)(Fi_ser) == Flags.init);
1744 	assert(deserialize!(TestSerializer, Flags)(Fac_ser) == Flags(Flag.a, Flag.c));
1745 	assert(deserialize!(TestSerializer, S)(Sac_ser) == S(Flags(Flag.a, Flag.c)));
1746 }
1747 
1748 @safe unittest { // issue #1182
1749 	struct T {
1750 		int x;
1751 		string y;
1752 	}
1753 	struct S {
1754 		@asArray T t;
1755 	}
1756 
1757 	auto s = S(T(42, "foo"));
1758 	enum Sm = S.mangleof;
1759 	enum Tm = T.mangleof;
1760 	enum s_ser = "D("~Sm~"){DE("~Tm~",t)(A("~Tm~")[2][AE(i,0)(V(i)(42))AE(i,0)AE(Aya,1)(V(Aya)(foo))AE(Aya,1)]A("~Tm~"))DE("~Tm~",t)}D("~Sm~")";
1761 
1762 	auto serialized = serialize!TestSerializer(s);
1763 	assert(serialized == s_ser, serialized);
1764 	assert(deserialize!(TestSerializer, S)(serialized) == s);
1765 }
1766 
1767 @safe unittest { // issue #1352 - ingore per policy
1768 	struct P1 {}
1769 	struct P2 {}
1770 
1771 	struct T {
1772 		@ignore int a = 5;
1773 		@ignore!P1 @ignore!P2 int b = 6;
1774 		@ignore!P1 c = 7;
1775 		int d = 8;
1776 	}
1777 
1778 	auto t = T(1, 2, 3, 4);
1779 	auto Tm = T.mangleof;
1780 	auto t_ser_plain = "D("~Tm~"){DE(i,b)(V(i)(2))DE(i,b)DE(i,c)(V(i)(3))DE(i,c)DE(i,d)(V(i)(4))DE(i,d)}D("~Tm~")";
1781 	auto t_ser_p1 = "D("~Tm~"){DE(i,d)(V(i)(4))DE(i,d)}D("~Tm~")";
1782 	auto t_ser_p2 = "D("~Tm~"){DE(i,c)(V(i)(3))DE(i,c)DE(i,d)(V(i)(4))DE(i,d)}D("~Tm~")";
1783 
1784 	{
1785 		auto serialized_plain = serialize!TestSerializer(t);
1786 		assert(serialized_plain == t_ser_plain);
1787 		assert(deserialize!(TestSerializer, T)(serialized_plain) == T(5, 2, 3, 4));
1788 	}
1789 
1790 	{
1791 		auto serialized_p1 = serializeWithPolicy!(TestSerializer, P1)(t);
1792 		assert(serialized_p1 == t_ser_p1, serialized_p1);
1793 		assert(deserializeWithPolicy!(TestSerializer, P1, T)(serialized_p1) == T(5, 6, 7, 4));
1794 	}
1795 
1796 	{
1797 		auto serialized_p2 = serializeWithPolicy!(TestSerializer, P2)(t);
1798 		assert(serialized_p2 == t_ser_p2);
1799 		assert(deserializeWithPolicy!(TestSerializer, P2, T)(serialized_p2) == T(5, 6, 3, 4));
1800 	}
1801 }
1802 
1803 unittest {
1804 	import std.conv : to;
1805 	import std.string : toLower, toUpper;
1806 
1807 	template P(T) if (is(T == enum)) {
1808 		@safe:
1809 		static string toRepresentation(T v) { return v.to!string.toLower(); }
1810 		static T fromRepresentation(string str) { return str.toUpper().to!T; }
1811 	}
1812 
1813 
1814 	enum E {
1815 		RED,
1816 		GREEN
1817 	}
1818 
1819 	assert(P!E.fromRepresentation("green") == E.GREEN);
1820 	static assert(isPolicySerializable!(P, E));
1821 
1822 	auto ser_red = "V(Aya)(red)";
1823 	assert(serializeWithPolicy!(TestSerializer, P)(E.RED) == ser_red, serializeWithPolicy!(TestSerializer, P)(E.RED));
1824 	assert(deserializeWithPolicy!(TestSerializer, P, E)(ser_red) == E.RED);
1825 
1826 	import vibe.data.json : Json, JsonSerializer;
1827 	assert(serializeWithPolicy!(JsonSerializer, P)(E.RED) == Json("red"));
1828 }
1829 
1830 unittest {
1831 	static struct R { int y; }
1832 	static struct Custom {
1833 		@safe:
1834 		int x;
1835 		R toRepresentation() const { return R(x); }
1836 		static Custom fromRepresentation(R r) { return Custom(r.y); }
1837 	}
1838 
1839 	auto c = Custom(42);
1840 	auto Rn = R.mangleof;
1841 	auto ser = serialize!TestSerializer(c);
1842 	assert(ser == "D("~Rn~"){DE(i,y)(V(i)(42))DE(i,y)}D("~Rn~")");
1843 	auto deser = deserialize!(TestSerializer, Custom)(ser);
1844 	assert(deser.x == 42);
1845 }
1846 
1847 unittest {
1848 	import std.typecons : Typedef;
1849 	alias T = Typedef!int;
1850 	auto ser = serialize!TestSerializer(T(42));
1851 	assert(ser == "V(i)(42)", ser);
1852 	auto deser = deserialize!(TestSerializer, T)(ser);
1853 	assert(deser == 42);
1854 }
1855 
1856 @safe unittest {
1857 	static struct Foo { Foo[] foos; }
1858 	Foo f;
1859 	string ser = serialize!TestSerializer(f);
1860 	assert(deserialize!(TestSerializer, Foo)(ser) == f);
1861 }
1862 
1863 @system unittest {
1864 	static struct SystemSerializer {
1865 		TestSerializer ser;
1866 		alias ser this;
1867 		this(string s) { ser.result = s; }
1868 		T readValue(Traits, T)() @system { return ser.readValue!(Traits, T); }
1869 		void writeValue(Traits, T)(T value) @system { ser.writeValue!(Traits, T)(value); }
1870 		void readDictionary(Traits)(scope void delegate(string) @system entry_callback) { ser.readDictionary!Traits((s) @trusted { entry_callback(s); }); }
1871 		void readArray(Traits)(scope void delegate(size_t) @system size_callback, scope void delegate() @system entry_callback) { ser.readArray!Traits((s) @trusted { size_callback(s); }, () @trusted { entry_callback(); }); }
1872 	}
1873 
1874 	static struct Bar { Bar[] foos; int i; }
1875 	Bar f;
1876 	string ser = serialize!SystemSerializer(f);
1877 	assert(deserialize!(SystemSerializer, Bar)(ser) == f);
1878 }
1879 
1880 @safe unittest {
1881 	static struct S { @name("+foo") int bar; }
1882 	auto Sn = S.mangleof;
1883 	auto s = S(42);
1884 	string ser = serialize!TestSerializer(s);
1885 	assert(ser == "D("~Sn~"){DE(i,+foo)(V(i)(42))DE(i,+foo)}D("~Sn~")", ser);
1886 	auto deser = deserialize!(TestSerializer, S)(ser);
1887 	assert(deser.bar == 42);
1888 }
1889 
1890 @safe unittest {
1891 	static struct S { int bar_; }
1892 	auto Sn = S.mangleof;
1893 	auto s = S(42);
1894 	string ser = serialize!TestSerializer(s);
1895 	assert(ser == "D("~Sn~"){DE(i,bar)(V(i)(42))DE(i,bar)}D("~Sn~")", ser);
1896 	auto deser = deserialize!(TestSerializer, S)(ser);
1897 	assert(deser.bar_ == 42);
1898 }