1 /**
2 	BSON serialization and value handling.
3 
4 	Copyright: © 2012-2015 Sönke Ludwig
5 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	Authors: Sönke Ludwig
7 */
8 module vibe.data.bson;
9 
10 ///
11 unittest {
12 	void manipulateBson(Bson b)
13 	{
14 		import std.stdio;
15 
16 		// retrieving the values is done using get()
17 		assert(b["name"].get!string == "Example");
18 		assert(b["id"].get!int == 1);
19 
20 		// semantic conversions can be done using to()
21 		assert(b["id"].to!string == "1");
22 
23 		// prints:
24 		// name: "Example"
25 		// id: 1
26 		foreach (string key, value; b)
27 			writefln("%s: %s", key, value);
28 
29 		// print out with JSON syntax: {"name": "Example", "id": 1}
30 		writefln("BSON: %s", b.toString());
31 
32 		// DEPRECATED: object members can be accessed using member syntax, just like in JavaScript
33 		//j = Bson.emptyObject;
34 		//j.name = "Example";
35 		//j.id = 1;
36 	}
37 }
38 
39 /// Constructing `Bson` objects
40 unittest {
41 	// construct a BSON object {"field1": "foo", "field2": 42, "field3": true}
42 
43 	// using the constructor
44 	Bson b1 = Bson(["field1": Bson("foo"), "field2": Bson(42), "field3": Bson(true)]);
45 
46 	// using piecewise construction
47 	Bson b2 = Bson.emptyObject;
48 	b2["field1"] = "foo";
49 	b2["field2"] = 42;
50 	b2["field3"] = true;
51 
52 	// using serialization
53 	struct S {
54 		string field1;
55 		int field2;
56 		bool field3;
57 	}
58 	Bson b3 = S("foo", 42, true).serializeToBson();
59 }
60 
61 
62 public import vibe.data.json;
63 
64 import vibe.internal.conv : enumToString;
65 
66 import std.algorithm;
67 import std.array;
68 import std.base64;
69 import std.bitmanip;
70 import std.conv;
71 import std.datetime;
72 import std.uuid: UUID;
73 import std.exception;
74 import std.range;
75 import std.traits;
76 import std.typecons : Tuple, tuple;
77 
78 
79 alias bdata_t = immutable(ubyte)[];
80 
81 /**
82 	Represents a BSON value.
83 
84 
85 */
86 struct Bson {
87 @safe:
88 
89 	/// Represents the type of a BSON value
90 	enum Type : ubyte {
91 		end        = 0x00,  /// End marker - should never occur explicitly
92 		double_    = 0x01,  /// A 64-bit floating point value
93 		string     = 0x02,  /// A UTF-8 string
94 		object     = 0x03,  /// An object aka. dictionary of string to Bson
95 		array      = 0x04,  /// An array of BSON values
96 		binData    = 0x05,  /// Raw binary data (ubyte[])
97 		undefined  = 0x06,  /// Deprecated
98 		objectID   = 0x07,  /// BSON Object ID (96-bit)
99 		bool_      = 0x08,  /// Boolean value
100 		date       = 0x09,  /// Date value (UTC)
101 		null_      = 0x0A,  /// Null value
102 		regex      = 0x0B,  /// Regular expression
103 		dbRef      = 0x0C,  /// Deprecated
104 		code       = 0x0D,  /// JaveScript code
105 		symbol     = 0x0E,  /// Symbol/variable name
106 		codeWScope = 0x0F,  /// JavaScript code with scope
107 		int_       = 0x10,  /// 32-bit integer
108 		timestamp  = 0x11,  /// Timestamp value
109 		long_      = 0x12,  /// 64-bit integer
110 		minKey     = 0xff,  /// Internal value
111 		maxKey     = 0x7f,  /// Internal value
112 
113 		deprecated("Use `end` instead.") End = end,                /// Compatibility alias
114 		deprecated("Use `double_` instead.") Double = double_,         /// Compatibility alias
115 		deprecated("Use `string` instead.") String = string,          /// Compatibility alias
116 		deprecated("Use `object` instead.") Object = object,          /// Compatibility alias
117 		deprecated("Use `array` instead.") Array = array,            /// Compatibility alias
118 		deprecated("Use `binData` instead.") BinData = binData,        /// Compatibility alias
119 		deprecated("Use `undefined` instead.") Undefined = undefined,    /// Compatibility alias
120 		deprecated("Use `objectID` instead.") ObjectID = objectID,      /// Compatibility alias
121 		deprecated("Use `bool_` instead.") Bool = bool_,             /// Compatibility alias
122 		deprecated("Use `date` instead.") Date = date,              /// Compatibility alias
123 		deprecated("Use `null_` instead.") Null = null_,             /// Compatibility alias
124 		deprecated("Use `regex` instead.") Regex = regex,            /// Compatibility alias
125 		deprecated("Use `dBRef` instead.") DBRef = dbRef,            /// Compatibility alias
126 		deprecated("Use `code` instead.") Code = code,              /// Compatibility alias
127 		deprecated("Use `symbol` instead.") Symbol = symbol,          /// Compatibility alias
128 		deprecated("Use `codeWScope` instead.") CodeWScope = codeWScope,  /// Compatibility alias
129 		deprecated("Use `int_` instead.") Int = int_,               /// Compatibility alias
130 		deprecated("Use `timestamp` instead.") Timestamp = timestamp,    /// Compatibility alias
131 		deprecated("Use `long_` instead.") Long = long_,             /// Compatibility alias
132 		deprecated("Use `minKey` instead.") MinKey = minKey,          /// Compatibility alias
133 		deprecated("Use `maxKey` instead.") MaxKey = maxKey           /// Compatibility alias
134 	}
135 
136 	// length + 0 byte end for empty lists (map, array)
137 	private static immutable ubyte[] emptyListBytes = [5, 0, 0, 0, 0];
138 
139 	/// Returns a new, empty Bson value of type Object.
140 	static @property Bson emptyObject()
141 	{
142 		Bson ret;
143 		ret.m_type = Type.object;
144 		ret.m_data = emptyListBytes;
145 		return ret;
146 	}
147 
148 	/// Returns a new, empty Bson value of type Array.
149 	static @property Bson emptyArray()
150 	{
151 		Bson ret;
152 		ret.m_type = Type.array;
153 		ret.m_data = emptyListBytes;
154 		return ret;
155 	}
156 
157 	private {
158 		Type m_type = Type.undefined;
159 		bdata_t m_data;
160 	}
161 
162 	/**
163 		Creates a new BSON value using raw data.
164 
165 		A slice of the first bytes of `data` is stored, containg the data related to the value. An
166 		exception is thrown if `data` is too short.
167 	*/
168 	this(Type type, bdata_t data)
169 	{
170 		m_type = type;
171 		m_data = data;
172 		final switch(type){
173 			case Type.end: m_data = null; break;
174 			case Type.double_: m_data = m_data[0 .. 8]; break;
175 			case Type..string: m_data = m_data[0 .. 4 + fromBsonData!int(m_data)]; break;
176 			case Type.object: m_data = m_data[0 .. fromBsonData!int(m_data)]; break;
177 			case Type.array: m_data = m_data[0 .. fromBsonData!int(m_data)]; break;
178 			case Type.binData: m_data = m_data[0 .. 5 + fromBsonData!int(m_data)]; break;
179 			case Type.undefined: m_data = null; break;
180 			case Type.objectID: m_data = m_data[0 .. 12]; break;
181 			case Type.bool_: m_data = m_data[0 .. 1]; break;
182 			case Type.date: m_data = m_data[0 .. 8]; break;
183 			case Type.null_: m_data = null; break;
184 			case Type.regex:
185 				auto tmp = m_data;
186 				tmp.skipCString();
187 				tmp.skipCString();
188 				m_data = m_data[0 .. $ - tmp.length];
189 				break;
190 			case Type.dbRef: m_data = m_data[0 .. 0]; assert(false, "Not implemented.");
191 			case Type.code: m_data = m_data[0 .. 4 + fromBsonData!int(m_data)]; break;
192 			case Type.symbol: m_data = m_data[0 .. 4 + fromBsonData!int(m_data)]; break;
193 			case Type.codeWScope: m_data = m_data[0 .. 0]; assert(false, "Not implemented.");
194 			case Type.int_: m_data = m_data[0 .. 4]; break;
195 			case Type.timestamp: m_data = m_data[0 .. 8]; break;
196 			case Type.long_: m_data = m_data[0 .. 8]; break;
197 			case Type.minKey: m_data = null; break;
198 			case Type.maxKey: m_data = null; break;
199 		}
200 	}
201 
202 	/**
203 		Initializes a new BSON value from the given D type.
204 	*/
205 	this(double value) { opAssign(value); }
206 	/// ditto
207 	this(string value, Type type = Type..string)
208 	{
209 		assert(type == Type..string || type == Type.code || type == Type.symbol);
210 		opAssign(value);
211 		m_type = type;
212 	}
213 	/// ditto
214 	this(in Bson[string] value) { opAssign(value); }
215 	/// ditto
216 	this(in Bson[] value) { opAssign(value); }
217 	/// ditto
218 	this(in BsonBinData value) { opAssign(value); }
219 	/// ditto
220 	this(in BsonObjectID value) { opAssign(value); }
221 	/// ditto
222 	this(bool value) { opAssign(value); }
223 	/// ditto
224 	this(in BsonDate value) { opAssign(value); }
225 	/// ditto
226 	this(typeof(null)) { opAssign(null); }
227 	/// ditto
228 	this(in BsonRegex value) { opAssign(value); }
229 	/// ditto
230 	this(int value) { opAssign(value); }
231 	/// ditto
232 	this(in BsonTimestamp value) { opAssign(value); }
233 	/// ditto
234 	this(long value) { opAssign(value); }
235 	/// ditto
236 	this(in Json value) { opAssign(value); }
237 	/// ditto
238 	this(in UUID value) { opAssign(value); }
239 
240 	/**
241 		Assigns a D type to a BSON value.
242 	*/
243 	void opAssign(const Bson other)
244 	{
245 		m_data = other.m_data;
246 		m_type = other.m_type;
247 	}
248 	/// ditto
249 	void opAssign(double value)
250 	{
251 		m_data = toBsonData(value).idup;
252 		m_type = Type.double_;
253 	}
254 	/// ditto
255 	void opAssign(string value)
256 	{
257 		import std.utf;
258 		debug std.utf.validate(value);
259 		auto app = appender!bdata_t();
260 		app.put(toBsonData(cast(int)value.length+1));
261 		app.put(cast(bdata_t)value);
262 		app.put(cast(ubyte)0);
263 		m_data = app.data;
264 		m_type = Type..string;
265 	}
266 	/// ditto
267 	void opAssign(in Bson[string] value)
268 	{
269 		auto app = appender!bdata_t();
270 		foreach( k, ref v; value ){
271 			app.put(cast(ubyte)v.type);
272 			putCString(app, k);
273 			app.put(v.data);
274 		}
275 
276 		auto dapp = appender!bdata_t();
277 		dapp.put(toBsonData(cast(int)app.data.length+5));
278 		dapp.put(app.data);
279 		dapp.put(cast(ubyte)0);
280 		m_data = dapp.data;
281 		m_type = Type.object;
282 	}
283 	/// ditto
284 	void opAssign(in Bson[] value)
285 	{
286 		auto app = appender!bdata_t();
287 		foreach( i, ref v; value ){
288 			app.put(v.type);
289 			putCString(app, .to!string(i));
290 			app.put(v.data);
291 		}
292 
293 		auto dapp = appender!bdata_t();
294 		dapp.put(toBsonData(cast(int)app.data.length+5));
295 		dapp.put(app.data);
296 		dapp.put(cast(ubyte)0);
297 		m_data = dapp.data;
298 		m_type = Type.array;
299 	}
300 	/// ditto
301 	void opAssign(in BsonBinData value)
302 	{
303 		auto app = appender!bdata_t();
304 		app.put(toBsonData(cast(int)value.rawData.length));
305 		app.put(value.type);
306 		app.put(value.rawData);
307 
308 		m_data = app.data;
309 		m_type = Type.binData;
310 	}
311 	/// ditto
312 	void opAssign(in BsonObjectID value)
313 	{
314 		m_data = value.m_bytes.idup;
315 		m_type = Type.objectID;
316 	}
317 	/// ditto
318 	void opAssign(bool value)
319 	{
320 		m_data = [value ? 0x01 : 0x00];
321 		m_type = Type.bool_;
322 	}
323 	/// ditto
324 	void opAssign(in BsonDate value)
325 	{
326 		m_data = toBsonData(value.m_time).idup;
327 		m_type = Type.date;
328 	}
329 	/// ditto
330 	void opAssign(typeof(null))
331 	{
332 		m_data = null;
333 		m_type = Type.null_;
334 	}
335 	/// ditto
336 	void opAssign(in BsonRegex value)
337 	{
338 		auto app = appender!bdata_t();
339 		putCString(app, value.expression);
340 		putCString(app, value.options);
341 		m_data = app.data;
342 		m_type = type.regex;
343 	}
344 	/// ditto
345 	void opAssign(int value)
346 	{
347 		m_data = toBsonData(value).idup;
348 		m_type = Type.int_;
349 	}
350 	/// ditto
351 	void opAssign(in BsonTimestamp value)
352 	{
353 		m_data = toBsonData(value.m_time).idup;
354 		m_type = Type.timestamp;
355 	}
356 	/// ditto
357 	void opAssign(long value)
358 	{
359 		m_data = toBsonData(value).idup;
360 		m_type = Type.long_;
361 	}
362 	/// ditto
363 	void opAssign(in Json value)
364 	@trusted {
365 		auto app = appender!bdata_t();
366 		m_type = writeBson(app, value);
367 		m_data = app.data;
368 	}
369 	/// ditto
370 	void opAssign(in UUID value)
371 	{
372 		opAssign(BsonBinData(BsonBinData.Type.uuid, value.data.idup));
373 	}
374 
375 	/**
376 		Returns the BSON type of this value.
377 	*/
378 	@property Type type() const { return m_type; }
379 
380 	bool isNull() const { return m_type == Type.null_; }
381 
382 	/**
383 		Returns the raw data representing this BSON value (not including the field name and type).
384 	*/
385 	@property bdata_t data() const { return m_data; }
386 
387 	/**
388 		Converts the BSON value to a D value.
389 
390 		If the BSON type of the value does not match the D type, an exception is thrown.
391 
392 		See_Also: `deserializeBson`, `opt`, `to`
393 	*/
394 	T opCast(T)() const { return get!T(); }
395 	/// ditto
396 	@property T get(T)()
397 	const {
398 		static if( is(T == double) ){ checkType(Type.double_); return fromBsonData!double(m_data); }
399 		else static if( is(T == string) ){
400 			checkType(Type..string, Type.code, Type.symbol);
401 			return cast(string)m_data[4 .. 4+fromBsonData!int(m_data)-1];
402 		}
403 		else static if( is(Unqual!T == Bson[string]) || is(Unqual!T == const(Bson)[string]) ){
404 			checkType(Type.object);
405 			Bson[string] ret;
406 			auto d = m_data[4 .. $];
407 			while( d.length > 0 ){
408 				auto tp = cast(Type)d[0];
409 				if( tp == Type.end ) break;
410 				d = d[1 .. $];
411 				auto key = skipCString(d);
412 				auto value = Bson(tp, d);
413 				d = d[value.data.length .. $];
414 
415 				ret[key] = value;
416 			}
417 			return cast(T)ret;
418 		}
419 		else static if( is(Unqual!T == Bson[]) || is(Unqual!T == const(Bson)[]) ){
420 			checkType(Type.array);
421 			Bson[] ret;
422 			auto d = m_data[4 .. $];
423 			while( d.length > 0 ){
424 				auto tp = cast(Type)d[0];
425 				if( tp == Type.end ) break;
426 				/*auto key = */skipCString(d); // should be '0', '1', ...
427 				auto value = Bson(tp, d);
428 				d = d[value.data.length .. $];
429 
430 				ret ~= value;
431 			}
432 			return cast(T)ret;
433 		}
434 		else static if( is(T == BsonBinData) ){
435 			checkType(Type.binData);
436 			auto size = fromBsonData!int(m_data);
437 			auto type = cast(BsonBinData.Type)m_data[4];
438 			return BsonBinData(type, m_data[5 .. 5+size]);
439 		}
440 		else static if( is(T == BsonObjectID) ){ checkType(Type.objectID); return BsonObjectID(m_data[0 .. 12]); }
441 		else static if( is(T == bool) ){ checkType(Type.bool_); return m_data[0] != 0; }
442 		else static if( is(T == BsonDate) ){ checkType(Type.date); return BsonDate(fromBsonData!long(m_data)); }
443 		else static if( is(T == SysTime) ){
444 			checkType(Type.date);
445 			string data = cast(string)m_data[4 .. 4+fromBsonData!int(m_data)-1];
446 			return SysTime.fromISOString(data);
447 		}
448 		else static if( is(T == BsonRegex) ){
449 			checkType(Type.regex);
450 			auto d = m_data[0 .. $];
451 			auto expr = skipCString(d);
452 			auto options = skipCString(d);
453 			return BsonRegex(expr, options);
454 		}
455 		else static if( is(T == int) ){ checkType(Type.int_); return fromBsonData!int(m_data); }
456 		else static if( is(T == BsonTimestamp) ){ checkType(Type.timestamp); return BsonTimestamp(fromBsonData!long(m_data)); }
457 		else static if( is(T == long) ){ checkType(Type.long_); return fromBsonData!long(m_data); }
458 		else static if( is(T == Json) ){
459 			pragma(msg, "Bson.get!Json() and Bson.opCast!Json() will soon be removed. Please use Bson.toJson() instead.");
460 			return this.toJson();
461 		}
462 		else static if( is(T == UUID) ){
463 			checkType(Type.binData);
464 			auto bbd = this.get!BsonBinData();
465 			enforce(bbd.type == BsonBinData.Type.uuid, "BsonBinData value is type '"~bbd.type.enumToString~"', expected to be uuid");
466 			const ubyte[16] b = bbd.rawData;
467 			return UUID(b);
468 		}
469 		else static if( is(T == SysTime) ) {
470 			checkType(Type.date);
471 			return BsonDate(fromBsonData!long(m_data)).toSysTime();
472 		}
473 		else static assert(false, "Cannot cast "~typeof(this).stringof~" to '"~T.stringof~"'.");
474 	}
475 
476 	/**
477 		Converts the BSON value to a D value.
478 
479 		In addition to working like `get!T`, the following conversions are done:
480 		- `to!double` - casts int and long to double
481 		- `to!long` - casts int to long
482 		- `to!string` - returns the same as toString 
483 
484 		See_Also: `deserializeBson`, `opt`, `get`
485 	*/
486 	@property T to(T)()
487 	const {
488 		static if( is(T == double) ){
489 			checkType(Type.double_, Type.long_, Type.int_);
490 			if (m_type == Type.double_)
491 				return fromBsonData!double(m_data);
492 			else if (m_type == Type.int_)
493 				return cast(double)fromBsonData!int(m_data);
494 			else if (m_type == Type.long_)
495 				return cast(double)fromBsonData!long(m_data);
496 			else
497 				assert(false);
498 		}
499 		else static if( is(T == string) ){
500 			return toString();
501 		}
502 		else static if( is(Unqual!T == Bson[string]) || is(Unqual!T == const(Bson)[string]) ){
503 			checkType(Type.object);
504 			Bson[string] ret;
505 			auto d = m_data[4 .. $];
506 			while( d.length > 0 ){
507 				auto tp = cast(Type)d[0];
508 				if( tp == Type.end ) break;
509 				d = d[1 .. $];
510 				auto key = skipCString(d);
511 				auto value = Bson(tp, d);
512 				d = d[value.data.length .. $];
513 
514 				ret[key] = value;
515 			}
516 			return cast(T)ret;
517 		}
518 		else static if( is(Unqual!T == Bson[]) || is(Unqual!T == const(Bson)[]) ){
519 			checkType(Type.array);
520 			Bson[] ret;
521 			auto d = m_data[4 .. $];
522 			while( d.length > 0 ){
523 				auto tp = cast(Type)d[0];
524 				if( tp == Type.end ) break;
525 				/*auto key = */skipCString(d); // should be '0', '1', ...
526 				auto value = Bson(tp, d);
527 				d = d[value.data.length .. $];
528 
529 				ret ~= value;
530 			}
531 			return cast(T)ret;
532 		}
533 		else static if( is(T == BsonBinData) ){
534 			checkType(Type.binData);
535 			auto size = fromBsonData!int(m_data);
536 			auto type = cast(BsonBinData.Type)m_data[4];
537 			return BsonBinData(type, m_data[5 .. 5+size]);
538 		}
539 		else static if( is(T == BsonObjectID) ){ checkType(Type.objectID); return BsonObjectID(m_data[0 .. 12]); }
540 		else static if( is(T == bool) ){ checkType(Type.bool_); return m_data[0] != 0; }
541 		else static if( is(T == BsonDate) ){ checkType(Type.date); return BsonDate(fromBsonData!long(m_data)); }
542 		else static if( is(T == SysTime) ){
543 			checkType(Type.date);
544 			string data = cast(string)m_data[4 .. 4+fromBsonData!int(m_data)-1];
545 			return SysTime.fromISOString(data);
546 		}
547 		else static if( is(T == BsonRegex) ){
548 			checkType(Type.regex);
549 			auto d = m_data[0 .. $];
550 			auto expr = skipCString(d);
551 			auto options = skipCString(d);
552 			return BsonRegex(expr, options);
553 		}
554 		else static if( is(T == int) ){ checkType(Type.int_); return fromBsonData!int(m_data); }
555 		else static if( is(T == BsonTimestamp) ){ checkType(Type.timestamp); return BsonTimestamp(fromBsonData!long(m_data)); }
556 		else static if( is(T == long) ){
557 			checkType(Type.long_, Type.int_);
558 			if (m_type == Type.int_)
559 				return cast(long)fromBsonData!int(m_data);
560 			else if (m_type == Type.long_)
561 				return fromBsonData!long(m_data);
562 			else
563 				assert(false);
564 		}
565 		else static if( is(T == Json) ){
566 			return this.toJson();
567 		}
568 		else static if( is(T == UUID) ){
569 			checkType(Type.binData);
570 			auto bbd = this.get!BsonBinData();
571 			enforce(bbd.type == BsonBinData.Type.uuid, "BsonBinData value is type '"~bbd.type.enumToString~"', expected to be uuid");
572 			const ubyte[16] b = bbd.rawData;
573 			return UUID(b);
574 		}
575 		else static if( is(T == SysTime) ) {
576 			checkType(Type.date);
577 			return BsonDate(fromBsonData!long(m_data)).toSysTime();
578 		}
579 		else static assert(false, "Cannot convert "~typeof(this).stringof~" to '"~T.stringof~"'.");
580 	}
581 
582 	/** Returns the native type for this BSON if it matches the current runtime type.
583 
584 		If the runtime type does not match the given native type, the 'def' parameter is returned
585 		instead.
586 	*/
587 	T opt(T)(T def = T.init)
588 	{
589 		if (isNull()) return def;
590 		try return cast(T)this;
591 		catch (Exception e) return def;
592 	}
593 	/// ditto
594 	const(T) opt(T)(const(T) def = const(T).init)
595 	const {
596 		if (isNull()) return def;
597 		try return cast(T)this;
598 		catch (Exception e) return def;
599 	}
600 
601 	/** Returns the length of a BSON value of type String, Array, Object or BinData.
602 	*/
603 	@property size_t length() const {
604 		switch( m_type ){
605 			default: enforce(false, "Bson objects of type "~m_type.enumToString~" do not have a length field."); break;
606 			case Type..string, Type.code, Type.symbol: return (cast(string)this).length;
607 			case Type.array: return byValue.walkLength;
608 			case Type.object: return byValue.walkLength;
609 			case Type.binData: assert(false); //return (cast(BsonBinData)this).length; break;
610 		}
611 		assert(false);
612 	}
613 
614 	/** Converts a given JSON value to the corresponding BSON value.
615 	*/
616 	static Bson fromJson(in Json value)
617 	@trusted {
618 		auto app = appender!bdata_t();
619 		auto tp = writeBson(app, value);
620 		return Bson(tp, app.data);
621 	}
622 
623 	/** Converts a BSON value to a JSON value.
624 
625 		All BSON types that cannot be exactly represented as JSON, will
626 		be converted to a string.
627 	*/
628 	Json toJson()
629 	const {
630 		switch( this.type ){
631 			default: assert(false);
632 			case Bson.Type.double_: return Json(get!double());
633 			case Bson.Type..string: return Json(get!string());
634 			case Bson.Type.object:
635 				Json[string] ret;
636 				foreach (k, v; this.byKeyValue)
637 					ret[k] = v.toJson();
638 				return Json(ret);
639 			case Bson.Type.array:
640 				auto ret = new Json[this.length];
641 				foreach (i, v; this.byIndexValue)
642 					ret[i] = v.toJson();
643 				return Json(ret);
644 			case Bson.Type.binData: return Json(() @trusted { return cast(string)Base64.encode(get!BsonBinData.rawData); } ());
645 			case Bson.Type.objectID: return Json(get!BsonObjectID().toString());
646 			case Bson.Type.bool_: return Json(get!bool());
647 			case Bson.Type.date: return Json(get!BsonDate.toString());
648 			case Bson.Type.null_: return Json(null);
649 			case Bson.Type.regex: assert(false, "TODO");
650 			case Bson.Type.dbRef: assert(false, "TODO");
651 			case Bson.Type.code: return Json(get!string());
652 			case Bson.Type.symbol: return Json(get!string());
653 			case Bson.Type.codeWScope: assert(false, "TODO");
654 			case Bson.Type.int_: return Json(get!int());
655 			case Bson.Type.timestamp: return Json(get!BsonTimestamp().m_time);
656 			case Bson.Type.long_: return Json(get!long());
657 			case Bson.Type.undefined: return Json();
658 		}
659 	}
660 
661 	/** Returns a string representation of this BSON value in JSON format.
662 	*/
663 	string toString()
664 	const {
665 		auto ret = appender!string;
666 		toString(ret);
667 		return ret.data;
668 	}
669 
670 	void toString(R)(ref R range)
671 	const {
672 		switch (type)
673 		{
674 		case Bson.Type.objectID:
675 			range.put("ObjectID(");
676 			range.put(get!BsonObjectID().toString());
677 			range.put(")");
678 			break;
679 		case Bson.Type.object:
680 			// keep ordering of objects
681 			range.put("{");
682 			bool first = true;
683 			foreach (k, v; this.byKeyValue)
684 			{
685 				if (!first) range.put(",");
686 				first = false;
687 				range.put(Json(k).toString());
688 				range.put(":");
689 				v.toString(range);
690 			}
691 			range.put("}");
692 			break;
693 		case Bson.Type.array:
694 			range.put("[");
695 			foreach (i, v; this.byIndexValue)
696 			{
697 				if (i != 0) range.put(",");
698 				v.toString(range);
699 			}
700 			range.put("]");
701 			break;
702 		default:
703 			range.put(toJson().toString());
704 			break;
705 		}
706 	}
707 
708 	import std.typecons : Nullable;
709 
710 	/**
711 		Check whether the BSON object contains the given key.
712 	*/
713 	Nullable!Bson tryIndex(string key) const {
714 		checkType(Type.object);
715 		foreach (string idx, v; this.byKeyValue)
716 			if(idx == key)
717 				return Nullable!Bson(v);
718 		return Nullable!Bson.init;
719 	}
720 
721 	/** Allows accessing fields of a BSON object using `[]`.
722 
723 		Returns a null value if the specified field does not exist.
724 	*/
725 	inout(Bson) opIndex(string idx) inout {
726 		foreach (string key, v; this.byKeyValue)
727 			if( key == idx )
728 				return v;
729 		return Bson(null);
730 	}
731 	/// ditto
732 	void opIndexAssign(T)(in T value, string idx){
733 		// WARNING: it is ABSOLUTELY ESSENTIAL that ordering is not changed!!!
734 		// MongoDB depends on ordering of the Bson maps.
735 
736 		auto newcont = appender!bdata_t();
737 		checkType(Type.object);
738 		auto d = m_data[4 .. $];
739 		while( d.length > 0 ){
740 			auto tp = cast(Type)d[0];
741 			if( tp == Type.end ) break;
742 			d = d[1 .. $];
743 			auto key = skipCString(d);
744 			auto val = Bson(tp, d);
745 			d = d[val.data.length .. $];
746 
747 			if( key != idx ){
748 				// copy to new array
749 				newcont.put(cast(ubyte)tp);
750 				putCString(newcont, key);
751 				newcont.put(val.data);
752 			}
753 		}
754 
755 		static if( is(T == Bson) )
756 			alias bval = value;
757 		else
758 			auto bval = Bson(value);
759 
760 		newcont.put(cast(ubyte)bval.type);
761 		putCString(newcont, idx);
762 		newcont.put(bval.data);
763 
764 		auto newdata = appender!bdata_t();
765 		newdata.put(toBsonData(cast(uint)(newcont.data.length + 5)));
766 		newdata.put(newcont.data);
767 		newdata.put(cast(ubyte)0);
768 		m_data = newdata.data;
769 	}
770 
771 	///
772 	unittest {
773 		Bson value = Bson.emptyObject;
774 		value["a"] = 1;
775 		value["b"] = true;
776 		value["c"] = "foo";
777 		assert(value["a"] == Bson(1));
778 		assert(value["b"] == Bson(true));
779 		assert(value["c"] == Bson("foo"));
780 	}
781 
782 	///
783 	unittest {
784 		auto srcUuid = UUID("00010203-0405-0607-0809-0a0b0c0d0e0f");
785 
786 		Bson b = srcUuid;
787 		auto u = b.get!UUID();
788 
789 		assert(b.type == Bson.Type.binData);
790 		assert(b.get!BsonBinData().type == BsonBinData.Type.uuid);
791 		assert(u == srcUuid);
792 	}
793 
794 	/** Allows index based access of a BSON array value.
795 
796 		Returns a null value if the index is out of bounds.
797 	*/
798 	inout(Bson) opIndex(size_t idx) inout {
799 		foreach (size_t i, v; this.byIndexValue)
800 			if (i == idx)
801 				return v;
802 		return Bson(null);
803 	}
804 
805 	///
806 	unittest {
807 		Bson[] entries;
808 		entries ~= Bson(1);
809 		entries ~= Bson(true);
810 		entries ~= Bson("foo");
811 
812 		Bson value = Bson(entries);
813 		assert(value[0] == Bson(1));
814 		assert(value[1] == Bson(true));
815 		assert(value[2] == Bson("foo"));
816 	}
817 
818 	/** Removes an entry from a BSON obect.
819 
820 		If the key doesn't exit, this function will be a no-op.
821 	*/
822 	void remove(string key)
823 	{
824 		checkType(Type.object);
825 		auto d = m_data[4 .. $];
826 		while (d.length > 0) {
827 			size_t start_remainder = d.length;
828 			auto tp = cast(Type)d[0];
829 			if (tp == Type.end) break;
830 			d = d[1 .. $];
831 			auto ekey = skipCString(d);
832 			auto evalue = Bson(tp, d);
833 			d = d[evalue.data.length .. $];
834 
835 			if (ekey == key) {
836 				m_data = m_data[0 .. $-start_remainder] ~ d;
837 				break;
838 			}
839 		}
840 	}
841 
842 	unittest {
843 		auto o = Bson.emptyObject;
844 		o["a"] = Bson(1);
845 		o["b"] = Bson(2);
846 		o["c"] = Bson(3);
847 		assert(o.length == 3);
848 		o.remove("b");
849 		assert(o.length == 2);
850 		assert(o["a"] == Bson(1));
851 		assert(o["c"] == Bson(3));
852 		o.remove("c");
853 		assert(o.length == 1);
854 		assert(o["a"] == Bson(1));
855 		o.remove("c");
856 		assert(o.length == 1);
857 		assert(o["a"] == Bson(1));
858 		o.remove("a");
859 		assert(o.length == 0);
860 	}
861 
862 	/**
863 		Allows foreach iterating over BSON objects and arrays.
864 	*/
865 	int opApply(scope int delegate(Bson obj) del)
866 	const @system {
867 		foreach (value; byValue)
868 			if (auto ret = del(value))
869 				return ret;
870 		return 0;
871 	}
872 	/// ditto
873 	int opApply(scope int delegate(size_t idx, Bson obj) del)
874 	const @system {
875 		foreach (index, value; byIndexValue)
876 			if (auto ret = del(index, value))
877 				return ret;
878 		return 0;
879 	}
880 	/// ditto
881 	int opApply(scope int delegate(string idx, Bson obj) del)
882 	const @system {
883 		foreach (key, value; byKeyValue)
884 			if (auto ret = del(key, value))
885 				return ret;
886 		return 0;
887 	}
888 
889 	/// Iterates over all values of an object or array.
890 	auto byValue() const { checkType(Type.array, Type.object); return byKeyValueImpl().map!(t => t[1]); }
891 	/// Iterates over all index/value pairs of an array.
892 	auto byIndexValue() const { checkType(Type.array); return byKeyValueImpl().map!(t => Tuple!(size_t, "key", Bson, "value")(t[0].to!size_t, t[1])); }
893 	/// Iterates over all key/value pairs of an object.
894 	auto byKeyValue() const { checkType(Type.object); return byKeyValueImpl(); }
895 
896 	private auto byKeyValueImpl()
897 	const {
898 		checkType(Type.object, Type.array);
899 
900 		alias T = Tuple!(string, "key", Bson, "value");
901 
902 		static struct Rng {
903 			private {
904 				immutable(ubyte)[] data;
905 				string key;
906 				Bson value;
907 			}
908 
909 			@property bool empty() const { return data.length == 0; }
910 			@property T front() { return T(key, value); }
911 			@property Rng save() const { return this; }
912 
913 			void popFront()
914 			{
915 				auto tp = cast(Type)data[0];
916 				data = data[1 .. $];
917 				if (tp == Type.end) return;
918 				key = skipCString(data);
919 				value = Bson(tp, data);
920 				data = data[value.data.length .. $];
921 			}
922 		}
923 
924 		auto ret = Rng(m_data[4 .. $]);
925 		ret.popFront();
926 		return ret;
927 	}
928 
929 	///
930 	bool opEquals(ref const Bson other) const {
931 		if( m_type != other.m_type ) return false;
932 		if (m_type != Type.object)
933 			return m_data == other.m_data;
934 
935 		if (m_data == other.m_data)
936 			return true;
937 		// Similar objects can have a different key order, but they must have a same length
938 		if (m_data.length != other.m_data.length)
939 			return false;
940 
941 		foreach (k, ref v; this.byKeyValue)
942 		{
943 			if (other[k] != v)
944 				return false;
945 		}
946 
947 		return true;
948 	}
949 	/// ditto
950 	bool opEquals(const Bson other) const {
951 		if( m_type != other.m_type ) return false;
952 
953 		return opEquals(other);
954 	}
955 
956 	private void checkType(in Type[] valid_types...)
957 	const {
958 		foreach( t; valid_types )
959 			if( m_type == t )
960 				return;
961 		throw new Exception("BSON value is type '"~m_type.enumToString~"', expected to be one of "~valid_types.map!(t => t.enumToString).join(", "));
962 	}
963 }
964 
965 
966 /**
967 	Represents a BSON binary data value (Bson.Type.binData).
968 */
969 struct BsonBinData {
970 @safe:
971 
972 	enum Type : ubyte {
973 		generic = 0x00,
974 		function_ = 0x01,
975 		binaryOld = 0x02,
976 		uuid = 0x03,
977 		md5 = 0x05,
978 		userDefined = 0x80,
979 
980 		deprecated("Use `generic` instead") Generic = generic,          /// Compatibility alias
981 		deprecated("Use `function_` instead") Function = function_,       /// Compatibility alias
982 		deprecated("Use `binaryOld` instead") BinaryOld = binaryOld,      /// Compatibility alias
983 		deprecated("Use `uuid` instead") UUID = uuid,                /// Compatibility alias
984 		deprecated("Use `md5` instead") MD5 = md5,                  /// Compatibility alias
985 		deprecated("Use `userDefined` instead") UserDefined	= userDefined,  /// Compatibility alias
986 	}
987 
988 	private {
989 		Type m_type;
990 		bdata_t m_data;
991 	}
992 
993 	this(Type type, immutable(ubyte)[] data)
994 	{
995 		m_type = type;
996 		m_data = data;
997 	}
998 
999 	@property Type type() const { return m_type; }
1000 	@property bdata_t rawData() const { return m_data; }
1001 }
1002 
1003 
1004 /**
1005 	Represents a BSON object id (Bson.Type.binData).
1006 */
1007 struct BsonObjectID {
1008 @safe:
1009 
1010 	private {
1011 		ubyte[12] m_bytes;
1012 		static immutable uint MACHINE_ID;
1013 		static immutable int ms_pid;
1014 		static uint ms_inc = 0;
1015 	}
1016 
1017     shared static this()
1018     {
1019 		import std.process;
1020 		import std.random;
1021         MACHINE_ID = uniform(0, 0xffffff);
1022         ms_pid = thisProcessID;
1023     }
1024 
1025     static this()
1026     {
1027 		import std.random;
1028         ms_inc = uniform(0, 0xffffff);
1029     }
1030 
1031 	/** Constructs a new object ID from the given raw byte array.
1032 	*/
1033 	this(in ubyte[] bytes)
1034 	{
1035 		assert(bytes.length == 12);
1036 		m_bytes[] = bytes[];
1037 	}
1038 
1039 	/** Creates an on object ID from a string in standard hexa-decimal form.
1040 	*/
1041 	static BsonObjectID fromString(string str)
1042 	{
1043 		import std.conv : ConvException;
1044 		static const lengthex = new ConvException("BSON Object ID string must be 24 characters.");
1045 		static const charex = new ConvException("Not a valid hex string.");
1046 
1047 		if (str.length != 24) throw lengthex;
1048 		BsonObjectID ret = void;
1049 		uint b = 0;
1050 		foreach( i, ch; str ){
1051 			ubyte n;
1052 			if( ch >= '0' && ch <= '9' ) n = cast(ubyte)(ch - '0');
1053 			else if( ch >= 'a' && ch <= 'f' ) n = cast(ubyte)(ch - 'a' + 10);
1054 			else if( ch >= 'A' && ch <= 'F' ) n = cast(ubyte)(ch - 'F' + 10);
1055 			else throw charex;
1056 			b <<= 4;
1057 			b += n;
1058 			if( i % 8 == 7 ){
1059 				auto j = i / 8;
1060 				ret.m_bytes[j*4 .. (j+1)*4] = toBigEndianData(b)[];
1061 				b = 0;
1062 			}
1063 		}
1064 		return ret;
1065 	}
1066 	/// ditto
1067 	alias fromHexString = fromString;
1068 
1069 	/** Generates a unique object ID.
1070 	 *
1071 	 *   By default it will use `Clock.currTime(UTC())` as the timestamp
1072 	 *   which guarantees that `BsonObjectID`s are chronologically
1073 	 *   sorted.
1074 	*/
1075 	static BsonObjectID generate(in SysTime time = Clock.currTime(UTC()))
1076 	{
1077 		import std.datetime;
1078 
1079 		BsonObjectID ret = void;
1080 		ret.m_bytes[0 .. 4] = toBigEndianData(cast(uint)time.toUnixTime())[];
1081 		ret.m_bytes[4 .. 7] = toBsonData(MACHINE_ID)[0 .. 3];
1082 		ret.m_bytes[7 .. 9] = toBsonData(cast(ushort)ms_pid)[];
1083 		ret.m_bytes[9 .. 12] = toBigEndianData(ms_inc++)[1 .. 4];
1084 		return ret;
1085 	}
1086 
1087 	/** Creates a pseudo object ID that matches the given date.
1088 
1089 		This kind of ID can be useful to query a database for items in a certain
1090 		date interval using their ID. This works using the property of standard BSON
1091 		object IDs that they store their creation date as part of the ID. Note that
1092 		this date part is only 32-bit wide and is limited to the same timespan as a
1093 		32-bit Unix timestamp.
1094 	*/
1095 	static BsonObjectID createDateID(in SysTime time)
1096 	{
1097 		BsonObjectID ret;
1098 		ret.m_bytes[0 .. 4] = toBigEndianData(cast(uint)time.toUnixTime())[];
1099 		return ret;
1100 	}
1101 
1102 	/** Returns true for any non-zero ID.
1103 	*/
1104 	@property bool valid() const {
1105 		foreach( b; m_bytes )
1106 			if( b != 0 )
1107 				return true;
1108 		return false;
1109 	}
1110 
1111 	/** Extracts the time/date portion of the object ID.
1112 
1113 		For IDs created using the standard generation algorithm or using createDateID
1114 		this will return the associated time stamp.
1115 	*/
1116 	@property SysTime timeStamp()
1117 	const {
1118 		ubyte[4] tm = m_bytes[0 .. 4];
1119 		return SysTime(unixTimeToStdTime(bigEndianToNative!uint(tm)));
1120 	}
1121 
1122 	/** Allows for relational comparison of different IDs.
1123 	*/
1124 	int opCmp(ref const BsonObjectID other)
1125 	const {
1126 		import core.stdc.string;
1127 		return () @trusted { return memcmp(m_bytes.ptr, other.m_bytes.ptr, m_bytes.length); } ();
1128 	}
1129 
1130 	/** Converts the ID to its standard hexa-decimal string representation.
1131 	*/
1132 	string toString() const pure {
1133 		enum hexdigits = "0123456789abcdef";
1134 		auto ret = new char[24];
1135 		foreach( i, b; m_bytes ){
1136 			ret[i*2+0] = hexdigits[(b >> 4) & 0x0F];
1137 			ret[i*2+1] = hexdigits[b & 0x0F];
1138 		}
1139 		return ret;
1140 	}
1141 
1142 	inout(ubyte)[] opCast() inout return { return m_bytes; }
1143 }
1144 
1145 unittest {
1146 	auto t0 = SysTime(Clock.currTime(UTC()).toUnixTime.unixTimeToStdTime);
1147 	auto id = BsonObjectID.generate();
1148 	auto t1 = SysTime(Clock.currTime(UTC()).toUnixTime.unixTimeToStdTime);
1149 	assert(t0 <= id.timeStamp);
1150 	assert(id.timeStamp <= t1);
1151 
1152 	id = BsonObjectID.generate(t0);
1153 	assert(id.timeStamp == t0);
1154 
1155 	id = BsonObjectID.generate(t1);
1156 	assert(id.timeStamp == t1);
1157 
1158 	immutable dt = DateTime(2014, 07, 31, 19, 14, 55);
1159 	id = BsonObjectID.generate(SysTime(dt, UTC()));
1160 	assert(id.timeStamp == SysTime(dt, UTC()));
1161 }
1162 
1163 unittest {
1164 	auto b = Bson(true);
1165 	assert(b.opt!bool(false) == true);
1166 	assert(b.opt!int(12) == 12);
1167 	assert(b.opt!(Bson[])(null).length == 0);
1168 
1169 	const c = b;
1170 	assert(c.opt!bool(false) == true);
1171 	assert(c.opt!int(12) == 12);
1172 	assert(c.opt!(Bson[])(null).length == 0);
1173 }
1174 
1175 
1176 /**
1177 	Represents a BSON date value (`Bson.Type.date`).
1178 
1179 	BSON date values are stored in UNIX time format, counting the number of
1180 	milliseconds from 1970/01/01.
1181 */
1182 struct BsonDate {
1183 @safe:
1184 
1185 	private long m_time; // milliseconds since UTC unix epoch
1186 
1187 	/** Constructs a BsonDate from the given date value.
1188 
1189 		The time-zone independent Date and DateTime types are assumed to be in
1190 		the local time zone and converted to UTC if tz is left to null.
1191 	*/
1192 	this(in Date date, immutable TimeZone tz = null) { this(SysTime(date, tz)); }
1193 	/// ditto
1194 	this(in DateTime date, immutable TimeZone tz = null) { this(SysTime(date, tz)); }
1195 	/// ditto
1196 	this(in SysTime date) { this(fromStdTime(date.stdTime()).m_time); }
1197 
1198 	/** Constructs a BsonDate from the given UNIX time.
1199 
1200 		unix_time needs to be given in milliseconds from 1970/01/01. This is
1201 		the native storage format for BsonDate.
1202 	*/
1203 	this(long unix_time)
1204 	{
1205 		m_time = unix_time;
1206 	}
1207 
1208 	/** Constructs a BsonDate from the given date/time string in ISO extended format.
1209 	*/
1210 	static BsonDate fromString(string iso_ext_string) { return BsonDate(SysTime.fromISOExtString(iso_ext_string)); }
1211 
1212 	/** Constructs a BsonDate from the given date/time in standard time as defined in `std.datetime`.
1213 	*/
1214 	static BsonDate fromStdTime(long std_time)
1215 	{
1216 		enum zero = unixTimeToStdTime(0);
1217 		return BsonDate((std_time - zero) / 10_000L);
1218 	}
1219 
1220 	/** The raw unix time value.
1221 
1222 		This is the native storage/transfer format of a BsonDate.
1223 	*/
1224 	@property long value() const { return m_time; }
1225 	/// ditto
1226 	@property void value(long v) { m_time = v; }
1227 
1228 	/** Returns the date formatted as ISO extended format.
1229 	*/
1230 	string toString() const { return toSysTime().toISOExtString(); }
1231 
1232 	/* Converts to a SysTime using UTC timezone.
1233 	*/
1234 	SysTime toSysTime() const {
1235 		return toSysTime(UTC());
1236 	}
1237 
1238 	/* Converts to a SysTime with a given timezone.
1239 	*/
1240 	SysTime toSysTime(immutable TimeZone tz) const {
1241 		auto zero = unixTimeToStdTime(0);
1242 		return SysTime(zero + m_time * 10_000L, tz);
1243 	}
1244 
1245 	/** Allows relational and equality comparisons.
1246 	*/
1247 	bool opEquals(ref const BsonDate other) const { return m_time == other.m_time; }
1248 	/// ditto
1249 	int opCmp(ref const BsonDate other) const {
1250 		if( m_time == other.m_time ) return 0;
1251 		if( m_time < other.m_time ) return -1;
1252 		else return 1;
1253 	}
1254 }
1255 
1256 
1257 /**
1258 	Represents a BSON timestamp value `(Bson.Type.timestamp)`.
1259 */
1260 struct BsonTimestamp {
1261 @safe:
1262 
1263 	private long m_time;
1264 
1265 	this( long time ){
1266 		m_time = time;
1267 	}
1268 }
1269 
1270 
1271 /**
1272 	Represents a BSON regular expression value `(Bson.Type.regex)`.
1273 */
1274 struct BsonRegex {
1275 @safe:
1276 
1277 	private {
1278 		string m_expr;
1279 		string m_options;
1280 	}
1281 
1282 	this(string expr, string options)
1283 	{
1284 		m_expr = expr;
1285 		m_options = options;
1286 	}
1287 
1288 	@property string expression() const { return m_expr; }
1289 	@property string options() const { return m_options; }
1290 }
1291 
1292 
1293 /**
1294 	Serializes the given value to BSON.
1295 
1296 	The following types of values are supported:
1297 
1298 	$(DL
1299 		$(DT `Bson`)            $(DD Used as-is)
1300 		$(DT `Json`)            $(DD Converted to BSON)
1301 		$(DT `BsonBinData`)     $(DD Converted to `Bson.Type.binData`)
1302 		$(DT `BsonObjectID`)    $(DD Converted to `Bson.Type.objectID`)
1303 		$(DT `BsonDate`)        $(DD Converted to `Bson.Type.date`)
1304 		$(DT `BsonTimestamp`)   $(DD Converted to `Bson.Type.timestamp`)
1305 		$(DT `BsonRegex`)       $(DD Converted to `Bson.Type.regex`)
1306 		$(DT `null`)            $(DD Converted to `Bson.Type.null_`)
1307 		$(DT `bool`)            $(DD Converted to `Bson.Type.bool_`)
1308 		$(DT `float`, `double`)   $(DD Converted to `Bson.Type.double_`)
1309 		$(DT `short`, `ushort`, `int`, `uint`, `long`, `ulong`) $(DD Converted to `Bson.Type.long_`)
1310 		$(DT `string`)          $(DD Converted to `Bson.Type.string`)
1311 		$(DT `ubyte[]`)         $(DD Converted to `Bson.Type.binData`)
1312 		$(DT `T[]`)             $(DD Converted to `Bson.Type.array`)
1313 		$(DT `T[string]`)       $(DD Converted to `Bson.Type.object`)
1314 		$(DT `struct`)          $(DD Converted to `Bson.Type.object`)
1315 		$(DT `class`)           $(DD Converted to `Bson.Type.object` or `Bson.Type.null_`)
1316 	)
1317 
1318 	All entries of an array or an associative array, as well as all R/W properties and
1319 	all fields of a struct/class are recursively serialized using the same rules.
1320 
1321 	Fields ending with an underscore will have the last underscore stripped in the
1322 	serialized output. This makes it possible to use fields with D keywords as their name
1323 	by simply appending an underscore.
1324 
1325 	The following methods can be used to customize the serialization of structs/classes:
1326 
1327 	---
1328 	Bson toBson() const;
1329 	static T fromBson(Bson src);
1330 
1331 	Json toJson() const;
1332 	static T fromJson(Json src);
1333 
1334 	string toString() const;
1335 	static T fromString(string src);
1336 	---
1337 
1338 	The methods will have to be defined in pairs. The first pair that is implemented by
1339 	the type will be used for serialization (i.e. `toBson` overrides `toJson`).
1340 
1341 	See_Also: `deserializeBson`
1342 */
1343 Bson serializeToBson(T)(auto ref T value, ubyte[] buffer = null)
1344 {
1345 	return serialize!BsonSerializer(value, buffer);
1346 }
1347 
1348 
1349 template deserializeBson(T)
1350 {
1351 	/**
1352 		Deserializes a BSON value into the destination variable.
1353 
1354 		The same types as for `serializeToBson()` are supported and handled inversely.
1355 
1356 		See_Also: `serializeToBson`
1357 	*/
1358 	void deserializeBson(ref T dst, Bson src)
1359 	{
1360 		dst = deserializeBson!T(src);
1361 	}
1362 	/// ditto
1363 	T deserializeBson(Bson src)
1364 	{
1365 		return deserialize!(BsonSerializer, T)(src);
1366 	}
1367 }
1368 
1369 unittest {
1370 	import std.stdio;
1371 	enum Foo : string { k = "test" }
1372 	enum Boo : int { l = 5 }
1373 	static struct S { float a; double b; bool c; int d; string e; byte f; ubyte g; long h; ulong i; float[] j; Foo k; Boo l;}
1374 	immutable S t = {1.5, -3.0, true, int.min, "Test", -128, 255, long.min, ulong.max, [1.1, 1.2, 1.3], Foo.k, Boo.l,};
1375 	S u;
1376 	deserializeBson(u, serializeToBson(t));
1377 	assert(t.a == u.a);
1378 	assert(t.b == u.b);
1379 	assert(t.c == u.c);
1380 	assert(t.d == u.d);
1381 	assert(t.e == u.e);
1382 	assert(t.f == u.f);
1383 	assert(t.g == u.g);
1384 	assert(t.h == u.h);
1385 	assert(t.i == u.i);
1386 	assert(t.j == u.j);
1387 	assert(t.k == u.k);
1388 	assert(t.l == u.l);
1389 }
1390 
1391 unittest
1392 {
1393 	assert(uint.max == serializeToBson(uint.max).deserializeBson!uint);
1394 	assert(ulong.max == serializeToBson(ulong.max).deserializeBson!ulong);
1395 }
1396 
1397 unittest {
1398 	assert(deserializeBson!SysTime(serializeToBson(SysTime(0))) == SysTime(0));
1399 	assert(deserializeBson!SysTime(serializeToBson(SysTime(0, UTC()))) == SysTime(0, UTC()));
1400 	assert(deserializeBson!Date(serializeToBson(Date.init)) == Date.init);
1401 	assert(deserializeBson!Date(serializeToBson(Date(2001, 1, 1))) == Date(2001, 1, 1));
1402 }
1403 
1404 @safe unittest {
1405 	static struct A { int value; static A fromJson(Json val) @safe { return A(val.get!int); } Json toJson() const @safe { return Json(value); } Bson toBson() { return Bson(); } }
1406 	static assert(!isStringSerializable!A && isJsonSerializable!A && !isBsonSerializable!A);
1407 	static assert(!isStringSerializable!(const(A)) && isJsonSerializable!(const(A)) && !isBsonSerializable!(const(A)));
1408 //	assert(serializeToBson(const A(123)) == Bson(123));
1409 //	assert(serializeToBson(A(123))       == Bson(123));
1410 
1411 	static struct B { int value; static B fromBson(Bson val) @safe { return B(val.get!int); } Bson toBson() const @safe { return Bson(value); } Json toJson() { return Json(); } }
1412 	static assert(!isStringSerializable!B && !isJsonSerializable!B && isBsonSerializable!B);
1413 	static assert(!isStringSerializable!(const(B)) && !isJsonSerializable!(const(B)) && isBsonSerializable!(const(B)));
1414 	assert(serializeToBson(const B(123)) == Bson(123));
1415 	assert(serializeToBson(B(123))       == Bson(123));
1416 
1417 	static struct C { int value; static C fromString(string val) @safe { return C(val.to!int); } string toString() const @safe { return value.to!string; } Json toJson() { return Json(); } }
1418 	static assert(isStringSerializable!C && !isJsonSerializable!C && !isBsonSerializable!C);
1419 	static assert(isStringSerializable!(const(C)) && !isJsonSerializable!(const(C)) && !isBsonSerializable!(const(C)));
1420 	assert(serializeToBson(const C(123)) == Bson("123"));
1421 	assert(serializeToBson(C(123))       == Bson("123"));
1422 
1423 	static struct D { int value; string toString() const { return ""; } }
1424 	static assert(!isStringSerializable!D && !isJsonSerializable!D && !isBsonSerializable!D);
1425 	static assert(!isStringSerializable!(const(D)) && !isJsonSerializable!(const(D)) && !isBsonSerializable!(const(D)));
1426 	assert(serializeToBson(const D(123)) == serializeToBson(["value": 123]));
1427 	assert(serializeToBson(D(123))       == serializeToBson(["value": 123]));
1428 
1429 	// test if const(class) is serializable
1430 	static class E { int value; this(int v) @safe { value = v; } static E fromBson(Bson val) @safe { return new E(val.get!int); } Bson toBson() const @safe { return Bson(value); } Json toJson() { return Json(); } }
1431 	static assert(!isStringSerializable!E && !isJsonSerializable!E && isBsonSerializable!E);
1432 	static assert(!isStringSerializable!(const(E)) && !isJsonSerializable!(const(E)) && isBsonSerializable!(const(E)));
1433 	assert(serializeToBson(new const E(123)) == Bson(123));
1434 	assert(serializeToBson(new E(123))       == Bson(123));
1435 }
1436 
1437 @safe unittest {
1438 	static struct E { ubyte[4] bytes; ubyte[] more; }
1439 	auto e = E([1, 2, 3, 4], [5, 6]);
1440 	auto eb = serializeToBson(e);
1441 	assert(eb["bytes"].type == Bson.Type.binData);
1442 	assert(eb["more"].type == Bson.Type.binData);
1443 	assert(e == deserializeBson!E(eb));
1444 }
1445 
1446 @safe unittest {
1447 	static class C {
1448 	@safe:
1449 		int a;
1450 		private int _b;
1451 		@property int b() const { return _b; }
1452 		@property void b(int v) { _b = v; }
1453 
1454 		@property int test() const @safe { return 10; }
1455 
1456 		void test2() {}
1457 	}
1458 	C c = new C;
1459 	c.a = 1;
1460 	c.b = 2;
1461 
1462 	C d;
1463 	deserializeBson(d, serializeToBson(c));
1464 	assert(c.a == d.a);
1465 	assert(c.b == d.b);
1466 
1467 	const(C) e = c; // serialize const class instances (issue #653)
1468 	deserializeBson(d, serializeToBson(e));
1469 	assert(e.a == d.a);
1470 	assert(e.b == d.b);
1471 }
1472 
1473 unittest {
1474 	static struct C { @safe: int value; static C fromString(string val) { return C(val.to!int); } string toString() const { return value.to!string; } }
1475 	enum Color { Red, Green, Blue }
1476 	{
1477 		static class T {
1478 			@safe:
1479 			string[Color] enumIndexedMap;
1480 			string[C] stringableIndexedMap;
1481 			this() {
1482 				enumIndexedMap = [ Color.Red : "magenta", Color.Blue : "deep blue" ];
1483 								stringableIndexedMap = [ C(42) : "forty-two" ];
1484 			}
1485 		}
1486 
1487 		T original = new T;
1488 		original.enumIndexedMap[Color.Green] = "olive";
1489 		T other;
1490 		deserializeBson(other, serializeToBson(original));
1491 		assert(serializeToBson(other) == serializeToBson(original));
1492 	}
1493 	{
1494 		static struct S {
1495 			string[Color] enumIndexedMap;
1496 			string[C] stringableIndexedMap;
1497 		}
1498 
1499 		S original;
1500 		original.enumIndexedMap = [ Color.Red : "magenta", Color.Blue : "deep blue" ];
1501 		original.enumIndexedMap[Color.Green] = "olive";
1502 				original.stringableIndexedMap = [ C(42) : "forty-two" ];
1503 		S other;
1504 		deserializeBson(other, serializeToBson(original));
1505 		assert(serializeToBson(other) == serializeToBson(original));
1506 	}
1507 }
1508 
1509 unittest {
1510 	ubyte[] data = [1, 2, 3];
1511 	auto bson = serializeToBson(data);
1512 	assert(bson.type == Bson.Type.binData);
1513 	assert(deserializeBson!(ubyte[])(bson) == data);
1514 }
1515 
1516 unittest { // issue #709
1517  	ulong[] data = [2354877787627192443, 1, 2354877787627192442];
1518 	auto bson = Bson.fromJson(serializeToBson(data).toJson);
1519 	assert(deserializeBson!(ulong[])(bson) == data);
1520 }
1521 
1522 unittest { // issue #709
1523  	uint[] data = [1, 2, 3, 4];
1524 	auto bson = Bson.fromJson(serializeToBson(data).toJson);
1525 //	assert(deserializeBson!(uint[])(bson) == data);
1526 	assert(deserializeBson!(ulong[])(bson).equal(data));
1527 }
1528 
1529 unittest {
1530 	import std.typecons;
1531 	Nullable!bool x;
1532 	auto bson = serializeToBson(x);
1533 	assert(bson.type == Bson.Type.null_);
1534 	deserializeBson(x, bson);
1535 	assert(x.isNull);
1536 	x = true;
1537 	bson = serializeToBson(x);
1538 	assert(bson.type == Bson.Type.bool_ && bson.get!bool == true);
1539 	deserializeBson(x, bson);
1540 	assert(x == true);
1541 }
1542 
1543 unittest { // issue #793
1544 	char[] test = "test".dup;
1545 	auto bson = serializeToBson(test);
1546 	//assert(bson.type == Bson.Type.string);
1547 	//assert(bson.get!string == "test");
1548 	assert(bson.type == Bson.Type.array);
1549 	assert(bson[0].type == Bson.Type..string && bson[0].get!string == "t");
1550 }
1551 
1552 @safe unittest { // issue #2212
1553 	auto bsonRegex = Bson(BsonRegex(".*", "i"));
1554 	auto parsedRegex = bsonRegex.get!BsonRegex;
1555 	assert(bsonRegex.type == Bson.Type.regex);
1556 	assert(parsedRegex.expression == ".*");
1557 	assert(parsedRegex.options == "i");
1558 }
1559 
1560 unittest
1561 {
1562 	UUID uuid = UUID("35399104-fbc9-4c08-bbaf-65a5efe6f5f2");
1563 
1564 	auto bson = Bson(uuid);
1565 	assert(bson.get!UUID == uuid);
1566 	assert(bson.deserializeBson!UUID == uuid);
1567 
1568 	bson = Bson([Bson(uuid)]);
1569 	assert(bson.deserializeBson!(UUID[]) == [uuid]);
1570 
1571 	bson = [uuid].serializeToBson();
1572 	assert(bson.deserializeBson!(UUID[]) == [uuid]);
1573 }
1574 
1575 /**
1576 	Serializes to an in-memory BSON representation.
1577 
1578 	See_Also: `vibe.data.serialization.serialize`, `vibe.data.serialization.deserialize`, `serializeToBson`, `deserializeBson`
1579 */
1580 struct BsonSerializer {
1581 	import vibe.utils.array : AllocAppender;
1582 
1583 	private {
1584 		AllocAppender!(ubyte[]) m_dst;
1585 		size_t[] m_compositeStack;
1586 		Bson.Type m_type = Bson.Type.null_;
1587 		Bson m_inputData;
1588 		string m_entryName;
1589 		size_t m_entryIndex = size_t.max;
1590 	}
1591 
1592 	this(Bson input)
1593 	@safe {
1594 		m_inputData = input;
1595 	}
1596 
1597 	this(ubyte[] buffer)
1598 	@safe {
1599 		import vibe.internal.utilallocator;
1600 		m_dst = () @trusted { return AllocAppender!(ubyte[])(vibeThreadAllocator(), buffer); } ();
1601 	}
1602 
1603 	@disable this(this);
1604 
1605 	template isSupportedValueType(T) { enum isSupportedValueType = is(typeof(getBsonTypeID(T.init))); }
1606 
1607 	//
1608 	// serialization
1609 	//
1610 	Bson getSerializedResult()
1611 	@safe {
1612 		auto ret = Bson(m_type, () @trusted { return cast(immutable)m_dst.data; } ());
1613 		() @trusted { m_dst.reset(); } ();
1614 		m_type = Bson.Type.null_;
1615 		return ret;
1616 	}
1617 
1618 	void beginWriteDictionary(Traits)()
1619 	{
1620 		writeCompositeEntryHeader(Bson.Type.object);
1621 		m_compositeStack ~= m_dst.data.length;
1622 		m_dst.put(toBsonData(cast(int)0));
1623 	}
1624 	void endWriteDictionary(Traits)()
1625 	{
1626 		m_dst.put(Bson.Type.end);
1627 		auto sh = m_compositeStack[$-1];
1628 		m_compositeStack.length--;
1629 		m_dst.data[sh .. sh + 4] = toBsonData(cast(uint)(m_dst.data.length - sh))[];
1630 	}
1631 	void beginWriteDictionaryEntry(Traits)(string name) { m_entryName = name; }
1632 	void endWriteDictionaryEntry(Traits)(string name) {}
1633 
1634 	void beginWriteArray(Traits)(size_t)
1635 	{
1636 		writeCompositeEntryHeader(Bson.Type.array);
1637 		m_compositeStack ~= m_dst.data.length;
1638 		m_dst.put(toBsonData(cast(int)0));
1639 	}
1640 	void endWriteArray(Traits)() { endWriteDictionary!Traits(); }
1641 	void beginWriteArrayEntry(Traits)(size_t idx) { m_entryIndex = idx; }
1642 	void endWriteArrayEntry(Traits)(size_t idx) {}
1643 
1644 	void writeValue(Traits, T)(auto ref T value) { writeValueH!(T, true)(value); }
1645 
1646 	private void writeValueH(T, bool write_header)(auto ref T value)
1647 	{
1648 		alias UT = Unqual!T;
1649 		static if (write_header) writeCompositeEntryHeader(getBsonTypeID(value));
1650 
1651 		static if (is(UT == Bson)) { m_dst.put(value.data); }
1652 		else static if (is(UT == Json)) { m_dst.put(Bson(value).data); } // FIXME: use .writeBsonValue
1653 		else static if (is(UT == typeof(null))) {}
1654 		else static if (is(UT == string)) { m_dst.put(toBsonData(cast(uint)value.length+1)); m_dst.putCString(value); }
1655 		else static if (is(UT == BsonBinData)) { m_dst.put(toBsonData(cast(int)value.rawData.length)); m_dst.put(value.type); m_dst.put(value.rawData); }
1656 		else static if (is(UT == BsonObjectID)) { m_dst.put(value.m_bytes[]); }
1657 		else static if (is(UT == BsonDate)) { m_dst.put(toBsonData(value.m_time)); }
1658 		else static if (is(UT == SysTime)) { m_dst.put(toBsonData(BsonDate(value).m_time)); }
1659 		else static if (is(UT == BsonRegex)) { m_dst.putCString(value.expression); m_dst.putCString(value.options); }
1660 		else static if (is(UT == BsonTimestamp)) { m_dst.put(toBsonData(value.m_time)); }
1661 		else static if (is(UT == bool)) { m_dst.put(cast(ubyte)(value ? 0x01 : 0x00)); }
1662 		else static if (is(UT : int) && isIntegral!UT) { m_dst.put(toBsonData(cast(int)value)); }
1663 		else static if (is(UT : long) && isIntegral!UT) { m_dst.put(toBsonData(value)); }
1664 		else static if (is(UT : double) && isFloatingPoint!UT) { m_dst.put(toBsonData(cast(double)value)); }
1665 		else static if (is(UT == UUID)) { m_dst.put(Bson(value).data); }
1666 		else static if (isBsonSerializable!UT) {
1667 			static if (!__traits(compiles, () @safe { return value.toBson(); } ()))
1668 				pragma(msg, "Non-@safe toBson/fromBson methods are deprecated - annotate "~T.stringof~".toBson() with @safe.");
1669 			m_dst.put(() @trusted { return value.toBson(); } ().data);
1670 		} else static if (isJsonSerializable!UT) {
1671 			static if (!__traits(compiles, () @safe { return value.toJson(); } ()))
1672 				pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~UT.stringof~".toJson() with @safe.");
1673 			m_dst.put(Bson(() @trusted { return value.toJson(); } ()).data);
1674 		} else static if (is(UT : const(ubyte)[])) { writeValueH!(BsonBinData, false)(BsonBinData(BsonBinData.Type.generic, value.idup)); }
1675 		else static assert(false, "Unsupported type: " ~ UT.stringof);
1676 	}
1677 
1678 	private void writeCompositeEntryHeader(Bson.Type tp)
1679 	@safe {
1680 		if (!m_compositeStack.length) {
1681 			assert(m_type == Bson.Type.null_, "Overwriting root item.");
1682 			m_type = tp;
1683 		}
1684 
1685 		if (m_entryName !is null) {
1686 			m_dst.put(tp);
1687 			m_dst.putCString(m_entryName);
1688 			m_entryName = null;
1689 		} else if (m_entryIndex != size_t.max) {
1690 			import std.format;
1691 			m_dst.put(tp);
1692 			static struct Wrapper {
1693 				@trusted:
1694 				AllocAppender!(ubyte[])* app;
1695 				void put(char ch) { (*app).put(ch); }
1696 				void put(in char[] str) { (*app).put(cast(const(ubyte)[])str); }
1697 			}
1698 			auto wr = Wrapper(&m_dst);
1699 			wr.formattedWrite("%d\0", m_entryIndex);
1700 			m_entryIndex = size_t.max;
1701 		}
1702 	}
1703 
1704 	//
1705 	// deserialization
1706 	//
1707 	void readDictionary(Traits)(scope void delegate(string) @safe entry_callback)
1708 	{
1709 		enforce(m_inputData.type == Bson.Type.object, "Expected object instead of "~m_inputData.type.enumToString);
1710 		auto old = m_inputData;
1711 		foreach (string name, value; old.byKeyValue) {
1712 			m_inputData = value;
1713 			entry_callback(name);
1714 		}
1715 		m_inputData = old;
1716 	}
1717 
1718 	void beginReadDictionaryEntry(Traits)(string name) {}
1719 	void endReadDictionaryEntry(Traits)(string name) {}
1720 
1721 	void readArray(Traits)(scope void delegate(size_t) @safe size_callback, scope void delegate() @safe entry_callback)
1722 	{
1723 		enforce(m_inputData.type == Bson.Type.array, "Expected array instead of "~m_inputData.type.enumToString);
1724 		auto old = m_inputData;
1725 		foreach (value; old.byValue) {
1726 			m_inputData = value;
1727 			entry_callback();
1728 		}
1729 		m_inputData = old;
1730 	}
1731 
1732 	void beginReadArrayEntry(Traits)(size_t index) {}
1733 	void endReadArrayEntry(Traits)(size_t index) {}
1734 
1735 	T readValue(Traits, T)()
1736 	{
1737 		static if (is(T == Bson)) return m_inputData;
1738 		else static if (is(T == Json)) return m_inputData.toJson();
1739 		else static if (is(T == bool)) return m_inputData.get!bool();
1740 		else static if (is(T == uint)) return cast(T)m_inputData.get!int();
1741 		else static if (is(T : int)) {
1742 			if(m_inputData.type == Bson.Type.long_) {
1743 				enforce((m_inputData.get!long() >= int.min) && (m_inputData.get!long() <= int.max), "Long out of range while attempting to deserialize to int: " ~ m_inputData.get!long.to!string);
1744 				return cast(T)m_inputData.get!long();
1745 			}
1746 			else return m_inputData.get!int().to!T;
1747 		}
1748 		else static if (is(T : long)) {
1749 			if(m_inputData.type == Bson.Type.int_) return cast(T)m_inputData.get!int();
1750 			else return cast(T)m_inputData.get!long();
1751 		}
1752 		else static if (is(T : double)) return cast(T)m_inputData.get!double();
1753 		else static if (is(T == SysTime)) {
1754 			// support legacy behavior to serialize as string
1755 			if (m_inputData.type == Bson.Type..string) return SysTime.fromISOExtString(m_inputData.get!string);
1756 			else return m_inputData.get!BsonDate().toSysTime();
1757 		}
1758 		else static if (isBsonSerializable!T) {
1759 			static if (!__traits(compiles, () @safe { return T.fromBson(Bson.init); } ()))
1760 				pragma(msg, "Non-@safe toBson/fromBson methods are deprecated - annotate "~T.stringof~".fromBson() with @safe.");
1761 			auto bval = readValue!(Traits, Bson);
1762 			return () @trusted { return T.fromBson(bval); } ();
1763 		} else static if (isJsonSerializable!T) {
1764 			static if (!__traits(compiles, () @safe { return T.fromJson(Json.init); } ()))
1765 				pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~T.stringof~".fromJson() with @safe.");
1766 			auto jval = readValue!(Traits, Bson).toJson();
1767 			return () @trusted { return T.fromJson(jval); } ();
1768 		} else static if (is(T : const(ubyte)[])) {
1769 			auto ret = m_inputData.get!BsonBinData.rawData;
1770 			static if (isStaticArray!T) return cast(T)ret[0 .. T.length];
1771 			else static if (is(T : immutable(ubyte)[])) return ret;
1772 			else return cast(T)ret.dup;
1773 		} else return m_inputData.get!T();
1774 	}
1775 
1776 	bool tryReadNull(Traits)()
1777 	{
1778 		if (m_inputData.type == Bson.Type.null_) return true;
1779 		return false;
1780 	}
1781 
1782 	private static Bson.Type getBsonTypeID(T, bool accept_ao = false)(auto ref T value)
1783 	@safe {
1784 		alias UT = Unqual!T;
1785 		Bson.Type tp;
1786 		static if (is(T == Bson)) tp = value.type;
1787 		else static if (is(UT == Json)) tp = jsonTypeToBsonType(value.type);
1788 		else static if (is(UT == typeof(null))) tp = Bson.Type.null_;
1789 		else static if (is(UT == string)) tp = Bson.Type..string;
1790 		else static if (is(UT == BsonBinData)) tp = Bson.Type.binData;
1791 		else static if (is(UT == BsonObjectID)) tp = Bson.Type.objectID;
1792 		else static if (is(UT == BsonDate)) tp = Bson.Type.date;
1793 		else static if (is(UT == SysTime)) tp = Bson.Type.date;
1794 		else static if (is(UT == BsonRegex)) tp = Bson.Type.regex;
1795 		else static if (is(UT == BsonTimestamp)) tp = Bson.Type.timestamp;
1796 		else static if (is(UT == bool)) tp = Bson.Type.bool_;
1797 		else static if (isIntegral!UT && is(UT : int)) tp = Bson.Type.int_;
1798 		else static if (isIntegral!UT && is(UT : long)) tp = Bson.Type.long_;
1799 		else static if (isFloatingPoint!UT && is(UT : double)) tp = Bson.Type.double_;
1800 		else static if (isBsonSerializable!UT) tp = value.toBson().type; // FIXME: this is highly inefficient
1801 		else static if (isJsonSerializable!UT) tp = jsonTypeToBsonType(value.toJson().type); // FIXME: this is highly inefficient
1802 		else static if (is(UT == UUID)) tp = Bson.Type.binData;
1803 		else static if (is(UT : const(ubyte)[])) tp = Bson.Type.binData;
1804 		else static if (accept_ao && isArray!UT) tp = Bson.Type.array;
1805 		else static if (accept_ao && isAssociativeArray!UT) tp = Bson.Type.object;
1806 		else static if (accept_ao && (is(UT == class) || is(UT == struct))) tp = Bson.Type.object;
1807 		else static assert(false, "Unsupported type: " ~ UT.stringof);
1808 		return tp;
1809 	}
1810 }
1811 
1812 private Bson.Type jsonTypeToBsonType(Json.Type tp)
1813 @safe {
1814 	static immutable Bson.Type[Json.Type.max+1] JsonIDToBsonID = [
1815 		Bson.Type.undefined,
1816 		Bson.Type.null_,
1817 		Bson.Type.bool_,
1818 		Bson.Type.long_,
1819 		Bson.Type.long_,
1820 		Bson.Type.double_,
1821 		Bson.Type..string,
1822 		Bson.Type.array,
1823 		Bson.Type.object
1824 	];
1825 	return JsonIDToBsonID[tp];
1826 }
1827 
1828 private Bson.Type writeBson(R)(ref R dst, in Json value)
1829 	if( isOutputRange!(R, ubyte) )
1830 {
1831 	final switch(value.type){
1832 		case Json.Type.undefined:
1833 			return Bson.Type.undefined;
1834 		case Json.Type.null_:
1835 			return Bson.Type.null_;
1836 		case Json.Type.bool_:
1837 			dst.put(cast(ubyte)(cast(bool)value ? 0x01 : 0x00));
1838 			return Bson.Type.bool_;
1839 		case Json.Type.int_:
1840 			dst.put(toBsonData(cast(long)value));
1841 			return Bson.Type.long_;
1842 		case Json.Type.bigInt:
1843 			dst.put(toBsonData(cast(long)value));
1844 			return Bson.Type.long_;
1845 		case Json.Type.float_:
1846 			dst.put(toBsonData(cast(double)value));
1847 			return Bson.Type.double_;
1848 		case Json.Type..string:
1849 			dst.put(toBsonData(cast(uint)value.length+1));
1850 			dst.put(cast(bdata_t)cast(string)value);
1851 			dst.put(cast(ubyte)0);
1852 			return Bson.Type..string;
1853 		case Json.Type.array:
1854 			auto app = appender!bdata_t();
1855 			foreach( size_t i, ref const Json v; value ){
1856 				app.put(cast(ubyte)(jsonTypeToBsonType(v.type)));
1857 				putCString(app, to!string(i));
1858 				writeBson(app, v);
1859 			}
1860 
1861 			dst.put(toBsonData(cast(int)(app.data.length + int.sizeof + 1)));
1862 			dst.put(app.data);
1863 			dst.put(cast(ubyte)0);
1864 			return Bson.Type.array;
1865 		case Json.Type.object:
1866 			auto app = appender!bdata_t();
1867 			foreach( string k, ref const Json v; value ){
1868 				app.put(cast(ubyte)(jsonTypeToBsonType(v.type)));
1869 				putCString(app, k);
1870 				writeBson(app, v);
1871 			}
1872 
1873 			dst.put(toBsonData(cast(int)(app.data.length + int.sizeof + 1)));
1874 			dst.put(app.data);
1875 			dst.put(cast(ubyte)0);
1876 			return Bson.Type.object;
1877 	}
1878 }
1879 
1880 unittest
1881 {
1882 	Json jsvalue = parseJsonString("{\"key\" : \"Value\"}");
1883 	assert(serializeToBson(jsvalue).toJson() == jsvalue);
1884 
1885 	jsvalue = parseJsonString("{\"key\" : [{\"key\" : \"Value\"}, {\"key2\" : \"Value2\"}] }");
1886 	assert(serializeToBson(jsvalue).toJson() == jsvalue);
1887 
1888 	jsvalue = parseJsonString("[ 1 , 2 , 3]");
1889 	assert(serializeToBson(jsvalue).toJson() == jsvalue);
1890 }
1891 
1892 unittest
1893 {
1894 	static struct Pipeline(ARGS...) { @asArray ARGS pipeline; }
1895 	auto getPipeline(ARGS...)(ARGS args) { return Pipeline!ARGS(args); }
1896 
1897 	string[string] a = ["foo":"bar"];
1898 	int b = 42;
1899 
1900 	auto fields = getPipeline(a, b).serializeToBson()["pipeline"].get!(Bson[]);
1901 	assert(fields[0]["foo"].get!string == "bar");
1902 	assert(fields[1].get!int == 42);
1903 }
1904 
1905 @safe unittest {
1906 	struct S {
1907 		immutable(ubyte)[][] arrays;
1908 	}
1909 
1910 	S s = S([[1, 2, 3], [4, 5, 6]]);
1911 	S t;
1912 	deserializeBson(t, serializeToBson(s));
1913 	assert(t == s);
1914 }
1915 
1916 private string skipCString(ref bdata_t data)
1917 @safe {
1918 	auto idx = data.countUntil(0);
1919 	enforce(idx >= 0, "Unterminated BSON C-string.");
1920 	auto ret = data[0 .. idx];
1921 	data = data[idx+1 .. $];
1922 	return cast(string)ret;
1923 }
1924 
1925 private void putCString(R)(ref R dst, string str)
1926 {
1927 	dst.put(cast(bdata_t)str);
1928 	dst.put(cast(ubyte)0);
1929 }
1930 
1931 ubyte[] toBsonData(T)(T v)
1932 {
1933 	/*static T tmp;
1934 	tmp = nativeToLittleEndian(v);
1935 	return cast(ubyte[])((&tmp)[0 .. 1]);*/
1936 	if (__ctfe) return nativeToLittleEndian(v).dup;
1937 	else {
1938 		static ubyte[T.sizeof] ret;
1939 		ret = nativeToLittleEndian(v);
1940 		return ret;
1941 	}
1942 }
1943 
1944 T fromBsonData(T)(in ubyte[] v)
1945 {
1946 	assert(v.length >= T.sizeof);
1947 	//return (cast(T[])v[0 .. T.sizeof])[0];
1948 	ubyte[T.sizeof] vu = v[0 .. T.sizeof];
1949 	return littleEndianToNative!T(vu);
1950 }
1951 
1952 ubyte[] toBigEndianData(T)(T v)
1953 {
1954 	if (__ctfe) return nativeToBigEndian(v).dup;
1955 	else {
1956 		static ubyte[T.sizeof] ret;
1957 		ret = nativeToBigEndian(v);
1958 		return ret;
1959 	}
1960 }
1961 
1962 private string underscoreStrip(string field_name)
1963 pure @safe {
1964 	if( field_name.length < 1 || field_name[$-1] != '_' ) return field_name;
1965 	else return field_name[0 .. $-1];
1966 }
1967 
1968 /// private
1969 package template isBsonSerializable(T) { enum isBsonSerializable = is(typeof(T.init.toBson()) : Bson) && is(typeof(T.fromBson(Bson())) : T); }