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