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