1 /**
2 Copyright: Copyright (c) 2014 Andrey Penechko.
3 License: a$(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 
6 Some code is based on msgpack-d by Masahiro Nakagawa.
7 
8 Concise Binary Object Representation (CBOR) for D lang.
9 
10 The Concise Binary Object Representation (CBOR) is a data format
11 whose design goals include the possibility of extremely small code
12 size, fairly small message size, and extensibility without the need
13 for version negotiation.  These design goals make it different from
14 earlier binary serializations such as ASN.1 and MessagePack.
15 
16 Standards: Conforms to RFC 7049.
17 */
18 
19 module cbor;
20 
21 private import std.string : format;
22 private import std.traits;
23 private import std.typecons : Flag;
24 
25 //version = Cbor_Debug;
26 
27 /// Thrown in a case of decoding error.
28 class CborException : Exception
29 {
30 	@trusted pure this(string message, string file = __FILE__, size_t line = __LINE__)
31 	{
32 		super(message, file, line);
33 	}
34 }
35 
36 //------------------------------------------------------------------------------
37 //		 SSSSS  TTTTTTT  OOOOO  RRRRRR    AAA     GGGG  EEEEEEE 
38 //		SS        TTT   OO   OO RR   RR  AAAAA   GG  GG EE      
39 //		 SSSSS    TTT   OO   OO RRRRRR  AA   AA GG      EEEEE   
40 //		     SS   TTT   OO   OO RR  RR  AAAAAAA GG   GG EE      
41 //		 SSSSS    TTT    OOOO0  RR   RR AA   AA  GGGGGG EEEEEEE 
42 //------------------------------------------------------------------------------
43 
44 /// Tagged union for CBOR items.
45 align(1) struct CborValue
46 {
47 	align(1):
48 	enum Type : ubyte
49 	{
50 		boolean,
51 		nil,
52 		undefined,
53 
54 		posinteger,
55 		neginteger,
56 		floating,
57 		
58 		array,
59 		map,
60 		
61 		raw,
62 		text,
63 	}
64 
65 	static union Via
66 	{
67 		bool boolean;
68 		long integer;
69 		ulong uinteger;
70 		double floating;
71 		
72 		CborValue[] array;
73 		CborValue[CborValue] map;
74 		
75 		ubyte[] raw;
76 		string text;
77 	}
78 
79 	Type type;
80 	Via via;
81 
82 	/**
83 	 * Constructs a $(D CborValue) with arguments.
84 	 *
85 	 * Params:
86 	 *  value = the real content.
87 	 *  type  = the type of value.
88 	 */
89 	@safe
90 	this(Type type = Type.nil)
91 	{
92 		this.type = type;
93 	}
94 
95 	@safe
96 	this(typeof(null))
97 	{
98 		this(Type.nil);
99 	}
100 
101 	/// ditto
102 	@trusted
103 	this(bool value, Type type = Type.boolean)
104 	{
105 		this(type);
106 		via.boolean = value;
107 	}
108 
109 
110 	/// ditto
111 	@trusted
112 	this(T)(T value) if (isIntegral!T)
113 	{
114 		if (value < 0)
115 		{
116 			this(Type.neginteger);
117 			via.integer = value;
118 		}
119 		else
120 		{
121 			this(Type.posinteger);
122 			via.uinteger = value;
123 		}
124 	}
125 
126 
127 	/// ditto
128 	@trusted
129 	this(T)(T value, Type type = Type.floating) if (isFloatingPoint!T)
130 	{
131 		this(type);
132 		via.floating = value;
133 	}
134 
135 
136 	/// ditto
137 	@trusted
138 	this(CborValue[] value, Type type = Type.array)
139 	{
140 		this(type);
141 		via.array = value;
142 	}
143 
144 
145 	/// ditto
146 	@trusted
147 	this(CborValue[CborValue] value, Type type = Type.map)
148 	{
149 		this(type);
150 		via.map = value;
151 	}
152 
153 
154 	/// ditto
155 	@trusted
156 	this(ubyte[] value, Type type = Type.raw)
157 	{
158 		this(type);
159 		via.raw = value;
160 	}
161 
162 	/// ditto
163 	@trusted
164 	this(string value, Type type = Type.text)
165 	{
166 		this(type);
167 		via.text = value;
168 	}
169 
170 
171 	/**
172 	 * Converts value to $(D_PARAM T) type.
173 	 *
174 	 * Returns:
175 	 *  converted value.
176 	 *
177 	 * Throws:
178 	 *  CborException if type is mismatched.
179 	 *
180 	 * NOTE:
181 	 *  Current implementation uses cast.
182 	 */
183 	@property @trusted
184 	T as(T)() if (is(Unqual!T == bool))
185 	{
186 		if (type != Type.boolean)
187 			onCastErrorToFrom!T(type);
188 
189 		return via.boolean;
190 	}
191 
192 
193 	/// ditto
194 	@property @trusted
195 	T as(T)() if (isIntegral!T && !is(Unqual!T == enum))
196 	{
197 		if (type == Type.neginteger)
198 			return cast(T)via.integer;
199 
200 		if (type == Type.posinteger)
201 			return cast(T)via.uinteger;
202 
203 		onCastErrorToFrom!T(type);
204 
205 		assert(false);
206 	}
207 
208 
209 	/// ditto
210 	@property @trusted
211 	T as(T)() if (isFloatingPoint!T && !is(Unqual!T == enum))
212 	{
213 		if (type != Type.floating)
214 			onCastErrorToFrom!T(type);
215 
216 		return cast(T)via.floating;
217 	}
218 
219 
220 	/// ditto
221 	@property @trusted
222 	T as(T)() if (is(Unqual!T == enum))
223 	{
224 		return cast(T)as!(OriginalType!T);
225 	}
226 
227 
228 	/// ditto
229 	@property @trusted
230 	T as(T)() if (isArray!T && !is(Unqual!T == enum))
231 	{
232 		alias V = typeof(T.init[0]);
233 
234 		if (type == Type.nil)
235 		{
236 			static if (isDynamicArray!T)
237 			{
238 				return null;
239 			}
240 			else
241 			{
242 				return T.init;
243 			}
244 		}
245 
246 		static if (is(V == ubyte))
247 		{
248 			if (type != Type.raw)
249 				onCastErrorToFrom!T(type);
250 
251 			static if (isDynamicArray!T)
252 			{
253 				return cast(T)via.raw;
254 			}
255 			else
256 			{
257 				if (via.raw.length != T.length)
258 					onCastErrorToFrom!T(type);
259 
260 				return cast(T)(via.raw[0 .. T.length]);
261 			}
262 		}
263 		else static if(is(T == string))
264 		{
265 			if (type != Type.text)
266 				onCastErrorToFrom!T(type);
267 
268 			static if (isDynamicArray!T)
269 			{
270 				return cast(T)via.text;
271 			}
272 			else
273 			{
274 				if (via.text.length != T.length)
275 					onCastErrorToFrom!T(type);
276 
277 				return cast(T)(via.text[0 .. T.length]);
278 			}
279 		}
280 		else
281 		{
282 			if (type != Type.array)
283 				onCastErrorToFrom!T(type);
284 
285 			V[] array = new V[via.array.length];
286 
287 			foreach (i, elem; via.array)
288 				array[i] = elem.as!(V);
289 
290 			return array;
291 		}
292 	}
293 
294 
295 	/// ditto
296 	@property @trusted
297 	T as(T)() if (isAssociativeArray!T)
298 	{
299 		alias K = typeof(T.init.keys[0]);
300 		alias V = typeof(T.init.values[0]);
301 
302 		if (type == Type.nil)
303 			return null;
304 
305 		if (type != Type.map)
306 			onCastErrorToFrom!T(type);
307 
308 		V[K] map;
309 
310 		foreach (key, value; via.map)
311 			map[key.as!(K)] = value.as!(V);
312 
313 		return map;
314 	}
315 
316 
317 	/// ditto
318 	@property @trusted
319 	T as(T)()
320 		if (is(T == struct) || is(T == class) || isTuple!T)
321 	{
322 		static if (is(T == class))
323 			if (type == CborValue.Type.nil)
324 				return null;
325 
326 		if (type != CborValue.Type.array)
327 			throw new CborException(format("Can not decode %s from %s", T.stringof, type));
328 
329 		T obj;
330 
331 		size_t arrLength = via.array.length;
332 		size_t numMembers;
333 
334 		static if (isTuple!T)
335 			numMembers = T.Types.length;
336 		else
337 			numMembers = numEncodableMembers!T;
338 
339 		if (arrLength != numMembers)
340 		{
341 			throw new CborException(
342 				format("The number of deserialized members of %s is mismatched."~
343 					" Got %s, while expected %s members",
344 						T.stringof, numMembers, arrLength));
345 		}
346 
347 		static if (isTuple!T)
348 		{
349 			foreach (i, Type; T.Types)
350 				obj.field[i] = via.array[i].as!(Type);
351 		}
352 		else 
353 		{  // simple struct
354 			static if (is(T == class))
355 				obj = new T();
356 
357 			foreach(i, ref member; obj.tupleof)
358 			{
359 				static if (isEncodedField!(typeof(member)))
360 					member = via.array[i].as!(typeof(member));
361 			}
362 		}
363 
364 		return obj;
365 	}
366 
367 
368 	/// Comparison for equality.
369 	@trusted
370 	bool opEquals()(auto ref const CborValue other) const
371 	{
372 		if (type != other.type)
373 			return false;
374 	
375 		final switch(other.type)
376 		{
377 			case Type.boolean: return opEquals(other.via.boolean);
378 			case Type.nil: return type == Type.nil;
379 			case Type.undefined: return type == Type.undefined;
380 			case Type.neginteger: return opEquals(other.via.integer);
381 			case Type.posinteger: return opEquals(other.via.uinteger);
382 			case Type.floating: return opEquals(other.via.floating);
383 			case Type.array: return opEquals(other.via.array);
384 			case Type.map: return opEquals(other.via.map);
385 			case Type.raw: return opEquals(other.via.raw);
386 			case Type.text: return opEquals(other.via.text);
387 		}
388 	}
389 
390 
391 	/// ditto
392 	@trusted
393 	bool opEquals(T : bool)(const T other) const
394 	{
395 		if (type != Type.boolean)
396 			return false;
397 
398 		return via.boolean == other;
399 	}
400 
401 
402 	/// ditto
403 	@trusted
404 	bool opEquals(T)(const T other) const if (isIntegral!T && !is(T == typeof(null)))
405 	{
406 		static if (isUnsigned!T)
407 		{
408 			if (type == Type.posinteger)
409 				return via.uinteger == other;
410 			else
411 				return false;
412 		}
413 		else
414 		{
415 			if (type == Type.neginteger || type == Type.posinteger)
416 				return via.integer == other;
417 			else
418 				return false;
419 		}
420 	}
421 
422 
423 	/// ditto
424 	@trusted
425 	bool opEquals(T)(const T other) const if (isFloatingPoint!T)
426 	{
427 		if (type != Type.floating)
428 			return false;
429 
430 		return via.floating == other;
431 	}
432 
433 
434 	/// ditto
435 	@trusted
436 	bool opEquals(T)(const typeof(null) other) const if (is(T == typeof(null)))
437 	{
438 		if (type == Type.array || type == Type.raw || type == Type.text)
439 		{
440 			return via.raw.length == 0;
441 		}
442 		else if (type == Type.map)
443 		{
444 			return via.map.length == 0;
445 		}
446 
447 		return false;
448 	}
449 
450 
451 	/// ditto
452 	@trusted
453 	bool opEquals(T : const CborValue[])(const T other) const if (!is(T == typeof(null)))
454 	{
455 		if (type != Type.array)
456 			return false;
457 
458 		return via.array == other;
459 	}
460 
461 	/// ditto
462 	@trusted
463 	bool opEquals(T : const(V)[], V)(const T other) const if (!is(T == typeof(null)))
464 	{
465 		if (type != Type.array)
466 			return false;
467 
468 		if (other.length != via.array.length) return false;
469 
470 		auto arr = via.array;
471 
472 		foreach(i, ref item; other)
473 		{
474 			if (item != arr[i]) return false;
475 		}
476 
477 		return true;
478 	}
479 
480 
481 	/// ditto
482 	@trusted
483 	bool opEquals(T : const CborValue[CborValue])(const T other) const if (!is(T == typeof(null)))
484 	{
485 		if (type != Type.map)
486 			return false;
487 
488 		// This comparison is instead of default comparison because 'via.map == other' raises "Access Violation".
489 		foreach (key, value; via.map) {
490 			if (key in other) {
491 				if (other[key] != value)
492 					return false;
493 			} else {
494 				return false;
495 			}
496 		}
497 
498 		return true;
499 	}
500 
501 	/// ditto
502 	@trusted
503 	bool opEquals(T : const V[K], K, V)(const T other) const if (!is(T == typeof(null)))
504 	{
505 		if (type != Type.map)
506 			return false;
507 
508 		// This comparison is instead of default comparison because 'via.map == other' raises "Access Violation".
509 		auto map = via.map;
510 
511 		if (map.length != other.length) return false;
512 
513 		foreach (key, value; other) {
514 			if (auto thisVal = CborValue(key) in map) {
515 				if (*thisVal != value)
516 					return false;
517 			} else {
518 				return false;
519 			}
520 		}
521 
522 		return true;
523 	}
524 
525 
526 	/// ditto
527 	@trusted
528 	bool opEquals(T : const(ubyte)[])(const T other) const if (!is(T == typeof(null)))
529 	{
530 		if (type != Type.raw)
531 			return false;
532 
533 		return via.raw == other;
534 	}
535 
536 
537 	/// ditto
538 	@trusted
539 	bool opEquals(T : string)(const T other) const if (!is(T == typeof(null)))
540 	{
541 		if (type != Type.text)
542 			return false;
543 
544 		return via.text == other;
545 	}
546 
547 	/// Hashing.
548 	size_t toHash() const nothrow @trusted
549 	{
550 		final switch(type)
551 		{
552 			case Type.boolean: return typeid(bool).getHash(&via.boolean);
553 			case Type.nil: return 0;
554 			case Type.undefined: return size_t.max;
555 			case Type.neginteger: return typeid(long).getHash(&via.integer);
556 			case Type.posinteger: return typeid(ulong).getHash(&via.uinteger);
557 			case Type.floating: return typeid(real).getHash(&via.floating);
558 			case Type.array: return typeid(CborValue[]).getHash(&via.array);
559 			case Type.map: return typeid(CborValue[CborValue]).getHash(&via.map);
560 			case Type.raw: return typeid(ubyte[]).getHash(&via.raw);
561 			case Type.text: return typeid(string).getHash(&via.text);
562 		}
563 	}
564 
565 	/// String representation.
566 	string toString()
567 	{
568 		import std.string : format;
569 		final switch(type)
570 		{
571 			case Type.boolean: return format("CborValue(%s)", via.boolean);
572 			case Type.nil: return "CborValue(null)";
573 			case Type.undefined: return "CborValue(undefined)";
574 			case Type.neginteger: return format("CborValue(%s, %s)", type, via.integer);
575 			case Type.posinteger: return format("CborValue(%s, %s)", type, via.uinteger);
576 			case Type.floating: return format("CborValue(%s, %s)", type, via.floating);
577 			case Type.array: return format("CborValue(%s, %s)", type, via.array);
578 			case Type.map: return format("CborValue(%s, %s)", type, via.map);
579 			case Type.raw: return format("CborValue(%s, %s)", type, via.raw);
580 			case Type.text: return format("CborValue(%s, \"%s\")", type, via.text);
581 		}
582 	}
583 }
584 
585 //------------------------------------------------------------------------------
586 //		EEEEEEE NN   NN  CCCCC   OOOOO  DDDDD   IIIII NN   NN   GGGG  
587 //		EE      NNN  NN CC    C OO   OO DD  DD   III  NNN  NN  GG  GG 
588 //		EEEEE   NN N NN CC      OO   OO DD   DD  III  NN N NN GG      
589 //		EE      NN  NNN CC    C OO   OO DD   DD  III  NN  NNN GG   GG 
590 //		EEEEEEE NN   NN  CCCCC   OOOO0  DDDDDD  IIIII NN   NN  GGGGGG 
591 //------------------------------------------------------------------------------
592 
593 
594 private import std.range : isInputRange, isOutputRange, ElementType;
595 private import std.typecons : isTuple;
596 
597 /// Encodes value E into output range sink.
598 /// Returns number of bytes written to sink.
599 size_t encodeCbor(R, E)(auto ref R sink, E value)
600 	if(isOutputRange!(R, ubyte))
601 {
602 	import std.typecons : isTuple;
603 
604 	static if (isIntegral!E)
605 	{
606 		return encodeCborInt(sink, value);
607 	}
608 	else static if (isFloatingPoint!E)
609 	{
610 		return encodeCborFloat(sink, value);
611 	}
612 	else static if (isBoolean!E)
613 	{
614 		return encodeCborBool(sink, value);
615 	}
616 	else static if (is(E == typeof(null)))
617 	{
618 		return encodeCborNull(sink, value);
619 	}
620 	else static if (isInputRange!E && is(ElementType!E == ubyte))
621 	{
622 		return encodeCborRaw(sink, value);
623 	}
624 	else static if (is(E == string))
625 	{
626 		return encodeCborString(sink, value);
627 	}
628 	else static if (isInputRange!E || isArray!E || isTuple!E ||
629 		is(E == class) || is(E == struct))
630 	{
631 		return encodeCborArray(sink, value);
632 	}
633 	else static if (isAssociativeArray!E)
634 	{
635 		return encodeCborMap(sink, value);
636 	}
637 	else
638 	{
639 		static assert(false, "Unable to encode " ~ E.stringof);
640 	}
641 }
642 
643 // Encode integer types as separate type or as part of arrays or map.
644 private size_t encodeLongType(R)(auto ref R sink, ubyte majorType, ulong length)
645 	if(isOutputRange!(R, ubyte))
646 {
647 	import std.bitmanip : nativeToBigEndian;
648 	import std.array;
649 
650 	majorType <<= 5;
651 	if (length < 24) {
652 		putChecked(sink, cast(ubyte)(majorType | length));
653 		return 1;
654 	} else if (length <= ubyte.max) {
655 		putChecked(sink, cast(ubyte)(majorType | 24));
656 		putChecked(sink, cast(ubyte)length);
657 		return 2;
658 	} else if (length <= ushort.max) {
659 		putChecked(sink, cast(ubyte)(majorType | 25));
660 		putChecked(sink, nativeToBigEndian!ushort(cast(ushort)length)[]);
661 		return 3;
662 	} else if (length <= uint.max) {
663 		putChecked(sink, cast(ubyte)(majorType | 26));
664 		putChecked(sink, nativeToBigEndian!uint(cast(uint)length)[]);
665 		return 5;
666 	} else { // if (length <= ulong.max)
667 		putChecked(sink, cast(ubyte)(majorType | 27));
668 		putChecked(sink, nativeToBigEndian!ulong(cast(ulong)length)[]);
669 		return 9;
670 	}
671 }
672 
673 /// Encodes integer.
674 size_t encodeCborInt(R, E)(auto ref R sink, E value)
675 	if(isOutputRange!(R, ubyte) && isIntegral!E)
676 {
677 	ulong val;
678 	ubyte majorType;
679 	
680 	if (value < 0) {
681 		val = -value - 1;
682 		majorType = 1;
683 	} else {
684 		val = value;
685 		majorType = 0;
686 	}
687 
688 	return encodeLongType(sink, majorType, val);
689 }
690 
691 /// Encodes floating.
692 size_t encodeCborFloat(R, E)(auto ref R sink, E value)
693 	if(isOutputRange!(R, ubyte) && isFloatingPoint!E)
694 {
695 	import std.bitmanip : nativeToBigEndian;
696 	enum majorType = 7 << 5;
697 
698 
699 	static if (is(E == float))
700 	{
701 		
702 		__FloatRep flt;
703 		flt.f = value;
704 		putChecked(sink, cast(ubyte)(majorType | 26));
705 		putChecked(sink, nativeToBigEndian!uint(flt.u)[]);
706 		return 5;
707 	}
708 	else static if (is(E == double) || is(E == real))
709 	{
710 		
711 		__DoubleRep dbl;
712 		dbl.d = cast(double)value;
713 		putChecked(sink, cast(ubyte)(majorType | 27));
714 		putChecked(sink, nativeToBigEndian!ulong(dbl.u)[]);
715 		return 9;
716 	}
717 }
718 
719 /// Encodes boolean.
720 size_t encodeCborBool(R, E)(auto ref R sink, E value)
721 	if(isOutputRange!(R, ubyte) && isBoolean!E)
722 {
723 	if (value)
724 		putChecked(sink, cast(ubyte)0xf5);
725 	else
726 		putChecked(sink, cast(ubyte)0xf4);
727 	return 1;
728 }
729 
730 /// Encodes null.
731 size_t encodeCborNull(R, E)(auto ref R sink, E value)
732 	if(isOutputRange!(R, ubyte) && is(E == typeof(null)))
733 {
734 	
735 	putChecked(sink, cast(ubyte)0xf6);
736 	return 1;
737 }
738 
739 /// Encodes range of ubytes.
740 size_t encodeCborRaw(R, E)(auto ref R sink, E value)
741 	if(isOutputRange!(R, ubyte) && is(ElementType!E == ubyte))
742 {
743 	auto size = encodeLongType(sink, 2, value.length);
744 	size += value.length;
745 	putChecked(sink, value);
746 	return size;
747 }
748 
749 /// Encodes string.
750 size_t encodeCborString(R, E)(auto ref R sink, E value)
751 	if(isOutputRange!(R, ubyte) && is(E == string))
752 {
753 	auto size = encodeLongType(sink, 3, value.length);
754 	size += value.length;
755 	putChecked(sink, cast(ubyte[])value);
756 	return size;
757 }
758 
759 /// Encodes array of any items or a tuple as cbor array.
760 size_t encodeCborArray(R, E)(auto ref R sink, E value)
761 	if(isOutputRange!(R, ubyte) &&
762 	(isInputRange!E || isArray!E || isTuple!E))
763 {
764 	static if (is(E == void[])) // accept []
765 	{
766 		return encodeCborArrayHead(sink, 0);
767 	}
768 	else
769 	{
770 		auto size = encodeCborArrayHead(sink, value.length);
771 		foreach(item; value)
772 			size += encodeCbor(sink, item);
773 		return size;
774 	}
775 }
776 
777 /// Encodes structs and classes as cbor array.
778 size_t encodeCborArray(R, A)(auto ref R sink, A aggregate)
779 	if(isOutputRange!(R, ubyte) &&
780 		(is(A == struct) || is(A == class)) &&
781 		!isTuple!A)
782 {
783 	return encodeCborAggregate!(Flag!"WithFieldName".no)(sink, aggregate);
784 }
785 
786 /// Encodes asociative array as cbor map.
787 size_t encodeCborMap(R, E)(auto ref R sink, E value)
788 	if(isOutputRange!(R, ubyte) && isAssociativeArray!E)
789 {
790 	auto size = encodeCborMapHead(sink, value.length);
791 	foreach(key, element; value)
792 	{
793 		size += encodeCbor(sink, key);
794 		size += encodeCbor(sink, element);
795 	}
796 	return size;
797 }
798 
799 /// Encodes structs and classes as cbor map.
800 /// Note, that decoding of structs and classes from maps is not supported (yet).
801 size_t encodeCborMap(R, A)(auto ref R sink, A aggregate)
802 	if(isOutputRange!(R, ubyte) &&
803 		(is(A == struct) || is(A == class)) &&
804 		!isTuple!A)
805 {
806 	return encodeCborAggregate!(Flag!"WithFieldName".yes)(sink, aggregate);
807 }
808 
809 /// Encode array head with arrayLength elements.
810 /// arrayLength items must follow.
811 size_t encodeCborArrayHead(R)(auto ref R sink, ulong arrayLength)
812 	if(isOutputRange!(R, ubyte))
813 {
814 	return encodeLongType(sink, 4, arrayLength);
815 }
816 
817 /// Encode map head with mapLength elements.
818 /// mapLength pairs of items must follow. Keys first, then values.
819 size_t encodeCborMapHead(R)(auto ref R sink, ulong mapLength)
820 	if(isOutputRange!(R, ubyte))
821 {
822 	return encodeLongType(sink, 5, mapLength);
823 }
824 
825 /// Encodes classes and structs. If withFieldName is yes, than value is encoded as map.
826 /// If withFieldName is no, then value is encoded as an array.
827 size_t encodeCborAggregate(Flag!"WithFieldName" withFieldName, R, A)(auto ref R sink, auto ref A aggregate)
828 	if (isOutputRange!(R, ubyte) && (is(A == struct) || is(A == class)))
829 {
830 	size_t size;
831 	static if (is(A == class))
832 		if (aggregate is null)
833 			return encodeCbor(sink, null);
834 
835 	size += encodeCborArrayHead(sink, numEncodableMembers!A);
836 	foreach(i, member; aggregate.tupleof)
837 	{
838 		static if (__traits(compiles, { encodeCbor(sink, member); }))
839 		{
840 			static if (withFieldName)
841 				size += encodeCborString(sink, __traits(identifier, aggregate.tupleof[i]));
842 			size += encodeCbor(sink, member);
843 		}
844 	}
845 	return size;
846 }
847 
848 //------------------------------------------------------------------------------
849 //		DDDDD   EEEEEEE  CCCCC   OOOOO  DDDDD   IIIII NN   NN   GGGG  
850 //		DD  DD  EE      CC    C OO   OO DD  DD   III  NNN  NN  GG  GG 
851 //		DD   DD EEEEE   CC      OO   OO DD   DD  III  NN N NN GG      
852 //		DD   DD EE      CC    C OO   OO DD   DD  III  NN  NNN GG   GG 
853 //		DDDDDD  EEEEEEE  CCCCC   OOOO0  DDDDDD  IIIII NN   NN  GGGGGG 
854 //------------------------------------------------------------------------------
855 
856 
857 /// Decodes single value and returns it as CborValue tagged union type.
858 /// Throws CborException if data is not well-formed.
859 /// Note, that ubyte[] and string types are slices of input range if ubyte[] was provided.
860 /// Will modify input range, popping all the bytes of the first item.
861 CborValue decodeCbor(R)(auto ref R input)
862 	if(isInputRange!R && is(ElementType!R == ubyte))
863 {
864 	import std.array;
865 	import std.bitmanip;
866 	
867 	// tags will be ignored and decoding will restart from here
868 	start_label:
869 
870 	assert(!input.empty);
871 	if (input.empty) onInsufficientInput();
872 
873 	ubyte item = input.front;
874 	input.popFront;
875 
876 	switch(item)
877 	{
878 		case 0x00: .. case 0x17: // Integer 0x00..0x17 (0..23)
879 			return CborValue(item);
880 		case 0x18: // Unsigned integer (one-byte uint8_t follows)
881 			return CborValue(readInteger!ubyte(input));
882 		case 0x19: // Unsigned integer (two-byte uint16_t follows)
883 			return CborValue(readInteger!ushort(input));
884 		case 0x1a: // Unsigned integer (four-byte uint_t follows)
885 			return CborValue(readInteger!uint(input));
886 		case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
887 			return CborValue(readInteger!ulong(input));
888 		case 0x20: .. case 0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24)
889 			return CborValue(cast(byte)(-1 - item + 0x20));
890 		case 0x38: // Negative integer -1-n (one-byte uint8_t for n follows)
891 			return CborValue(-1 - cast(long)readInteger!ubyte(input));
892 		case 0x39: // Negative integer -1-n (two-byte uint16_t for n follows)
893 			return CborValue(-1 - cast(long)readInteger!ushort(input));
894 		case 0x3a: // Negative integer -1-n (four-byte uint_t for n follows)
895 			return CborValue(-1 - cast(long)readInteger!uint(input));
896 		case 0x3b: // Negative integer -1-n (eight-byte uint64_t for n follows)
897 			return CborValue(-1 - cast(long)readInteger!ulong(input));
898 		case 0x40: .. case 0x57: // byte string (0x00..0x17 bytes follow)
899 			return CborValue(readBytes(input, item - 0x40));
900 		case 0x58: // byte string (one-byte uint8_t for n, and then n bytes follow)
901 			return CborValue(readBytes(input, readInteger!ubyte(input)));
902 		case 0x59: // byte string (two-byte uint16_t for n, and then n bytes follow)
903 			return CborValue(readBytes(input, readInteger!ushort(input)));
904 		case 0x5a: // byte string (four-byte uint_t for n, and then n bytes follow)
905 			return CborValue(readBytes(input, readInteger!uint(input)));
906 		case 0x5b: // byte string (eight-byte uint64_t for n, and then n bytes follow)
907 			return CborValue(readBytes(input, readInteger!ulong(input)));
908 		case 0x5f: // byte string, byte strings follow, terminated by "break"
909 			onUnsupportedTag(item); break;
910 		case 0x60: .. case 0x77: // UTF-8 string (0x00..0x17 bytes follow)
911 			return CborValue(cast(string)readBytes(input, item - 0x60));
912 		case 0x78: // UTF-8 string (one-byte uint8_t for n, and then n bytes follow)
913 			return CborValue(cast(string)readBytes(input, readInteger!ubyte(input)));
914 		case 0x79: // UTF-8 string (two-byte uint16_t for n, and then n bytes follow)
915 			return CborValue(cast(string)readBytes(input, readInteger!ushort(input)));
916 		case 0x7a: // UTF-8 string (four-byte uint_t for n, and then n bytes follow)
917 			return CborValue(cast(string)readBytes(input, readInteger!uint(input)));
918 		case 0x7b: // UTF-8 string (eight-byte uint64_t for n, and then n bytes follow)
919 			return CborValue(cast(string)readBytes(input, readInteger!ulong(input)));
920 		case 0x7f: // UTF-8 string, UTF-8 strings follow, terminated by "break"
921 			onUnsupportedTag(item); break;
922 		case 0x80: .. case 0x97: // array (0x00..0x17 data items follow)
923 			return CborValue(readArray(input, item - 0x80));
924 		case 0x98: // array (one-byte uint8_t for n, and then n data items follow)
925 			return CborValue(readArray(input, readInteger!ubyte(input)));
926 		case 0x99: // array (two-byte uint16_t for n, and then n data items follow)
927 			return CborValue(readArray(input, readInteger!ushort(input)));
928 		case 0x9a: // array (four-byte uint_t for n, and then n data items follow)
929 			return CborValue(readArray(input, readInteger!uint(input)));
930 		case 0x9b: // array (eight-byte uint64_t for n, and then n data items follow)
931 			return CborValue(readArray(input, readInteger!ulong(input)));
932 		case 0x9f: // array, data items follow, terminated by "break"
933 			onUnsupportedTag(item); break;
934 		case 0xa0: .. case 0xb7: // map (0x00..0x17 pairs of data items follow)
935 			return CborValue(readMap(input, item - 0xa0));
936 		case 0xb8: // map (one-byte uint8_t for n, and then n pairs of data items follow)   
937 			return CborValue(readMap(input, readInteger!ubyte(input)));
938 		case 0xb9: // map (two-byte uint16_t for n, and then n pairs of data items follow)
939 			return CborValue(readMap(input, readInteger!ushort(input)));
940 		case 0xba: // map (four-byte uint_t for n, and then n pairs of data items follow)
941 			return CborValue(readMap(input, readInteger!uint(input)));
942 		case 0xbb: // map (eight-byte uint64_t for n, and then n pairs of data items follow)
943 			return CborValue(readMap(input, readInteger!ulong(input)));
944 		case 0xbf: // map, pairs of data items follow, terminated by "break"
945 			onUnsupportedTag(item); break;
946 		case 0xc0: .. case 0xd7: // (tagged item) ignore
947 			goto start_label;
948 		case 0xd8: // ignore 1-byte tag
949 			dropBytes(input, 1);
950 			goto start_label;
951 		case 0xd9: // ignore 2-byte tag
952 			dropBytes(input, 2);
953 			goto start_label;
954 		case 0xda: // ignore 4-byte tag
955 			dropBytes(input, 4);
956 			goto start_label;
957 		case 0xdb: // ignore 8-byte tag
958 			dropBytes(input, 8);
959 			goto start_label;
960 		case 0xe0: .. case 0xf3: // (simple value)
961 			onUnsupportedTag(item); break;
962 		case 0xf4: // False
963 			return CborValue(false);
964 		case 0xf5: // True
965 			return CborValue(true);
966 		case 0xf6: // Null
967 			return CborValue(null);
968 		case 0xf7: // Undefined
969 			return CborValue(CborValue.Type.undefined);
970 		case 0xf8: // (simple value, one byte follows)
971 			onUnsupportedTag(item); break;
972 		case 0xf9: // Half-Precision Float (two-byte IEEE 754)
973 			__HalfRep hr = {u : readInteger!ushort(input)};
974 			return CborValue(hr.h.get!double);
975 		case 0xfa: // Single-Precision Float (four-byte IEEE 754)
976 			__FloatRep fr = {u : readInteger!uint(input)};
977 			return CborValue(fr.f);
978 		case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
979 			__DoubleRep dr = {u : readInteger!ulong(input)};
980 			return CborValue(dr.d);
981 		case 0xff: // "break" stop code
982 			onUnsupportedTag(item); break;
983 		default:
984 			onUnsupportedTag(item);
985 	}
986 
987 	assert(false);
988 }
989 
990 /// Decodes single cbor value and tries to convert it to requested type.
991 /// If types doesn't match CborException is thrown.
992 /// Note, that ubyte[] and string types are slices of input range if ubyte[] was provided.
993 /// Will modify input range, popping all the elements of T.
994 T decodeCborSingle(T, R)(auto ref R input)
995 	if(isInputRange!R && is(ElementType!R == ubyte))
996 {
997 	CborValue value = decodeCbor(input);
998 	return value.as!T;
999 }
1000 
1001 /// Decodes single cbor value and tries to convert it to requested type.
1002 /// If types doesn't match CborException is thrown.
1003 /// Note, that this version will dup all arrays for you.
1004 /// Will modify input range, popping all the elements of T.
1005 T decodeCborSingleDup(T, R)(auto ref R input)
1006 	if(isInputRange!R && is(ElementType!R == ubyte))
1007 {
1008 	CborValue value = decodeCbor(input);
1009 
1010 	static if (is(T == E[], E))
1011 		return value.as!T.dup;
1012 	else
1013 		return value.as!T;
1014 }
1015 
1016 //------------------------------------------------------------------------------
1017 //		HH   HH EEEEEEE LL      PPPPPP  EEEEEEE RRRRRR   SSSSS  
1018 //		HH   HH EE      LL      PP   PP EE      RR   RR SS      
1019 //		HHHHHHH EEEEE   LL      PPPPPP  EEEEE   RRRRRR   SSSSS  
1020 //		HH   HH EE      LL      PP      EE      RR  RR       SS 
1021 //		HH   HH EEEEEEE LLLLLLL PP      EEEEEEE RR   RR  SSSSS  
1022 //------------------------------------------------------------------------------
1023 
1024 private void putChecked(R, E)(ref R sink, const auto ref E e)
1025 {
1026 	import std.range : put, hasLength;
1027 	version(Cbor_Debug)
1028 	static if (hasLength!R)
1029 	{
1030 		size_t elemSize;
1031 
1032 		static if (hasLength!E)
1033 			elemSize = e.length * ElementType!E.sizeof;
1034 		else
1035 			elemSize = E.sizeof;
1036 
1037 		assert(sink.length >= elemSize,
1038 			format("Provided sink length is to small. Sink.$ %s < Data.$ %s", sink.length, elemSize));
1039 	}
1040 	put(sink, e);
1041 }
1042 
1043 private T readInteger(T, R)(auto ref R input)
1044 {
1045 	return readN!(T.sizeof, T, R)(input);
1046 }
1047 
1048 private T readN(ubyte size, T, R)(auto ref R input)
1049 	if(isInputRange!R && is(ElementType!R == ubyte))
1050 {
1051 	import std.algorithm : copy, take;
1052 	import std.bitmanip : bigEndianToNative;
1053 	import std.range : dropExactly;
1054 	
1055 	static assert(T.sizeof == size);
1056 	static assert(size > 0);
1057 	if (input.length < size) onInsufficientInput();
1058 
1059 	ubyte[size] data;
1060 
1061 	copy(take(input, size), data[]);
1062 	input = input.dropExactly(size);
1063 	T result = bigEndianToNative!(T, size)(data);
1064 
1065 	return result;
1066 }
1067 
1068 // Drops exactly length bytes from input range.
1069 // If there is not sufficient bytes in input, CborException is thrown.
1070 private void dropBytes(R)(auto ref R input, ulong length)
1071 	if(isInputRange!R && is(ElementType!R == ubyte))
1072 {
1073 	import std.range : dropExactly;
1074 	if (input.length < length) onInsufficientInput();
1075 	input = input.dropExactly(cast(size_t)length);
1076 }
1077 
1078 // Reads byte array from input range. On 32-bit can read up to uint.max bytes.
1079 // If ubyte[] is passed as input, a slice will be returned.
1080 // Make sure to dup array when input buffer is reused.
1081 private ubyte[] readBytes(R)(auto ref R input, ulong length)
1082 	if(isInputRange!R && is(ElementType!R == ubyte))
1083 {
1084 	import std.algorithm : take;
1085 	import std.array;
1086 	if (input.length < length) onInsufficientInput();
1087 
1088 	static if (size_t.sizeof < ulong.sizeof)
1089 		if (length > size_t.max)
1090 			throw new CborException(format("Array size is too big %s", length));
1091 	
1092 	size_t dataLength = cast(size_t)length;
1093 	ubyte[] result;
1094 	static if (is(R == ubyte[]))
1095 	{
1096 		result = input[0..dataLength];
1097 		input = input[dataLength..$];
1098 	}
1099 	else
1100 	{
1101 		result = take(input, dataLength).array;
1102 	}
1103 
1104 	return result;
1105 }
1106 
1107 // Read array of 'length' items into CborValue[].
1108 private CborValue[] readArray(R)(auto ref R input, ulong length)
1109 	if(isInputRange!R && is(ElementType!R == ubyte))
1110 {
1111 	static if (size_t.sizeof < ulong.sizeof)
1112 		if (length > size_t.max)
1113 			throw new CborException(format("Array size is too big %s", length));
1114 
1115 	size_t arrayLength = cast(size_t)length;
1116 	CborValue[] result = new CborValue[arrayLength]; // can use uninitializedArray
1117 	foreach(ref elem; result)
1118 	{
1119 		elem = decodeCbor(input);
1120 	}
1121 
1122 	return result;
1123 }
1124 
1125 // length - num of pairs
1126 private CborValue[CborValue] readMap(R)(auto ref R input, ulong length)
1127 	if(isInputRange!R && is(ElementType!R == ubyte))
1128 {
1129 	static if (size_t.sizeof < ulong.sizeof)
1130 		if (length > size_t.max)
1131 			throw new CborException(format("Map size is too big: %s", length));
1132 
1133 	size_t mapLength = cast(size_t)length;
1134 	CborValue[CborValue] result; // can use uninitializedArray
1135 	foreach(i; 0..mapLength)
1136 	{
1137 		auto key = decodeCbor(input);
1138 		if (key in result) throw new CborException(format("duplicate key %s in map found", key));
1139 		result[key] = decodeCbor(input);
1140 	}
1141 
1142 	return result;
1143 }
1144 
1145 private import std.numeric : CustomFloat;
1146 private union __HalfRep { CustomFloat!16 h; ushort u; string toString(){return format("__HalfRep(%s, %x)", h, u);};}
1147 private union __FloatRep { float f; uint u; string toString(){return format("__FloatRep(%s, %x)", f, u);};}
1148 private union __DoubleRep { double d; ulong u; string toString(){return format("__DoubleRep(%s, %x)", d, u);};}
1149 
1150 private template isEncodedField(T)
1151 {
1152 	enum isEncodedField = __traits(compiles, { encodeCbor((ubyte[]).init, T.init); });
1153 }
1154 
1155 template numEncodableMembers(alias T)
1156 {
1157 	enum numEncodableMembers = numEncodableMembersImpl!(T.tupleof);
1158 }
1159 
1160 private template numEncodableMembersImpl(members ...)
1161 {
1162 	static if (members.length == 0)
1163 		enum numEncodableMembersImpl = 0;
1164 	else
1165 		enum numEncodableMembersImpl = 
1166 			cast(int)__traits(compiles, { encodeCbor(cast(ubyte[])null, members[0].init); }) +
1167 			numEncodableMembersImpl!(members[1..$]);
1168 }
1169 
1170 //------------------------------------------------------------------------------
1171 //		TTTTTTT EEEEEEE  SSSSS  TTTTTTT  SSSSS  
1172 //		  TTT   EE      SS        TTT   SS      
1173 //		  TTT   EEEEE    SSSSS    TTT    SSSSS  
1174 //		  TTT   EE           SS   TTT        SS 
1175 //		  TTT   EEEEEEE  SSSSS    TTT    SSSSS  
1176 //------------------------------------------------------------------------------
1177                                       
1178 
1179 unittest // positive integer
1180 {
1181 	CborValue val = CborValue(22);
1182 	assert(val == 22);
1183 	assert(val.as!ubyte == 22);
1184 	assert(val.as!ushort == 22);
1185 	assert(val.as!uint == 22);
1186 	assert(val.as!ulong == 22);
1187 	assert(val.as!byte == 22);
1188 	assert(val.as!short == 22);
1189 	assert(val.as!int == 22);
1190 	assert(val.as!long == 22);
1191 	assert(val.type == CborValue.Type.posinteger);
1192 
1193 	val = CborValue(ulong.max);
1194 	assert(val == ulong.max);
1195 	assert(val.type == CborValue.Type.posinteger);
1196 }
1197 
1198 unittest // negative integer
1199 {
1200 	CborValue val = CborValue(-22);
1201 	assert(val == -22);
1202 	assert(val !=  22);
1203 	assert(val.as!byte == -22);
1204 	assert(val.as!short == -22);
1205 	assert(val.as!int == -22);
1206 	assert(val.as!long == -22);
1207 	assert(val.as!ulong == cast(ulong)-22);
1208 	assert(val.type == CborValue.Type.neginteger);
1209 }
1210 
1211 unittest // floating point
1212 {
1213 	CborValue val = CborValue(-22.0f);
1214 	assert(val == -22f);
1215 	assert(val.as!real == -22f);
1216 	assert(val.as!double == -22f);
1217 	assert(val.as!float == -22f);
1218 	assert(val.type == CborValue.Type.floating);
1219 }
1220 
1221 unittest // boolean
1222 {
1223 	CborValue val = CborValue(true);
1224 	assert(val == true);
1225 	assert(val.as!bool == true);
1226 	assert(val.type == CborValue.Type.boolean);
1227 
1228 	val = CborValue(false);
1229 	assert(val == false);
1230 	assert(val.as!bool == false);
1231 	assert(val.type == CborValue.Type.boolean);
1232 }
1233 
1234 unittest // undefined
1235 {
1236 	CborValue val = CborValue(CborValue.Type.undefined);
1237 	assert(val == CborValue(CborValue.Type.undefined));
1238 	assert(val.type == CborValue.Type.undefined);
1239 }
1240 
1241 unittest // null value
1242 {
1243 	CborValue val = CborValue(null);
1244 	assert(val == CborValue(null)); // prefer
1245 	assert(val.as!(ubyte[]) == null);
1246 	assert(val.as!(ubyte[3]) == [0,0,0]);
1247 	assert(val == CborValue(CborValue.Type.nil));
1248 	assert(val.type == CborValue.Type.nil);
1249 }
1250 
1251 unittest // array
1252 {
1253 	CborValue val = CborValue([CborValue(1), CborValue("string"), CborValue(true), CborValue(null)]);
1254 	assert(val == [CborValue(1), CborValue("string"), CborValue(true), CborValue(null)]);
1255 	assert(val.type == CborValue.Type.array);
1256 }
1257 
1258 unittest // map
1259 {
1260 	CborValue val = CborValue([CborValue("a") : CborValue(42)]);
1261 	assert(val == [CborValue("a") : CborValue(42)]);
1262 	assert(val.type == CborValue.Type.map);
1263 }
1264 
1265 unittest // byte string
1266 {
1267 	CborValue val = CborValue(cast(ubyte[])[1, 2, 3, 4, 5]);
1268 	assert(val == cast(ubyte[])[1, 2, 3, 4, 5]);
1269 	assert(val.type == CborValue.Type.raw);
1270 }
1271 
1272 unittest // string
1273 {
1274 	CborValue val = CborValue("hello");
1275 	assert(val == "hello");
1276 	assert(val.type == CborValue.Type.text);
1277 }
1278 
1279 // Testing helpers
1280 version(unittest)
1281 {
1282 	private ubyte[1024] buf;
1283 
1284 	private ubyte[] getEncoded(T)(T value)
1285 	{
1286 		return buf[0..encodeCbor(buf[], value)];
1287 	}
1288 
1289 	private string toHexString(ubyte[] arr)
1290 	{
1291 		return format("0x%(%02x%)", arr);
1292 	}
1293 	private string encodedString(T)(T value)
1294 	{
1295 		return toHexString(getEncoded(value));
1296 	}
1297 	private void printEncoded(T)(T value)
1298 	{
1299 		import std.stdio : writeln;
1300 		encodedString(value).writeln;
1301 	}
1302 	private void cmpEncoded(T)(T value, string encodedStr)
1303 	{
1304 		assert(encodedString(value) == encodedStr);
1305 	}
1306 }
1307 
1308 unittest // encoding
1309 {
1310 	// Test vectors
1311 	cmpEncoded(0, "0x00");
1312 	cmpEncoded(1, "0x01");
1313 	cmpEncoded(10, "0x0a");
1314 	cmpEncoded(23, "0x17");
1315 	cmpEncoded(24, "0x1818");
1316 	cmpEncoded(25, "0x1819");
1317 	cmpEncoded(100, "0x1864");
1318 	cmpEncoded(1000, "0x1903e8");
1319 	cmpEncoded(1000000, "0x1a000f4240");
1320 	cmpEncoded(1000000000000, "0x1b000000e8d4a51000");
1321 
1322 	//bignums
1323 	//cmpEncoded(18446744073709551615, "0x1bffffffffffffffff");
1324 	//cmpEncoded(18446744073709551616, "0xc249010000000000000000");
1325 	//cmpEncoded(-18446744073709551616, "0x3bffffffffffffffff");
1326 	//cmpEncoded(-18446744073709551617, "0xc349010000000000000000");
1327 	cmpEncoded(-1, "0x20");
1328 	cmpEncoded(-10, "0x29");
1329 	cmpEncoded(-100, "0x3863");
1330 	cmpEncoded(-1000, "0x3903e7");
1331 	
1332 	//printEncoded(0.0f, "0xf90000"); // half-float
1333 	//printEncoded(-0.0f, "0xf98000"); // half-float
1334 	//printEncoded(1.0f, "0xf93c00"); // half-float
1335 	cmpEncoded(1.1, "0xfb3ff199999999999a");
1336 	//printEncoded(1.5f, "0xf93e00"); // half-float
1337 	//printEncoded(65504.0f, "0xf97bff"); // half-float
1338 	cmpEncoded(100000.0f, "0xfa47c35000");
1339 	cmpEncoded(3.4028234663852886e+38f, "0xfa7f7fffff");
1340 	cmpEncoded(1.0e+300, "0xfb7e37e43c8800759c");
1341 	//printEncoded(5.960464477539063e-8f, "0xf90001"); // half-float
1342 	//printEncoded(0.00006103515625f, "0xf90400"); // half-float
1343 	//printEncoded(-4.0f, "0xf9c400"); // half-float
1344 	cmpEncoded(-4.1, "0xfbc010666666666666");
1345 	cmpEncoded(1.0f/0, "0xfa7f800000"); // Infinity
1346 	//cmpEncoded(NaN, "0xfa7fc00000"); // produces 0xfa7fe00000
1347 	cmpEncoded(-1.0f/0, "0xfaff800000"); // -Infinity
1348 	cmpEncoded(1.0/0, "0xfb7ff0000000000000"); // Infinity
1349 	//cmpEncoded(NaN, "0xfb7ff8000000000000"); // produces 0xfb7ffc000000000000
1350 	cmpEncoded(-1.0/0, "0xfbfff0000000000000");// -Infinity
1351 
1352 	cmpEncoded(false, "0xf4");
1353 	cmpEncoded(true, "0xf5");
1354 	cmpEncoded(null, "0xf6");
1355 	
1356 	// raw arrays, ubyte[]
1357 	cmpEncoded(cast(ubyte[])[], "0x40");
1358 	cmpEncoded(cast(ubyte[])[1, 2, 3, 4], "0x4401020304");
1359 	
1360 	// strings
1361 	cmpEncoded("", "0x60");
1362 	cmpEncoded("a", "0x6161");
1363 	cmpEncoded("IETF", "0x6449455446");
1364 	cmpEncoded("\"\\", "0x62225c");
1365 	cmpEncoded("\u00fc", "0x62c3bc");
1366 	cmpEncoded("\u6c34", "0x63e6b0b4");
1367 	//cmpEncoded("\ud800\udd51", "0x64f0908591"); // invalid character
1368 
1369 	import std.typecons : tuple;
1370 	// arrays
1371 	cmpEncoded([], "0x80");
1372 	cmpEncoded([1, 2, 3], "0x83010203");
1373 	cmpEncoded(tuple(1, [2, 3], [4, 5]), "0x8301820203820405");
1374 	enum arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1375 				15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25];
1376 	cmpEncoded(arr, "0x98190102030405060708090a0b0c0d0e0f101112131415161718181819");
1377 
1378 	// AA
1379 	uint[uint] emptyAA;
1380 	cmpEncoded(emptyAA, "0xa0");
1381 	cmpEncoded([1:2, 3:4], "0xa201020304");
1382 	
1383 	//cmpEncoded({"a": 1, "b": [2, 3]}, "0xa26161016162820203");
1384 	//cmpEncoded(["a", {"b": "c"}], "0x826161a161626163");
1385 	cmpEncoded(["a": "A", "b": "B", "c":"C", "d": "D", "e": "E"],
1386 		"0xa56161614161626142616361436164614461656145");
1387 	//cmpEncoded((_ h'0102', h'030405'), "0x5f42010243030405ff");
1388 	//cmpEncoded((_ "strea", "ming"), "0x7f657374726561646d696e67ff");
1389 	//cmpEncoded([_ ], "0x9fff");
1390 	//cmpEncoded([_ 1, [2, 3], [_ 4, 5]], "0x9f018202039f0405ffff");
1391 	//cmpEncoded([_ 1, [2, 3], [4, 5]], "0x9f01820203820405ff");
1392 	//cmpEncoded([1, [2, 3], [_ 4, 5]], "0x83018202039f0405ff");
1393 	//cmpEncoded([1, [_ 2, 3], [4, 5]], "0x83019f0203ff820405");
1394 	//cmpEncoded([_ 1, 2, 3, 4, 5, 6, 7, 8,	9, 10, 11, 12, 13, 14, 15,
1395 	//	16, 17, 18, 19, 20, 21, 22, 23, 24, 25],
1396 	//	"0x9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff");
1397 	//cmpEncoded({_ "a": 1, "b": [_ 2, 3]}, "0xbf61610161629f0203ffff");
1398 	//cmpEncoded(["a", {_ "b": "c"}], "0x826161bf61626163ff");
1399 	//cmpEncoded({_ "Fun": true, "Amt": -2}, "0xbf6346756ef563416d7421ff");
1400 
1401 	cmpEncoded(cast(ubyte)42, "0x182a");
1402 	cmpEncoded(cast(ushort)42, "0x182a");
1403 	cmpEncoded(cast(uint)42, "0x182a");
1404 	cmpEncoded(cast(ulong)42, "0x182a");
1405 	cmpEncoded(cast(byte)42, "0x182a");
1406 	cmpEncoded(cast(short)42, "0x182a");
1407 	cmpEncoded(cast(int)42, "0x182a");
1408 	cmpEncoded(cast(long)42, "0x182a");
1409 }
1410 
1411 unittest // decoding decodeCbor
1412 {
1413 	import std.range : only, chain, iota;
1414 	import std.exception;
1415 	import std.bitmanip;
1416 	import std.array;
1417 	import std.algorithm : equal;
1418 
1419 	alias ntob = nativeToBigEndian;
1420 	alias bton = bigEndianToNative;
1421 
1422 	// Integer 0x00..0x17 (0..23)
1423 	foreach(ubyte item; 0x00..0x18)
1424 	{
1425 		assert(decodeCbor(only(item))==item);
1426 	}
1427 
1428 	// Unsigned integer (one-byte uint8_t follows)
1429 	assert(decodeCbor(cast(ubyte[])[0x18, ubyte.max]) == ubyte.max);
1430 	assertThrown!CborException(decodeCbor(cast(ubyte[])[0x18]));
1431 
1432 	// Unsigned integer (two-byte uint16_t follows)
1433 	assert(decodeCbor(chain(cast(ubyte[])[0x19], ntob!ushort(1234)[])) == 1234);
1434 	assertThrown!CborException(decodeCbor(cast(ubyte[])[0x19]));
1435 
1436 	// Unsigned integer (four-byte uint_t follows)
1437 	assert(decodeCbor(chain(cast(ubyte[])[0x1a], ntob!uint(1234)[])) == 1234);
1438 	assertThrown!CborException(decodeCbor(cast(ubyte[])[0x1a]));
1439 
1440 	// Unsigned integer (eight-byte uint64_t follows)
1441 	assert(decodeCbor(chain(cast(ubyte[])[0x1b], ntob!ulong(1234)[])) == 1234);
1442 	assertThrown!CborException(decodeCbor(cast(ubyte[])[0x1b]));
1443 
1444 	// Negative integer -1-0x00..-1-0x17 (-1..-24)
1445 	foreach(ubyte item; 0x20..0x38) // [-1..-24]
1446 	{
1447 		assert(decodeCbor(only(item)) == -cast(long)item+0x1f);
1448 	}
1449 
1450 	// Negative integer -1-n (one-byte uint8_t for n follows)
1451 	assert(decodeCbor(cast(ubyte[])[0x38, byte.max-1]) == -byte.max);
1452 	assertThrown!CborException(decodeCbor(cast(ubyte[])[0x38]));
1453 
1454 	// Negative integer -1-n (two-byte uint16_t for n follows)
1455 	assert(decodeCbor(chain(cast(ubyte[])[0x39], ntob!short(1234-1)[])) == -1234);
1456 	assertThrown!CborException(decodeCbor(cast(ubyte[])[0x39]));
1457 
1458 	// Negative integer -1-n (four-byte uint_t for n follows)
1459 	assert(decodeCbor(chain(cast(ubyte[])[0x3a], ntob!int(1234-1)[])) == -1234);
1460 	assertThrown!CborException(decodeCbor(cast(ubyte[])[0x3a]));
1461 
1462 	// Negative integer -1-n (eight-byte uint64_t for n follows)
1463 	assert(decodeCbor(chain(cast(ubyte[])[0x3b], ntob!long(1234-1)[])) == -1234);
1464 	assertThrown!CborException(decodeCbor(cast(ubyte[])[0x3b]));
1465 
1466 	// byte string (0x00..0x17 bytes follow)
1467 	foreach(ubyte item; 0x40..0x58)
1468 	{
1469 		assert(equal(
1470 			decodeCbor(chain(
1471 				cast(ubyte[])[item],
1472 				iota(cast(ubyte)(item - 0x40)))
1473 			).via.raw,
1474 			iota(0, item - 0x40)
1475 			));
1476 	}
1477 
1478 	// byte string (one-byte uint8_t for n, and then n bytes follow)
1479 	assert(decodeCbor(cast(ubyte[])[0x58, 1, 42]) == cast(ubyte[])[42]);
1480 	// byte string (two-byte uint16_t for n, and then n bytes follow)
1481 	assert(decodeCbor(cast(ubyte[])[0x59, 0, 1, 42]) == cast(ubyte[])[42]);
1482 	// byte string (four-byte uint_t for n, and then n bytes follow)
1483 	assert(decodeCbor(cast(ubyte[])[0x5a, 0, 0, 0, 1, 42]) == cast(ubyte[])[42]);
1484 	// byte string (eight-byte uint64_t for n, and then n bytes follow)
1485 	assert(decodeCbor(cast(ubyte[])[0x5b, 0, 0, 0, 0, 0, 0, 0, 1, 42]) == cast(ubyte[])[42]);
1486 
1487 	// UTF-8 string (0x00..0x17 bytes follow)
1488 	assert(decodeCbor(cast(ubyte[])[0x64] ~ cast(ubyte[])"abcd") == "abcd");
1489 	// UTF-8 string (one-byte uint8_t for n, and then n bytes follow)
1490 	assert(decodeCbor(cast(ubyte[])[0x78, 4] ~ cast(ubyte[])"abcd") == "abcd");
1491 	// UTF-8 string (two-byte uint16_t for n, and then n bytes follow)
1492 	assert(decodeCbor(cast(ubyte[])[0x79, 0, 4] ~ cast(ubyte[])"abcd") == "abcd");
1493 	// UTF-8 string (four-byte uint_t for n, and then n bytes follow)
1494 	assert(decodeCbor(cast(ubyte[])[0x7a, 0, 0, 0, 4] ~ cast(ubyte[])"abcd") == "abcd");
1495 	// UTF-8 string (eight-byte uint64_t for n, and then n bytes follow)
1496 	assert(decodeCbor(cast(ubyte[])[0x7b, 0, 0, 0, 0, 0, 0, 0, 4] ~ cast(ubyte[])"abcd") == "abcd");
1497 	// UTF-8 string, UTF-8 strings follow, terminated by "break"
1498 
1499 	// array (0x00..0x17 data items follow)
1500 	assert(decodeCbor(cast(ubyte[])[0x84, 1, 2, 3, 4]) == [1, 2, 3, 4]);
1501 	// array (one-byte uint8_t for n, and then n data items follow)
1502 	assert(decodeCbor(cast(ubyte[])[0x98, 4, 1, 2, 3, 4]) == [1, 2, 3, 4]);
1503 	// array (two-byte uint16_t for n, and then n data items follow)
1504 	assert(decodeCbor(cast(ubyte[])[0x99, 0, 4, 1, 2, 3, 4]) == [1, 2, 3, 4]);
1505 	// array (four-byte uint_t for n, and then n data items follow)
1506 	assert(decodeCbor(cast(ubyte[])[0x9a, 0, 0, 0, 4, 1, 2, 3, 4]) == [1, 2, 3, 4]);
1507 	// array (eight-byte uint64_t for n, and then n data items follow)
1508 	assert(decodeCbor(cast(ubyte[])[0x9b, 0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 3, 4]) == [1, 2, 3, 4]);
1509 	// array, data items follow, terminated by "break"
1510 	
1511 	// map (0x00..0x17 pairs of data items follow)
1512 	assert(decodeCbor(getEncoded([1:2, 3:4])) == [1:2, 3:4]);
1513 	assert(decodeCbor(cast(ubyte[])[0xa2, 1, 2, 3, 4]) == [1:2, 3:4]);
1514 	// map (one-byte uint8_t for n, and then n pairs of data items follow)   
1515 	assert(decodeCbor(cast(ubyte[])[0xb8, 2, 1, 2, 3, 4]) == [1:2, 3:4]);
1516 	// map (two-byte uint16_t for n, and then n pairs of data items follow)
1517 	assert(decodeCbor(cast(ubyte[])[0xb9, 0, 2, 1, 2, 3, 4]) == [1:2, 3:4]);
1518 	// map (four-byte uint_t for n, and then n pairs of data items follow)
1519 	assert(decodeCbor(cast(ubyte[])[0xba, 0, 0, 0, 2, 1, 2, 3, 4]) == [1:2, 3:4]);
1520 	// map (eight-byte uint64_t for n, and then n pairs of data items follow)
1521 	assert(decodeCbor(cast(ubyte[])[0xbb, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 3, 4]) == [1:2, 3:4]);
1522 
1523 	// False
1524 	assert(decodeCbor(cast(ubyte[])[0xf4]) == false);
1525 	// True
1526 	assert(decodeCbor(cast(ubyte[])[0xf5]) == true);
1527 	// Null
1528 	assert(decodeCbor(cast(ubyte[])[0xf6]) == CborValue(null));
1529 	// Undefined
1530 	assert(decodeCbor(cast(ubyte[])[0xf7]) == CborValue(CborValue.Type.undefined));
1531 	
1532 	// (simple value, one byte follows) 0xf8
1533 
1534 	// Half-Precision Float (two-byte IEEE 754)
1535 	__HalfRep hr = {h : CustomFloat!16(1.234f)};
1536 	assert(decodeCbor(cast(ubyte[])[0xf9] ~
1537 		ntob!ushort((hr.u))[]) == CborValue(CustomFloat!16(1.234f).get!float));
1538 
1539 	// Single-Precision Float (four-byte IEEE 754)
1540 	assert(decodeCbor(cast(ubyte[])[0xfa] ~
1541 		ntob!uint((cast(__FloatRep)1.234f).u)[]) == CborValue(1.234f));
1542 	
1543 	// Double-Precision Float (eight-byte IEEE 754)
1544 	assert(decodeCbor(cast(ubyte[])[0xfb] ~
1545 		ntob!ulong((cast(__DoubleRep)1.234).u)[]) == CborValue(1.234));	
1546 }
1547 
1548 unittest // test tag ignoring
1549 {
1550 	assert(decodeCbor(cast(ubyte[])[0xc0, 0x18, ubyte.max]) == ubyte.max);
1551 
1552 	assert(decodeCbor(cast(ubyte[])[0xd8, 0, 0x18, ubyte.max]) == ubyte.max);
1553 	assert(decodeCbor(cast(ubyte[])[0xd9, 0, 0, 0x18, ubyte.max]) == ubyte.max);
1554 	assert(decodeCbor(cast(ubyte[])[0xda, 0, 0, 0, 0, 0x18, ubyte.max]) == ubyte.max);
1555 	assert(decodeCbor(cast(ubyte[])[0xdb, 0, 0, 0, 0, 0, 0, 0, 0, 0x18, ubyte.max]) == ubyte.max);
1556 }
1557 
1558 ///
1559 unittest // decoding exact
1560 {
1561 	static struct Inner
1562 	{
1563 		int[] array;
1564 		string someText;
1565 	}
1566 
1567 	static struct Test1
1568 	{
1569 		ubyte b;
1570 		short s;
1571 		uint i;
1572 		long l;
1573 		float f;
1574 		double d;
1575 		ubyte[] arr;
1576 		string str;
1577 		Inner inner;
1578 
1579 		void fun(){} // not encoded
1580 		void* pointer; // not encoded
1581 	}
1582 
1583 	ubyte[1024] buf1;
1584 	size_t size;
1585 
1586 	Test1 test = Test1(42, -120, 111111, -123456789, 0.1234, -0.987654,
1587 		cast(ubyte[])[1,2,3,4,5,6,7,8], "It is a test string",
1588 		Inner([1,2,3,4,5], "Test of inner struct"));
1589 
1590 	size = encodeCborArray(buf1[], test);
1591 	Test1 result = decodeCborSingle!Test1(buf1[0..size]);
1592 	assert(test == result);
1593 
1594 	import std.typecons : Tuple;
1595 
1596 	alias TupleVal = Tuple!(int, string, byte, string);
1597 	auto testTuple = TupleVal(1, "hello", 56, "there");
1598 
1599 	size = encodeCborArray(buf1[], testTuple);
1600 	TupleVal resultTuple = decodeCborSingle!TupleVal(buf1[0..size]);
1601 	assert(testTuple == resultTuple);
1602 
1603 	static class Inner2
1604 	{
1605 		int val;
1606 		ulong u;
1607 	}
1608 
1609 	static class Test2
1610 	{
1611 		ubyte b;
1612 		short s;
1613 		uint i;
1614 		long l;
1615 		float f;
1616 		double d;
1617 		ubyte[] arr;
1618 		string str;
1619 		Inner2 inner;
1620 	}
1621 
1622 	Test2 testClass = new Test2();
1623 	testClass.b = 42;
1624 	testClass.s = -120;
1625 	testClass.i = 111111;
1626 	testClass.l = -123456789;
1627 	testClass.f = 0.1234;
1628 	testClass.d = -0.987654;
1629 	testClass.arr = cast(ubyte[])[1,2,3,4,5,6,7,8];
1630 	testClass.str = "It is a test string";
1631 	testClass.inner = null;
1632 	
1633 	size = encodeCborArray(buf1[], testClass);
1634 	ubyte[] encodedBuf = buf1[0..size];
1635 	Test2 resultClass = decodeCborSingle!Test2(encodedBuf);
1636 	assert(encodedBuf.length == 0);
1637 
1638 	foreach(i, m; resultClass.tupleof)
1639 		assert(testClass.tupleof[i] == m);
1640 
1641 	testClass.inner = new Inner2;
1642 	testClass.inner.val = -555;
1643 	testClass.inner.u = 123456789;
1644 
1645 	size = encodeCborArray(buf1[], testClass);
1646 	resultClass = decodeCborSingle!Test2(buf1[0..size]);
1647 
1648 	foreach(i, m; resultClass.inner.tupleof)
1649 		assert(testClass.inner.tupleof[i] == m);
1650 }
1651 
1652 unittest // decoding with dup
1653 {
1654 	ubyte[128] buf1;
1655 	size_t size;
1656 
1657 	// with dup
1658 	size = encodeCbor(buf1[], cast(ubyte[])[0, 1, 2, 3, 4, 5]);
1659 	ubyte[] data = decodeCborSingleDup!(ubyte[])(buf1[0..size]);
1660 	buf1[] = 0;
1661 
1662 	assert(data == [0, 1, 2, 3, 4, 5]);
1663 
1664 	// without dup
1665 	size = encodeCbor(buf1[], cast(ubyte[])[0, 1, 2, 3, 4, 5]);
1666 	data = decodeCborSingle!(ubyte[])(buf1[0..size]);
1667 	buf1[] = 0;
1668 
1669 	assert(data == [0, 0, 0, 0, 0, 0]);
1670 
1671 	// dup is only needed for ubyte[] and string types,
1672 	// because they can be sliced from ubyte[] input range
1673 	size = encodeCbor(buf1[], [0, 1, 2, 3, 4, 5]); // int array
1674 	int[] intData = decodeCborSingle!(int[])(buf1[0..size]); // no dup
1675 	buf1[] = 0;
1676 
1677 	assert(intData == [0, 1, 2, 3, 4, 5]);
1678 
1679 	// also no slicing will occur if data was encoded as regular array and than
1680 	// ubyte[] retreived. integer[] -> ubyte[] cast would occur causing possible data loss.
1681 	// size = encodeCbor(buf1[], [0, 1, 2, 3, 4, 5]); // int array
1682 	// integer array cannot be decoded as ubyte[], only raw arrays can
1683 	// data = decodeCborSingle!(ubyte[])(buf1[0..size]); // CborException: Attempt to cast array to ubyte[]
1684 }
1685 
1686 private:
1687 
1688 @safe pure
1689 void onCastErrorToFrom(To)(CborValue.Type from, string file = __FILE__, size_t line = __LINE__)
1690 {
1691 	throw new CborException(format("Attempt to cast %s to %s", from, typeid(To)), file, line);
1692 }
1693 
1694 @safe pure
1695 void onInsufficientInput(string file = __FILE__, size_t line = __LINE__)
1696 {
1697 	throw new CborException("Input range is too short", file, line);
1698 }
1699 
1700 @safe pure
1701 void onUnsupportedTag(ubyte tag, string file = __FILE__, size_t line = __LINE__)
1702 {
1703 	throw new CborException(format("Unsupported tag found: %02x", tag), file, line);
1704 }