Skip to content

Commit 3e76aad

Browse files
committed
Upgrade chrono deps to v0.3 [#68], add UtcDateTime wrapper as serde serialization helper [#65]
1 parent ec68961 commit 3e76aad

File tree

6 files changed

+108
-11
lines changed

6 files changed

+108
-11
lines changed

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bson"
3-
version = "0.7.0"
3+
version = "0.7.1"
44
authors = [
55
"Y. T. Chung <[email protected]>",
66
"Kevin Yeh <[email protected]>"
@@ -16,7 +16,7 @@ name = "bson"
1616

1717
[dependencies]
1818
byteorder = "1.0"
19-
chrono = "0.2"
19+
chrono = "0.3"
2020
libc = "0.2"
2121
rand = "0.3"
2222
rust-crypto = "0.2"
@@ -26,3 +26,6 @@ time = "0.1"
2626
linked-hash-map = "0.3"
2727
hostname = "^0.1"
2828
hex = "^0.2"
29+
30+
[dev-dependencies]
31+
serde_derive = "1.0"

src/bson.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
//! BSON definition
2323
2424
use std::fmt::{self, Display, Debug};
25+
use std::ops::{Deref, DerefMut};
2526

2627
use chrono::{DateTime, Timelike, UTC};
2728
use chrono::offset::TimeZone;
@@ -429,7 +430,7 @@ impl Bson {
429430
Bson::UtcDatetime(ref v) => {
430431
doc! {
431432
"$date" => {
432-
"$numberLong" => ((v.timestamp() * 1000) + (v.nanosecond() / 1000000) as i64)
433+
"$numberLong" => ((v.timestamp() * 1000) + v.nanosecond() as i64 / 1000000)
433434
}
434435
}
435436
}
@@ -479,7 +480,7 @@ impl Bson {
479480
.get_document("$date")
480481
.and_then(|inner| inner.get_i64("$numberLong")) {
481482
return Bson::UtcDatetime(UTC.timestamp(long / 1000,
482-
(long % 1000) as u32 * 1000000));
483+
((long % 1000) * 1000000) as u32));
483484
} else if let Ok(sym) = values.get_str("$symbol") {
484485
return Bson::Symbol(sym.to_owned());
485486
}
@@ -587,3 +588,47 @@ impl Bson {
587588
}
588589
}
589590
}
591+
592+
/// `DateTime` representation in struct for serde serialization
593+
///
594+
/// Just a helper for convenience
595+
///
596+
/// ```rust,ignore
597+
/// #[macro_use]
598+
/// extern crate serde_derive;
599+
/// extern crate bson;
600+
/// use bson::UtcDateTime;
601+
///
602+
/// #[derive(Serialize, Deserialize)]
603+
/// struct Foo {
604+
/// date_time: UtcDateTime,
605+
/// }
606+
/// ```
607+
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
608+
pub struct UtcDateTime(pub DateTime<UTC>);
609+
610+
impl Deref for UtcDateTime {
611+
type Target = DateTime<UTC>;
612+
613+
fn deref(&self) -> &Self::Target {
614+
&self.0
615+
}
616+
}
617+
618+
impl DerefMut for UtcDateTime {
619+
fn deref_mut(&mut self) -> &mut DateTime<UTC> {
620+
&mut self.0
621+
}
622+
}
623+
624+
impl Into<DateTime<UTC>> for UtcDateTime {
625+
fn into(self) -> DateTime<UTC> {
626+
self.0
627+
}
628+
}
629+
630+
impl From<DateTime<UTC>> for UtcDateTime {
631+
fn from(x: DateTime<UTC>) -> Self {
632+
UtcDateTime(x)
633+
}
634+
}

src/decoder/serde.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess, SeqAccess,
55
DeserializeSeed, EnumAccess};
66
use serde::de::Unexpected;
77

8-
use bson::Bson;
8+
use bson::{Bson, UtcDateTime};
99
use oid::ObjectId;
1010
use ordered::{OrderedDocument, OrderedDocumentIntoIterator, OrderedDocumentVisitor};
1111
use super::error::{DecoderError, DecoderResult};
@@ -366,8 +366,7 @@ impl<'de> VariantAccess<'de> for VariantDecoder {
366366
match self.val.take() {
367367
None => Ok(()),
368368
Some(val) => {
369-
try!(Deserialize::deserialize(Decoder::new(val)));
370-
Ok(())
369+
Bson::deserialize(Decoder::new(val)).map(|_| ())
371370
}
372371
}
373372
}
@@ -570,3 +569,16 @@ impl<'de> Deserializer<'de> for MapDecoder {
570569
deserialize_byte_buf();
571570
}
572571
}
572+
573+
impl<'de> Deserialize<'de> for UtcDateTime {
574+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
575+
where D: Deserializer<'de>
576+
{
577+
use serde::de::Error;
578+
579+
match Bson::deserialize(deserializer)? {
580+
Bson::UtcDatetime(dt) => Ok(UtcDateTime(dt)),
581+
_ => Err(D::Error::custom("expecting UtcDateTime")),
582+
}
583+
}
584+
}

src/encoder/serde.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use serde::ser::{Serialize, Serializer, SerializeSeq, SerializeTuple, SerializeTupleStruct,
22
SerializeTupleVariant, SerializeMap, SerializeStruct, SerializeStructVariant};
33

4-
use bson::{Array, Bson, Document};
4+
use bson::{Array, Bson, Document, UtcDateTime};
55
use oid::ObjectId;
66

77
use super::{to_bson, EncoderError, EncoderResult};
@@ -434,3 +434,14 @@ impl SerializeStructVariant for StructVariantSerializer {
434434
Ok(Bson::Document(struct_variant))
435435
}
436436
}
437+
438+
impl Serialize for UtcDateTime {
439+
#[inline]
440+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
441+
where S: Serializer
442+
{
443+
// Cloning a `DateTime` is extremely cheap
444+
let doc = Bson::UtcDatetime(self.0);
445+
doc.serialize(serializer)
446+
}
447+
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ extern crate linked_hash_map;
5555
extern crate hostname;
5656
extern crate hex;
5757

58-
pub use self::bson::{Bson, Document, Array};
58+
pub use self::bson::{Bson, Document, Array, UtcDateTime};
5959
pub use self::encoder::{encode_document, to_bson, Encoder, EncoderResult, EncoderError};
6060
pub use self::decoder::{decode_document, from_bson, Decoder, DecoderResult, DecoderError};
6161
pub use self::ordered::{ValueAccessError, ValueAccessResult};

tests/serde.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
#[macro_use]
22
extern crate bson;
3-
use bson::{Encoder, Decoder};
4-
53
extern crate serde;
4+
#[macro_use]
5+
extern crate serde_derive;
6+
extern crate chrono;
7+
68
use serde::{Serialize, Deserialize};
9+
use bson::{Encoder, Decoder, Bson};
710

811
use std::collections::BTreeMap;
912

@@ -54,3 +57,26 @@ fn test_de_map() {
5457
expected.insert("y".to_string(), 1);
5558
assert_eq!(expected, map);
5659
}
60+
61+
#[test]
62+
fn test_ser_datetime() {
63+
use chrono::{UTC, Timelike};
64+
use bson::UtcDateTime;
65+
66+
#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
67+
struct Foo {
68+
date: UtcDateTime,
69+
}
70+
71+
let now = UTC::now();
72+
// FIXME: Due to BSON's datetime precision
73+
let now = now.with_nanosecond(now.nanosecond() / 1000000 * 1000000).unwrap();
74+
75+
let foo = Foo { date: From::from(now) };
76+
77+
let x = bson::to_bson(&foo).unwrap();
78+
assert_eq!(x.as_document().unwrap(), &doc! { "date" => (Bson::UtcDatetime(now)) });
79+
80+
let xfoo: Foo = bson::from_bson(x).unwrap();
81+
assert_eq!(xfoo, foo);
82+
}

0 commit comments

Comments
 (0)