1 module mutils.serializer.binary_maped;
2 
3 import std.algorithm : min;
4 import std.meta;
5 import std.stdio;
6 import std.traits;
7 
8 import mutils.container.vector;
9 import mutils.conv;
10 public import mutils.serializer.common;
11 
12 //  COS==ContainerOrSlice
13 
14 // THINK ABOUT: if serializer returns false con should: notbe changed, shoud be at the end of var, undefined??
15 
16 ubyte[] toBytes(T)(ref T val) {
17 	return (cast(ubyte*)&val)[0 .. T.sizeof];
18 }
19 
20 enum VariableType : byte {
21 	bool_,
22 	char_,
23 	byte_,
24 	ubyte_,
25 	short_,
26 	ushort_,
27 	int_,
28 	uint_,
29 	long_,
30 	ulong_,
31 	float_,
32 	double_,
33 	real_,
34 	struct_,
35 	class_,
36 	stringVector,
37 	customMap,
38 	array,
39 	enum_,
40 }
41 
42 VariableType getSerVariableType(TTT)() {
43 	alias T = Unqual!TTT;
44 
45 	static if (is(T == bool)) {
46 		return VariableType.bool_;
47 	} else static if (is(T == char)) {
48 		return VariableType.char_;
49 	} else static if (is(T == byte)) {
50 		return VariableType.byte_;
51 	} else static if (is(T == ubyte)) {
52 		return VariableType.ubyte_;
53 	} else static if (is(T == short)) {
54 		return VariableType.short_;
55 	} else static if (is(T == ushort)) {
56 		return VariableType.ushort_;
57 	} else static if (is(T == int)) {
58 		return VariableType.int_;
59 	} else static if (is(T == uint)) {
60 		return VariableType.uint_;
61 	} else static if (is(T == long)) {
62 		return VariableType.long_;
63 	} else static if (is(T == ulong)) {
64 		return VariableType.ulong_;
65 	} else static if (is(T == float)) {
66 		return VariableType.float_;
67 	} else static if (is(T == double)) {
68 		return VariableType.double_;
69 	} else static if (is(T == real)) {
70 		return VariableType.real_;
71 	} else static if (is(T == struct)) {
72 		return VariableType.struct_;
73 	} else static if (is(T == class)) {
74 		return VariableType.class_;
75 	} else static if (isStringVector!T) {
76 		return VariableType.stringVector;
77 	} else static if (isCustomMap!T) {
78 		return VariableType.customMap;
79 	} else static if (isStaticArray!T) {
80 		return VariableType.staticArray;
81 	} else static if (isCustomMap!T) {
82 		return VariableType.customMap;
83 	} else static if (is(T == enum)) {
84 		return VariableType.enum_;
85 	} else {
86 		static assert(0, "Type not supported 2307");
87 	}
88 }
89 
90 bool isSerBasicType(VariableType type) {
91 	return (type >= VariableType.bool_ && type <= VariableType.real_);
92 }
93 
94 SizeType getSerVariableTypeSize(VariableType type) {
95 	switch (type) {
96 	case VariableType.bool_:
97 	case VariableType.char_:
98 	case VariableType.byte_:
99 	case VariableType.ubyte_:
100 		return 1;
101 	case VariableType.short_:
102 	case VariableType.ushort_:
103 		return 2;
104 	case VariableType.int_:
105 	case VariableType.uint_:
106 	case VariableType.float_:
107 		return 4;
108 	case VariableType.long_:
109 	case VariableType.ulong_:
110 	case VariableType.double_:
111 		return 8;
112 	case VariableType.real_:
113 		//static assert(real.sizeof == 16);// On windows 10
114 		//static assert(real.alignof == 16);// On windows 2
115 		return 16;
116 	default:
117 		return 0;
118 	}
119 }
120 
121 void serializeType(Load load, COS)(ref VariableType type, ref COS con) {
122 	if (load == Load.yes) {
123 		type = cast(VariableType) con[0];
124 		con = con[1 .. $];
125 	} else {
126 		con ~= cast(ubyte) type;
127 	}
128 }
129 
130 struct SerBasicVariable {
131 	align(16) ubyte[16] data; // Strictest aligment and biggest size of basic types
132 
133 	VariableType type;
134 	bool serialize(Load load, COS)(ref COS con) {
135 		serializeType!(load)(type, con);
136 
137 		if (!isSerBasicType(type)) {
138 			return false;
139 		}
140 
141 		SizeType varSize = getSerVariableTypeSize(type);
142 
143 		static if (load == Load.yes) {
144 			data[0 .. varSize] = con[0 .. varSize];
145 			con = con[varSize .. $];
146 		} else {
147 			con ~= data[0 .. varSize];
148 		}
149 		return true;
150 	}
151 
152 	T get(T)() {
153 		enum VariableType typeT = getSerVariableType!T;
154 		enum SizeType varSize = getSerVariableTypeSize(typeT);
155 		assert(typeT == type);
156 		//static assert(T.sizeof == varSize); // real on windows 10 on linux 16
157 		T var;
158 		toBytes(var)[0 .. T.sizeof] = data[0 .. T.sizeof];
159 		return var;
160 	}
161 
162 	real getReal() {
163 		switch (type) {
164 		case VariableType.bool_:
165 			return get!bool;
166 		case VariableType.char_:
167 			return get!char;
168 		case VariableType.byte_:
169 			return get!byte;
170 		case VariableType.ubyte_:
171 			return get!ubyte;
172 		case VariableType.short_:
173 			return get!short;
174 		case VariableType.ushort_:
175 			return get!ushort;
176 		case VariableType.int_:
177 			return get!int;
178 		case VariableType.uint_:
179 			return get!uint;
180 		case VariableType.float_:
181 			return get!float;
182 		case VariableType.long_:
183 			return get!long;
184 		case VariableType.ulong_:
185 			return get!ulong;
186 		case VariableType.double_:
187 			return get!double;
188 		case VariableType.real_:
189 			return get!real;
190 		default:
191 			break;
192 		}
193 		assert(0); // TODO Log
194 		//return 0;
195 	}
196 
197 	real getLong() {
198 		switch (type) {
199 		case VariableType.bool_:
200 			return get!bool;
201 		case VariableType.char_:
202 			return get!char;
203 		case VariableType.byte_:
204 			return get!byte;
205 		case VariableType.ubyte_:
206 			return get!ubyte;
207 		case VariableType.short_:
208 			return get!short;
209 		case VariableType.ushort_:
210 			return get!ushort;
211 		case VariableType.int_:
212 			return get!int;
213 		case VariableType.uint_:
214 			return get!uint;
215 		case VariableType.float_:
216 			return get!float;
217 		case VariableType.long_:
218 			return get!long;
219 		case VariableType.ulong_:
220 			return get!ulong;
221 		case VariableType.double_:
222 			return get!double;
223 		case VariableType.real_:
224 			return get!real;
225 		default:
226 			break;
227 		}
228 
229 		assert(0); // TODO Log
230 		//return 0;
231 	}
232 }
233 
234 alias SizeNameType = ubyte;
235 alias SizeType = uint;
236 
237 struct BinarySerializerMaped {
238 	alias SliceElementType = ubyte;
239 	__gshared static BinarySerializerMaped instance;
240 
241 	static ubyte[] beginObject(Load load, COS)(ref COS con) {
242 		ubyte[] orginalSlice = con[];
243 
244 		SizeType objectSize = 0; // 0 is a placeholder value during save, proper value will be assigned in endObject
245 		serializeSize!(load)(objectSize, con);
246 
247 		static if (load == Load.yes) {
248 			con = con[0 .. objectSize];
249 			ubyte[] afterObjectSlice = orginalSlice[SizeType.sizeof + objectSize .. $];
250 			return afterObjectSlice;
251 		} else {
252 			return orginalSlice;
253 		}
254 
255 	}
256 
257 	static void endObject(Load load, COS)(ref COS con, ubyte[] slice) {
258 		static if (load == Load.yes) {
259 			con = slice;
260 		} else {
261 			SizeType objectSize = cast(SizeType)(con.length - (slice.length + SizeType.sizeof));
262 			con[slice.length .. slice.length + SizeType.sizeof] = toBytes(objectSize); // override object size
263 		}
264 
265 	}
266 
267 	//support for rvalues during load
268 	void serializeWithName(Load load, string name, T, COS)(ref T var, COS con) {
269 		static assert(load == Load.yes);
270 		serializeWithName!(load, name)(var, con);
271 	}
272 
273 	static bool serializeWithName(Load load, string name, T, COS)(ref T var, ref COS con) {
274 		static if (load == Load.yes) {
275 			return serializeByName!(load, name)(var, con);
276 		} else {
277 			serializeName!(load)(name, con);
278 			serialize!(load)(var, con);
279 			return true;
280 		}
281 
282 	}
283 	//support for rvalues during load
284 	void serialize(Load load, T, COS)(ref T var, COS con) {
285 		static assert(load == Load.yes);
286 		serialize!(load)(var, con);
287 	}
288 
289 	static bool serialize(Load load, T, COS)(ref T var, ref COS con) {
290 		static if (hasMember!(T, "customSerialize")) {
291 			VariableType type = VariableType.struct_;
292 			serializeType!(load)(type, con);
293 			assert(type==VariableType.struct_);
294 			var.customSerialize!(load)(instance, con);
295 			return true;
296 		} else static if (is(T == enum)) {
297 			return serializeEnum!(load)(var, con);
298 		} else static if (isBasicType!T) {
299 			return serializeBasicVar!(load)(var, con);
300 		} else static if (isStringVector!T) {
301 			return serializeStringVector!(load)(var, con);
302 		} else static if (isCustomVector!T) {
303 			return serializeCustomVector!(load)(var, con);
304 		} else static if (isStaticArray!T) {
305 			return serializeStaticArray!(load)(var, con);
306 		} else static if (isCustomMap!T) {
307 			return serializeCustomMap!(load)(var, con);
308 		} else static if (is(T == struct)) {
309 			return serializeStruct!(load)(var, con);
310 		} else static if (isPointer!T) {
311 			static assert(0, "Can not serialzie pointer");
312 		} else {
313 			static assert(0, "Not supported");
314 		}
315 	}
316 
317 	//////////////////////// IMPL
318 
319 	static bool serializeBasicVar(Load load, T, COS)(ref T var, ref COS con) {
320 		static assert(isBasicType!T);
321 
322 		enum VariableType properType = getSerVariableType!T;
323 		VariableType type = properType;
324 
325 		static if (load == Load.yes) {
326 			serializeTypeNoPop!(load)(type, con);
327 			if (type != properType) {
328 				return serializeBasicVarWithConversion!(load)(var, con);
329 			}
330 		}
331 
332 		serializeType!(load)(type, con);
333 		static if (load == Load.yes) {
334 			toBytes(var)[0 .. T.sizeof] = con[0 .. T.sizeof];
335 			con = con[T.sizeof .. $];
336 		} else {
337 			con ~= toBytes(var);
338 		}
339 		return true;
340 	}
341 
342 	static bool serializeBasicVarWithConversion(Load load, T, COS)(ref T var, ref COS con) {
343 		static assert(load == Load.yes);
344 
345 		enum VariableType properType = getSerVariableType!T;
346 
347 		VariableType type;
348 		serializeTypeNoPop!(load)(type, con);
349 
350 		if (!isSerBasicType(type)) {
351 			return false;
352 		}
353 
354 		SerBasicVariable serBasicVar;
355 		serBasicVar.serialize!(load)(con);
356 
357 		static if (isFloatingPoint!T) {
358 			var = cast(T) serBasicVar.getReal();
359 		} else static if (isIntegral!T || is(T == char)) {
360 			var = cast(T) serBasicVar.getLong();
361 		}
362 
363 		return true;
364 	}
365 
366 	static bool serializeEnum(Load load, T, COS)(ref T var, ref COS con) {
367 
368 		VariableType type = VariableType.enum_;
369 		serializeType!(load)(type, con);
370 
371 		if (type != VariableType.enum_) {
372 			return false;
373 		}
374 
375 		static if (load == Load.yes) {
376 			SizeType varSize;
377 			serializeSize!(load)(varSize, con);
378 			string str = cast(string) con[0 .. varSize];
379 			var = str2enum!(T)(str);
380 			assert(str.length == 0);
381 		} else {
382 			char[256] buffer;
383 			string enumStr = enum2str(var, buffer);
384 			SizeType varSize = cast(SizeType) enumStr.length;
385 			serializeSize!(load)(varSize, con);
386 			con ~= cast(ubyte[]) enumStr;
387 		}
388 		return true; //TODO return false when wrong enum is loaded
389 	}
390 
391 	static bool serializeStruct(Load load, T, COS)(ref T var, ref COS con) {
392 		static assert(is(T == struct));
393 
394 		enum VariableType properType = getSerVariableType!T;
395 		VariableType type = properType;
396 		serializeType!(load)(type, con);
397 		if (type != VariableType.struct_) {
398 			return false;
399 		}
400 
401 		ubyte[] begin = beginObject!(load)(con);
402 		scope (exit)
403 			endObject!(load)(con, begin);
404 
405 		foreach (i, ref a; var.tupleof) {
406 			alias TP = AliasSeq!(__traits(getAttributes, var.tupleof[i]));
407 			enum bool doSerialize = !hasNoserializeUda!(TP);
408 			static if (doSerialize) {
409 				enum string varName = __traits(identifier, var.tupleof[i]);
410 				static if (load == Load.yes) {
411 					serializeByName!(load, varName)(a, con);
412 				} else {
413 					serializeName!(load)(varName, con);
414 					serialize!(load)(a, con);
415 				}
416 			}
417 		}
418 
419 		return true;
420 	}
421 
422 	static bool serializeArray(Load load, T, COS)(ref T var, ref COS con) {
423 		assert(var.length < SizeType.max);
424 
425 		ubyte[] begin = beginObject!(load)(con);
426 		scope (exit)
427 			endObject!(load)(con, begin);
428 
429 		static if (load == Load.yes) {
430 			SizeType elemntsNum;
431 			serializeSize!(load)(elemntsNum, con);
432 
433 			if (elemntsNum == 0) {
434 				return true;
435 			}
436 
437 			VariableType elementType;
438 			serializeTypeNoPop!(load)(elementType, con);
439 			auto conSliceStart = con;
440 
441 			alias ElementType = Unqual!(ForeachType!(T));
442 			foreach (kkkkk; 0 .. elemntsNum) {
443 				ElementType el;
444 				bool ok = serialize!(load)(el, con);
445 				if (!ok) {
446 					return false;
447 				}
448 				var ~= el;
449 			}
450 
451 			SizeType oneElementSize = getSerVariableTypeSize(elementType);
452 			con = conSliceStart[oneElementSize * elemntsNum .. $];
453 		} else {
454 			SizeType elemntsNum = 0;
455 			size_t conLengthSizeStart = con.length;
456 			serializeSize!(load)(elemntsNum, con); // Place holder, proper elementsNum will be saved later
457 
458 			foreach (ref el; var) {
459 				bool ok = serialize!(load)(el, con);
460 				assert(ok);
461 				elemntsNum++;
462 			}
463 			SizeType* elementsNumPtr = cast(SizeType*)(con[].ptr + conLengthSizeStart);
464 			*elementsNumPtr = elemntsNum;
465 
466 		}
467 
468 		return true;
469 	}
470 
471 	static bool serializeStaticArray(Load load, T, COS)(ref T var, ref COS con) {
472 		static assert(isStaticArray!T);
473 
474 		VariableType type = VariableType.array;
475 		serializeType!(load)(type, con);
476 		if (type != VariableType.array) {
477 			return false;
478 		}
479 		ubyte[] begin = beginObject!(load)(con);
480 		scope (exit)
481 			endObject!(load)(con, begin);
482 
483 		SizeType elemntsNum = cast(SizeType) var.length;
484 		serializeSize!(load)(elemntsNum, con);
485 
486 		size_t elementsToLoadSave = min(var.length, elemntsNum);
487 
488 		static if (load == Load.yes) {
489 			VariableType elementType;
490 			serializeTypeNoPop!(load)(elementType, con);
491 			auto conSliceStart = con;
492 		}
493 
494 		foreach (i, ref el; var) {
495 			bool ok = serialize!(load)(el, con);
496 			if (!ok) {
497 				return false;
498 			}
499 			if (i >= elementsToLoadSave) {
500 				break;
501 			}
502 		}
503 
504 		static if (load == Load.yes) {
505 			SizeType oneElementSize = getSerVariableTypeSize(elementType);
506 			con = conSliceStart[oneElementSize * elementsToLoadSave .. $];
507 		}
508 		return true;
509 
510 	}
511 
512 	static bool serializeCustomVector(Load load, T, COS)(ref T var, ref COS con) {
513 		alias ElementType = Unqual!(ForeachType!(T));
514 
515 		VariableType type = VariableType.array;
516 		serializeType!(load)(type, con);
517 		if (type != VariableType.array) {
518 			return false;
519 		}
520 
521 		static if (load == Load.yes) {
522 			static if (hasMember!(T, "initialize")) {
523 				var.initialize();
524 			}
525 			auto sliceTmp = con;
526 			SizeType elementsNum;
527 			serializeSize!(load)(elementsNum, sliceTmp); // Size of whole array data - ignore
528 			serializeSize!(load)(elementsNum, sliceTmp);
529 
530 			static if (hasMember!(T, "reserve")) {
531 				var.reserve(elementsNum);
532 			}
533 		}
534 
535 		return serializeArray!(load)(var, con);
536 	}
537 
538 	static bool serializeStringVector(Load load, T, COS)(ref T var, ref COS con) {
539 		alias ElementType = char;
540 
541 		VariableType type = VariableType.stringVector;
542 		serializeType!(load)(type, con);
543 		if (type != VariableType.stringVector) {
544 			return false;
545 		}
546 
547 		assert(var.length < SizeType.max);
548 		SizeType size = cast(SizeType) var.length;
549 		serializeSize!(load)(size, con);
550 
551 		static if (load == Load.yes) {
552 			static if (hasMember!(T, "initialize")) {
553 				var.initialize();
554 			}
555 			var = cast(string) con[0 .. size];
556 			con = con[size .. $];
557 		} else {
558 			assert(var[].length == size);
559 			con ~= cast(ubyte[]) var[];
560 		}
561 		return true;
562 	}
563 
564 	static bool serializeRange(Load load, T, COS)(ref T var, ref COS con) {
565 		static assert(load == Load.no);
566 		alias ElementType = Unqual!(ForeachType!(T));
567 
568 		VariableType type = VariableType.staticArray; // Pretend it is staticArray
569 		serializeType!(load)(type, con);
570 		return serializeSlice!(load)(var[], con);
571 	}
572 
573 	static bool serializeCustomMap(Load load, T, COS)(ref T var, ref COS con) {
574 		static assert(isCustomMap!T);
575 
576 		VariableType type = VariableType.customMap;
577 		serializeType!(load)(type, con);
578 		if (type != VariableType.customMap) {
579 			return false;
580 		}
581 		//uint dataLength = cast(uint)(var.length);
582 		//serialize!(loadOrSkip!load)(dataLength, con);
583 
584 		ubyte[] begin = beginObject!(load)(con);
585 		scope (exit)
586 			endObject!(load)(con, begin);
587 
588 		SizeType elemntsNum = cast(SizeType) var.length;
589 		serializeSize!(load)(elemntsNum, con);
590 
591 		static if (load == Load.yes) {
592 			static if (hasMember!(T, "initialize")) {
593 				var.initialize();
594 			}
595 			static if (hasMember!(T, "reserve")) {
596 				var.reserve(elemntsNum);
597 			}
598 			foreach (i; 0 .. elemntsNum) {
599 				bool ok;
600 				T.Key key;
601 				T.Value value;
602 				ok = serialize!(load)(key, con);
603 				if (!ok) {
604 					return false;
605 				}
606 				ok = serialize!(load)(value, con);
607 				if (!ok) {
608 					return false;
609 				}
610 				var.add(key, value);
611 			}
612 		} else {
613 			foreach (ref key, ref value; &var.byKeyValue) {
614 				serialize!(load)(key, con);
615 				serialize!(load)(value, con);
616 			}
617 		}
618 		return false;
619 	}
620 
621 	//////////////////////////////////////////////// HELPERS
622 
623 	static bool serializeByName(Load load, string name, T, COS)(ref T var, ref COS con) {
624 		static assert(load == Load.yes);
625 		auto conBegin = con;
626 		scope (exit)
627 			con = conBegin; // Revert slice
628 
629 		foreach (noInfiniteLoop; 0 .. 1000) {
630 			string varName;
631 			serializeName!(load)(varName, con);
632 
633 			if (varName is null) {
634 				break;
635 			}
636 
637 			ubyte[] conStartVar = con;
638 
639 			VariableType type; // Custom serialize might not have it
640 			serializeType!(load)(type, con);
641 
642 			SizeType varSize;
643 			SizeType sizeSize;
644 
645 			if (isSerBasicType(type)) {
646 				varSize = getSerVariableTypeSize(type);
647 			} else {
648 				serializeSize!(load)(varSize, con);
649 				sizeSize = SizeType.sizeof;
650 			}
651 			SizeType varEnd = 1 + sizeSize + varSize;
652 
653 			if (varName == name) {
654 				ubyte[] conStartVarTmp = conStartVar[0 .. varEnd];
655 				bool loaded = serialize!(load)(var, conStartVarTmp);
656 				if (loaded) {
657 					if (noInfiniteLoop == 0) { // Move con because no one will read this value again(no key duplicates)
658 						conBegin = conStartVar[varEnd .. $];
659 					}
660 					return true;
661 				}
662 			}
663 			if (varEnd >= conStartVar.length) {
664 				return false;
665 			}
666 			con = conStartVar[varEnd .. $];
667 		}
668 		return false;
669 	}
670 
671 	private static void serializeName(Load load, COS)(auto ref string name, ref COS con) {
672 		if (load == Load.yes) {
673 			if (con.length < SizeNameType.sizeof) {
674 				name = null;
675 				return;
676 			}
677 			SizeNameType nameLength;
678 			toBytes(nameLength)[0 .. SizeNameType.sizeof] = con[0 .. SizeNameType.sizeof];
679 			con = con[SizeNameType.sizeof .. $];
680 			name = cast(string) con[0 .. nameLength];
681 			con = con[nameLength .. $];
682 		} else {
683 			assert(name.length <= SizeNameType.max);
684 			SizeNameType nameLength = cast(SizeNameType) name.length;
685 			con ~= toBytes(nameLength);
686 			con ~= cast(ubyte[]) name;
687 		}
688 		//writeln(name.length);
689 	}
690 
691 	private static void serializeTypeNoPop(Load load, COS)(ref VariableType type, ref COS con) {
692 		static assert(load == Load.yes);
693 
694 		type = cast(VariableType) con[0];
695 
696 	}
697 
698 	private static void serializeSize(Load load, COS)(ref SizeType size, ref COS con) {
699 		if (load == Load.yes) {
700 			toBytes(size)[0 .. SizeType.sizeof] = con[0 .. SizeType.sizeof];
701 			con = con[SizeType.sizeof .. $];
702 		} else {
703 			con ~= toBytes(size);
704 		}
705 	}
706 
707 	private static void serializeSizeNoPop(Load load, COS)(ref SizeType size, ref COS con) {
708 		static assert(load == Load.yes);
709 
710 		toBytes(size)[0 .. SizeType.sizeof] = con[0 .. SizeType.sizeof];
711 	}
712 
713 }
714 
715 import MSC;
716 
717 // test basic type
718 unittest {
719 	int test = 1;
720 
721 	CON_UB container;
722 
723 	//save
724 	BinarySerializerMaped.serializeWithName!(Load.no, "name",)(test, container);
725 	assert(container.length == SizeNameType.sizeof + 4 + VariableType.sizeof + 4);
726 
727 	//reset var
728 	test = 0;
729 	//load
730 	ubyte[] dataSlice = container[];
731 	BinarySerializerMaped.serializeWithName!(Load.yes, "name",)(test, dataSlice);
732 	assert(test == 1);
733 	//assert(dataSlice.length==0);
734 }
735 
736 unittest {
737 	static struct Test {
738 		int a;
739 		long b;
740 		ubyte c;
741 	}
742 
743 	static struct TestB {
744 		int bbbb;
745 		long c;
746 		char a;
747 	}
748 
749 	Test test = Test(1, 2, 3);
750 	Vector!ubyte container;
751 	//save
752 	BinarySerializerMaped.serializeWithName!(Load.no, "name",)(test, container);
753 	assert(container.length == SizeNameType.sizeof + 4 + VariableType.sizeof
754 			+ SizeType.sizeof + 3 * SizeNameType.sizeof + 3 + 3 * VariableType.sizeof + 4 + 8 + 1);
755 	//writeln("Ratio to ideal minimal size: ", container.length/(4.0f+8.0f+1.0f));
756 	//reset var
757 	TestB testB;
758 
759 	//load
760 	ubyte[] dataSlice = container[];
761 	BinarySerializerMaped.serializeWithName!(Load.yes, "name",)(testB, dataSlice);
762 	assert(testB == TestB(0, 3, 1));
763 }
764 // empty struct
765 unittest {
766 	static struct Test {
767 	}
768 
769 	static struct TestB {
770 		int aa;
771 		int bb;
772 	}
773 
774 	Test test = Test();
775 	Vector!ubyte container;
776 	//save
777 	BinarySerializerMaped.serializeWithName!(Load.no, "name",)(test, container);
778 	//reset var
779 	TestB testB;
780 	//load
781 	ubyte[] dataSlice = container[];
782 	BinarySerializerMaped.serializeWithName!(Load.yes, "name",)(testB, dataSlice);
783 
784 }
785 
786 // vectors
787 unittest {
788 	static struct Test {
789 		int[4] aa;
790 		Vector!ubyte bb;
791 		int[3] cc;
792 	}
793 
794 	static struct TestB {
795 		Vector!long bb;
796 		int[2] aa;
797 		Vector!int cc;
798 	}
799 
800 	enum ubyte[] bytesA = [3, 2, 1];
801 	enum long[] bytesB = [3, 2, 1];
802 	Test test = Test([1, 2, 3, 4], Vector!ubyte(bytesA), [10, 20, 30]);
803 	Vector!ubyte container;
804 	//save
805 	BinarySerializerMaped.serializeWithName!(Load.no, "name",)(test, container);
806 
807 	//reset var
808 	TestB testB;
809 	//load
810 	ubyte[] dataSlice = container[];
811 	BinarySerializerMaped.serializeWithName!(Load.yes, "name",)(testB, dataSlice);
812 
813 	assert(testB == TestB(Vector!long(bytesB), [1, 2], Vector!int([10, 20, 30])));
814 }
815 
816 // test custom map
817 unittest {
818 	import mutils.container.hash_map;
819 
820 	static struct TestStruct {
821 		int a;
822 		int b;
823 	}
824 
825 	static struct TestStructB {
826 		ushort b;
827 		long a;
828 		char c;
829 	}
830 
831 	HashMap!(int, TestStruct) map;
832 	map.add(1, TestStruct(1, 11));
833 	map.add(7, TestStruct(7, 77));
834 
835 	Vector!ubyte container;
836 
837 	//save
838 	BinarySerializerMaped.serializeWithName!(Load.no, "name",)(map, container);
839 
840 	//reset var
841 	HashMap!(byte, TestStructB) mapB;
842 	//load
843 	ubyte[] dataSlice = container[];
844 	BinarySerializerMaped.serializeWithName!(Load.yes, "name",)(mapB, dataSlice);
845 	assert(mapB.get(1) == TestStructB(11, 1));
846 	assert(mapB.get(7) == TestStructB(77, 7));
847 }
848 
849 // test string
850 unittest {
851 	import mutils.container.string_intern;
852 
853 	static struct Test {
854 		Vector!char aa;
855 		StringIntern bb;
856 	}
857 
858 	static struct TestB {
859 		Vector!char bb;
860 		StringIntern aa;
861 	}
862 
863 	Test test = Test(Vector!char("aaa"), StringIntern("bbb"));
864 	Vector!ubyte container;
865 	//save
866 	BinarySerializerMaped.serializeWithName!(Load.no, "name",)(test, container);
867 	//reset var
868 	TestB testB;
869 	//load
870 	ubyte[] dataSlice = container[];
871 	BinarySerializerMaped.serializeWithName!(Load.yes, "name",)(testB, dataSlice);
872 	assert(testB.aa == "aaa");
873 	assert(testB.bb[] == "bbb");
874 
875 }
876 
877 // test enum
878 unittest {
879 
880 	enum EnumA {
881 		aaa = 10,
882 		bbb = 20,
883 	}
884 
885 	enum EnumB {
886 		bbb = 10,
887 		aaa = 20,
888 	}
889 
890 	EnumA test = EnumA.aaa;
891 	Vector!ubyte container;
892 	//save
893 	BinarySerializerMaped.serializeWithName!(Load.no, "name",)(test, container);
894 	//reset var
895 	EnumB testB;
896 	//load
897 	ubyte[] dataSlice = container[];
898 	BinarySerializerMaped.serializeWithName!(Load.yes, "name",)(testB, dataSlice);
899 	assert(testB == EnumB.aaa);
900 }