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