Skip to content

Commit 8a92a56

Browse files
committed
RUST-739 Eliminate public dependencies on unstable crates (C-STABLE)
1 parent 87b3358 commit 8a92a56

File tree

16 files changed

+176
-139
lines changed

16 files changed

+176
-139
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ uuid = "0.8.1"
5858
assert_matches = "1.2"
5959
serde_bytes = "0.11"
6060
pretty_assertions = "0.6.1"
61+
chrono = { version = "0.4", features = ["serde"] }
6162

6263
[package.metadata.docs.rs]
6364
features = ["decimal128"]

examples/serialize.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn main() {
88

99
let arr = vec![
1010
Bson::String("blah".to_string()),
11-
Bson::DateTime(chrono::Utc::now()),
11+
Bson::DateTime(chrono::Utc::now().into()),
1212
Bson::ObjectId(oid::ObjectId::from_bytes([
1313
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1414
])),

src/bson.rs

Lines changed: 60 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@
2121

2222
//! BSON definition
2323
24-
use std::{
25-
fmt::{self, Debug, Display},
26-
ops::{Deref, DerefMut},
27-
};
24+
use std::fmt::{self, Debug, Display};
2825

2926
use chrono::{Datelike, SecondsFormat, TimeZone, Utc};
3027
use serde_json::{json, Value};
@@ -68,7 +65,7 @@ pub enum Bson {
6865
/// [ObjectId](http://dochub.mongodb.org/core/objectids)
6966
ObjectId(oid::ObjectId),
7067
/// UTC datetime
71-
DateTime(chrono::DateTime<Utc>),
68+
DateTime(crate::DateTime),
7269
/// Symbol (Deprecated)
7370
Symbol(String),
7471
/// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst)
@@ -290,7 +287,7 @@ impl From<oid::ObjectId> for Bson {
290287

291288
impl From<chrono::DateTime<Utc>> for Bson {
292289
fn from(a: chrono::DateTime<Utc>) -> Bson {
293-
Bson::DateTime(a)
290+
Bson::DateTime(DateTime(a))
294291
}
295292
}
296293

@@ -373,15 +370,15 @@ impl Bson {
373370
})
374371
}
375372
Bson::ObjectId(v) => json!({"$oid": v.to_hex()}),
376-
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.year() <= 99999 => {
377-
let seconds_format = if v.timestamp_subsec_millis() == 0 {
373+
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.0.year() <= 99999 => {
374+
let seconds_format = if v.0.timestamp_subsec_millis() == 0 {
378375
SecondsFormat::Secs
379376
} else {
380377
SecondsFormat::Millis
381378
};
382379

383380
json!({
384-
"$date": v.to_rfc3339_opts(seconds_format, true),
381+
"$date": v.0.to_rfc3339_opts(seconds_format, true),
385382
})
386383
}
387384
Bson::DateTime(v) => json!({
@@ -539,15 +536,15 @@ impl Bson {
539536
"$oid": v.to_string(),
540537
}
541538
}
542-
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.year() <= 99999 => {
543-
let seconds_format = if v.timestamp_subsec_millis() == 0 {
539+
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.0.year() <= 99999 => {
540+
let seconds_format = if v.0.timestamp_subsec_millis() == 0 {
544541
SecondsFormat::Secs
545542
} else {
546543
SecondsFormat::Millis
547544
};
548545

549546
doc! {
550-
"$date": v.to_rfc3339_opts(seconds_format, true),
547+
"$date": v.0.to_rfc3339_opts(seconds_format, true),
551548
}
552549
}
553550
Bson::DateTime(v) => doc! {
@@ -738,12 +735,12 @@ impl Bson {
738735

739736
["$date"] => {
740737
if let Ok(date) = doc.get_i64("$date") {
741-
return Bson::DateTime(DateTime::from_i64(date).into());
738+
return Bson::DateTime(DateTime::from_millis(date));
742739
}
743740

744741
if let Ok(date) = doc.get_str("$date") {
745742
if let Ok(date) = chrono::DateTime::parse_from_rfc3339(date) {
746-
return Bson::DateTime(date.into());
743+
return Bson::DateTime(date.with_timezone(&Utc).into());
747744
}
748745
}
749746
}
@@ -888,7 +885,7 @@ impl Bson {
888885
}
889886

890887
/// If `Bson` is `DateTime`, return its value. Returns `None` otherwise
891-
pub fn as_datetime(&self) -> Option<&chrono::DateTime<Utc>> {
888+
pub fn as_datetime(&self) -> Option<&crate::DateTime> {
892889
match *self {
893890
Bson::DateTime(ref v) => Some(v),
894891
_ => None,
@@ -897,7 +894,7 @@ impl Bson {
897894

898895
/// If `Bson` is `DateTime`, return a mutable reference to its value. Returns `None`
899896
/// otherwise
900-
pub fn as_datetime_mut(&mut self) -> Option<&mut chrono::DateTime<Utc>> {
897+
pub fn as_datetime_mut(&mut self) -> Option<&mut crate::DateTime> {
901898
match *self {
902899
Bson::DateTime(ref mut v) => Some(v),
903900
_ => None,
@@ -973,76 +970,78 @@ impl Timestamp {
973970
}
974971
}
975972

976-
/// `DateTime` representation in struct for serde serialization
973+
/// Struct representing a BSON datetime.
974+
///
975+
/// Is is recommended to use a [`chrono::DateTime`] for date operations
976+
/// and to convert it to/from a [`crate::DateTime`] via the `From`/`Into` implementations.
977+
///
978+
/// ```
979+
/// use chrono::prelude::*;
980+
/// # fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
981+
/// let chrono_dt: chrono::DateTime<Utc> = "2014-11-28T12:00:09Z".parse()?;
982+
/// let bson_dt: bson::DateTime = chrono_dt.into();
983+
/// let back_to_chrono: chrono::DateTime<Utc> = bson_dt.into();
984+
/// # Ok(())
985+
/// # }
986+
/// ```
977987
///
978-
/// Just a helper for convenience
988+
/// This type differs from [`chrono::DateTime`] in that it serializes to and deserializes from a
989+
/// BSON datetime rather than an ISO-8601 formatted string. This means that in non-BSON formats, it
990+
/// will serialize to and deserialize from that format's equivalent of the [extended JSON representation](https://docs.mongodb.com/manual/reference/mongodb-extended-json/) of a datetime. To serialize a
991+
/// [`chrono::DateTime`] as a BSON datetime, you can use
992+
/// [`serde_helpers::chrono_0_4_datetime_as_bson_datetime`].
979993
///
980994
/// ```rust
981995
/// use serde::{Serialize, Deserialize};
982-
/// use bson::DateTime;
983996
///
984997
/// #[derive(Serialize, Deserialize)]
985998
/// struct Foo {
986-
/// date_time: DateTime,
999+
/// // serializes as a BSON datetime.
1000+
/// date_time: bson::DateTime,
1001+
///
1002+
/// // serializes as an ISO-8601 string.
1003+
/// chrono_datetime: chrono::DateTime<chrono::Utc>,
1004+
///
1005+
/// // serializes as a BSON datetime.
1006+
/// #[serde(with = "bson::serde_helpers::chrono_0_4_datetime_as_bson_datetime")]
1007+
/// chrono_as_bson: chrono::DateTime<chrono::Utc>,
9871008
/// }
9881009
/// ```
9891010
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
990-
pub struct DateTime(pub chrono::DateTime<Utc>);
991-
992-
impl DateTime {
993-
pub(crate) fn from_i64(date: i64) -> Self {
994-
let mut num_secs = date / 1000;
995-
let mut num_millis = date % 1000;
996-
997-
// The chrono API only lets us create a DateTime with an i64 number of seconds
998-
// and a u32 number of nanoseconds. In the case of a negative timestamp, this
999-
// means that we need to turn the negative fractional part into a positive and
1000-
// shift the number of seconds down. For example:
1001-
//
1002-
// date = -4300 ms
1003-
// num_secs = date / 1000 = -4300 / 1000 = -4
1004-
// num_millis = date % 1000 = -4300 % 1000 = -300
1005-
//
1006-
// Since num_millis is less than 0:
1007-
// num_secs = num_secs -1 = -4 - 1 = -5
1008-
// num_millis = num_nanos + 1000 = -300 + 1000 = 700
1009-
//
1010-
// Instead of -4 seconds and -300 milliseconds, we now have -5 seconds and +700
1011-
// milliseconds, which expresses the same timestamp, but in a way we can create
1012-
// a DateTime with.
1013-
if num_millis < 0 {
1014-
num_secs -= 1;
1015-
num_millis += 1000;
1016-
};
1011+
pub struct DateTime(chrono::DateTime<Utc>);
10171012

1018-
Utc.timestamp(num_secs, num_millis as u32 * 1_000_000)
1019-
.into()
1013+
impl crate::DateTime {
1014+
pub(crate) fn from_millis(date: i64) -> Self {
1015+
Utc.timestamp_millis(date).into()
10201016
}
1021-
}
10221017

1023-
impl Deref for DateTime {
1024-
type Target = chrono::DateTime<Utc>;
1018+
/// Returns the number of non-leap-milliseconds since January 1, 1970 UTC.
1019+
pub fn timestamp_millis(&self) -> i64 {
1020+
self.0.timestamp_millis()
1021+
}
10251022

1026-
fn deref(&self) -> &Self::Target {
1027-
&self.0
1023+
/// If this DateTime is sub-millisecond precision. BSON only supports millisecond precision, so
1024+
/// this should be checked before serializing to BSON.
1025+
pub(crate) fn is_sub_millis_precision(&self) -> bool {
1026+
self.0.timestamp_subsec_micros() % 1000 != 0
10281027
}
10291028
}
10301029

1031-
impl DerefMut for DateTime {
1032-
fn deref_mut(&mut self) -> &mut chrono::DateTime<Utc> {
1033-
&mut self.0
1030+
impl Display for crate::DateTime {
1031+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1032+
Display::fmt(&self.0, f)
10341033
}
10351034
}
10361035

1037-
impl From<DateTime> for chrono::DateTime<Utc> {
1036+
impl From<crate::DateTime> for chrono::DateTime<Utc> {
10381037
fn from(utc: DateTime) -> Self {
10391038
utc.0
10401039
}
10411040
}
10421041

1043-
impl From<chrono::DateTime<Utc>> for DateTime {
1044-
fn from(x: chrono::DateTime<Utc>) -> Self {
1045-
DateTime(x)
1042+
impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for crate::DateTime {
1043+
fn from(x: chrono::DateTime<T>) -> Self {
1044+
DateTime(x.with_timezone(&Utc))
10461045
}
10471046
}
10481047

src/de/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ pub(crate) fn deserialize_bson_kvp<R: Read + ?Sized>(
327327
let time = read_i64(reader)?;
328328

329329
match Utc.timestamp_millis_opt(time) {
330-
LocalResult::Single(t) => Bson::DateTime(t),
330+
LocalResult::Single(t) => Bson::DateTime(t.into()),
331331
_ => {
332332
return Err(Error::InvalidDateTime {
333333
key,

src/de/serde.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ impl<'de> Deserialize<'de> for DateTime {
762762
D: de::Deserializer<'de>,
763763
{
764764
match Bson::deserialize(deserializer)? {
765-
Bson::DateTime(dt) => Ok(DateTime(dt)),
765+
Bson::DateTime(dt) => Ok(dt),
766766
_ => Err(D::Error::custom("expecting DateTime")),
767767
}
768768
}

src/document.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use std::{
1010
};
1111

1212
use ahash::RandomState;
13-
use chrono::{DateTime, Utc};
1413
use indexmap::IndexMap;
1514
use serde::de::{self, Error, MapAccess, Visitor};
1615

@@ -438,7 +437,7 @@ impl Document {
438437
}
439438

440439
/// Get a reference to a UTC datetime value for this key if it exists and has the correct type.
441-
pub fn get_datetime(&self, key: impl AsRef<str>) -> ValueAccessResult<&DateTime<Utc>> {
440+
pub fn get_datetime(&self, key: impl AsRef<str>) -> ValueAccessResult<&crate::DateTime> {
442441
match self.get(key) {
443442
Some(&Bson::DateTime(ref v)) => Ok(v),
444443
Some(_) => Err(ValueAccessError::UnexpectedType),
@@ -451,7 +450,7 @@ impl Document {
451450
pub fn get_datetime_mut(
452451
&mut self,
453452
key: impl AsRef<str>,
454-
) -> ValueAccessResult<&mut DateTime<Utc>> {
453+
) -> ValueAccessResult<&mut crate::DateTime> {
455454
match self.get_mut(key) {
456455
Some(&mut Bson::DateTime(ref mut v)) => Ok(v),
457456
Some(_) => Err(ValueAccessError::UnexpectedType),

src/extjson/de.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
141141

142142
if obj.contains_key("$date") {
143143
let extjson_datetime: models::DateTime = serde_json::from_value(obj.into())?;
144-
return Ok(Bson::DateTime(extjson_datetime.parse()?.0));
144+
return Ok(Bson::DateTime(extjson_datetime.parse()?));
145145
}
146146

147147
if obj.contains_key("$minKey") {

src/extjson/models.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ impl DateTime {
241241
match self.body {
242242
DateTimeBody::Canonical(date) => {
243243
let date = date.parse()?;
244-
Ok(crate::DateTime::from_i64(date))
244+
Ok(crate::DateTime::from_millis(date))
245245
}
246246
DateTimeBody::Relaxed(date) => {
247247
let datetime: chrono::DateTime<Utc> =

0 commit comments

Comments
 (0)