Skip to content

Commit 4f2f585

Browse files
committed
BSON De/serialization
1 parent e7d4444 commit 4f2f585

File tree

5 files changed

+1040
-2
lines changed

5 files changed

+1040
-2
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,9 @@ libc = "0.1"
1717
rand = "0.3"
1818
rust-crypto = "0.2.31"
1919
rustc-serialize = "0.3"
20+
serde = "~0.6.1"
2021
time = "0.1"
22+
23+
[dependencies.num]
24+
version = "~0.1.27"
25+
default-features = false

src/bson.rs

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
2424
use std::fmt::{Display, Error, Formatter};
2525

26-
use chrono::{DateTime, UTC};
26+
use chrono::{DateTime, Timelike, UTC};
27+
use chrono::offset::TimeZone;
2728
use rustc_serialize::json;
28-
use rustc_serialize::hex::ToHex;
29+
use rustc_serialize::hex::{FromHex, ToHex};
2930

3031
use ordered::OrderedDocument;
3132
use spec::{ElementType, BinarySubtype};
@@ -290,4 +291,85 @@ impl Bson {
290291
&json::Json::Null => Bson::Null,
291292
}
292293
}
294+
295+
pub fn to_extended_document(&self) -> Document {
296+
match *self {
297+
Bson::RegExp(ref pat, ref opt) => {
298+
doc! {
299+
"$regex" => (pat.clone()),
300+
"$options" => (opt.clone())
301+
}
302+
}
303+
Bson::JavaScriptCode(ref code) => {
304+
doc! {
305+
"$code" => (code.clone())
306+
}
307+
}
308+
Bson::JavaScriptCodeWithScope(ref code, ref scope) => {
309+
doc! {
310+
"$code" => (code.clone()),
311+
"$scope" => (scope.clone())
312+
}
313+
}
314+
Bson::TimeStamp(v) => {
315+
// TODO
316+
doc! {
317+
//"$timestamp" => {
318+
// "t" => (v[0..4] as i32),
319+
//"i" => (v[4..8] as i32),
320+
"$timestamp" => v
321+
}
322+
}
323+
Bson::Binary(t, ref v) => {
324+
let tval: u8 = From::from(t);
325+
doc! {
326+
"$binary" => (v.to_hex()),
327+
"type" => (tval as i64)
328+
}
329+
}
330+
Bson::ObjectId(ref v) => {
331+
doc! {
332+
"$oid" => (v.to_string())
333+
}
334+
}
335+
Bson::UtcDatetime(ref v) => {
336+
doc! {
337+
"$date" => {
338+
"$numberLong" => ((v.timestamp() * 1000) + (v.nanosecond() / 1000000) as i64)
339+
}
340+
}
341+
}
342+
// TODO: Actual error
343+
_ => unreachable!()
344+
}
345+
}
346+
347+
pub fn from_extended_document(values: Document) -> Result<Bson, Error> {
348+
if let Some(&Bson::String(ref pat)) = values.get("$regex") {
349+
if let Some(&Bson::String(ref opt)) = values.get("$options") {
350+
return Ok(Bson::RegExp(pat.to_owned(), opt.to_owned()));
351+
}
352+
} else if let Some(&Bson::String(ref code)) = values.get("$code") {
353+
if let Some(&Bson::Document(ref scope)) = values.get("$sscope") {
354+
return Ok(Bson::JavaScriptCodeWithScope(code.to_owned(), scope.to_owned()));
355+
} else {
356+
return Ok(Bson::JavaScriptCode(code.to_owned()));
357+
}
358+
} else if values.contains_key("$timestamp") {
359+
// TODO
360+
} else if let Some(&Bson::String(ref hex)) = values.get("$binary") {
361+
if let Some(&Bson::I64(t)) = values.get("type") {
362+
let ttype = t as u8;
363+
return Ok(Bson::Binary(From::from(ttype), hex.from_hex().unwrap()));
364+
}
365+
} else if let Some(&Bson::String(ref hex)) = values.get("$oid") {
366+
return Ok(Bson::ObjectId(oid::ObjectId::with_string(hex).unwrap()));
367+
} else if let Some(&Bson::Document(ref doc)) = values.get("$date") {
368+
if let Some(&Bson::I64(long)) = doc.get("$numberLong") {
369+
return Ok(Bson::UtcDatetime(UTC.timestamp(long / 1000, (long % 1000) as u32 * 1000000)));
370+
}
371+
}
372+
373+
Ok(Bson::Document(values))
374+
}
293375
}

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,21 @@ extern crate crypto;
4848
extern crate libc;
4949
extern crate rand;
5050
extern crate rustc_serialize;
51+
extern crate serde;
5152
extern crate time;
5253

5354
pub use self::bson::{Bson, Document, Array};
5455
pub use self::encoder::{encode_document, EncoderResult, EncoderError};
5556
pub use self::decoder::{decode_document, DecoderResult, DecoderError};
5657
pub use self::ordered::{ValueAccessError, ValueAccessResult};
58+
pub use self::ser::{to_bson, from_bson};
5759

60+
#[macro_use]
5861
pub mod macros;
5962
pub mod oid;
6063
pub mod spec;
6164
mod bson;
6265
mod encoder;
6366
mod decoder;
6467
mod ordered;
68+
mod ser;

src/ordered.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use std::fmt::{Debug, Display, Error, Formatter};
99
use std::iter::{FromIterator, Map};
1010
use std::vec::IntoIter;
1111
use std::slice;
12+
use serde::ser::{Serialize, Serializer};
13+
use serde::ser::impls::MapIteratorVisitor;
1214

1315
/// Error to indicate that either a value was empty or it contained an unexpected
1416
/// type, for use with the direct getters.
@@ -365,3 +367,21 @@ impl OrderedDocument {
365367
self.document.remove(key)
366368
}
367369
}
370+
371+
impl Serialize for OrderedDocument {
372+
#[inline]
373+
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
374+
where S: Serializer,
375+
{
376+
serializer.visit_map(MapIteratorVisitor::new(self.iter(), Some(self.len())))
377+
}
378+
}
379+
380+
impl From<BTreeMap<String, Bson>> for OrderedDocument {
381+
fn from(tree: BTreeMap<String, Bson>) -> OrderedDocument {
382+
OrderedDocument {
383+
keys: tree.keys().cloned().collect(),
384+
document: tree,
385+
}
386+
}
387+
}

0 commit comments

Comments
 (0)