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