Skip to content

Commit 6380979

Browse files
datetime and oid
1 parent 8389d37 commit 6380979

File tree

10 files changed

+93
-152
lines changed

10 files changed

+93
-152
lines changed

src/datetime.rs

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
//! Module containing functionality related to BSON DateTimes.
22
//! For more information, see the documentation for the [`DateTime`] type.
3+
pub(crate) mod builder;
34

45
use std::{
56
convert::TryInto,
6-
error,
77
fmt::{self, Display},
8-
result,
98
time::{Duration, SystemTime},
109
};
1110

12-
pub(crate) mod builder;
13-
pub use crate::datetime::builder::DateTimeBuilder;
14-
use time::format_description::well_known::Rfc3339;
15-
1611
#[cfg(feature = "chrono-0_4")]
1712
use chrono::{LocalResult, TimeZone, Utc};
1813
#[cfg(all(
1914
feature = "serde_with-3",
2015
any(feature = "chrono-0_4", feature = "time-0_3")
2116
))]
2217
use serde::{Deserialize, Deserializer, Serialize};
18+
use time::format_description::well_known::Rfc3339;
19+
20+
pub use crate::datetime::builder::DateTimeBuilder;
21+
use crate::error::{Error, Result};
2322

2423
/// Struct representing a BSON datetime.
2524
/// Note: BSON datetimes have millisecond precision.
@@ -390,19 +389,14 @@ impl crate::DateTime {
390389
pub fn try_to_rfc3339_string(self) -> Result<String> {
391390
self.to_time_0_3()
392391
.format(&Rfc3339)
393-
.map_err(|e| Error::CannotFormat {
394-
message: e.to_string(),
395-
})
392+
.map_err(Error::bad_conversion)
396393
}
397394

398395
/// Convert the given RFC 3339 formatted string to a [`DateTime`], truncating it to millisecond
399396
/// precision.
400397
pub fn parse_rfc3339_str(s: impl AsRef<str>) -> Result<Self> {
401-
let odt = time::OffsetDateTime::parse(s.as_ref(), &Rfc3339).map_err(|e| {
402-
Error::InvalidTimestamp {
403-
message: e.to_string(),
404-
}
405-
})?;
398+
let odt =
399+
time::OffsetDateTime::parse(s.as_ref(), &Rfc3339).map_err(Error::invalid_value)?;
406400
Ok(Self::from_time_0_3(odt))
407401
}
408402

@@ -547,30 +541,3 @@ impl serde_with::SerializeAs<time::OffsetDateTime> for crate::DateTime {
547541
dt.serialize(serializer)
548542
}
549543
}
550-
551-
/// Errors that can occur during [`DateTime`] construction and generation.
552-
#[derive(Clone, Debug)]
553-
#[non_exhaustive]
554-
pub enum Error {
555-
/// Error returned when an invalid datetime format is provided to a conversion method.
556-
#[non_exhaustive]
557-
InvalidTimestamp { message: String },
558-
/// Error returned when a [`DateTime`] cannot be represented in a particular format.
559-
#[non_exhaustive]
560-
CannotFormat { message: String },
561-
}
562-
563-
/// Alias for `Result<T, DateTime::Error>`
564-
pub type Result<T> = result::Result<T, Error>;
565-
566-
impl fmt::Display for Error {
567-
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
568-
match self {
569-
Error::InvalidTimestamp { message } | Error::CannotFormat { message } => {
570-
write!(fmt, "{}", message)
571-
}
572-
}
573-
}
574-
}
575-
576-
impl error::Error for Error {}

src/datetime/builder.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
use super::*;
21
use std::convert::TryFrom;
2+
33
use time::Date;
44

5+
use crate::{
6+
datetime::DateTime,
7+
error::{Error, Result},
8+
};
9+
510
/// Builder for constructing a BSON [`DateTime`]
611
pub struct DateTimeBuilder<Y = NoYear, M = NoMonth, D = NoDay> {
712
pub(crate) year: Y,
@@ -169,19 +174,16 @@ impl DateTimeBuilder<Year, Month, Day> {
169174
///
170175
/// Note: You cannot call `build()` before setting at least the year, month and day.
171176
pub fn build(self) -> Result<DateTime> {
172-
let err = |e: time::error::ComponentRange| Error::InvalidTimestamp {
173-
message: e.to_string(),
174-
};
175-
let month = time::Month::try_from(self.month.0).map_err(err)?;
177+
let month = time::Month::try_from(self.month.0).map_err(Error::invalid_value)?;
176178
let dt = Date::from_calendar_date(self.year.0, month, self.day.0)
177-
.map_err(err)?
179+
.map_err(Error::invalid_value)?
178180
.with_hms_milli(
179181
self.hour.unwrap_or(0),
180182
self.minute.unwrap_or(0),
181183
self.second.unwrap_or(0),
182184
self.millisecond.unwrap_or(0),
183185
)
184-
.map_err(err)?;
186+
.map_err(Error::invalid_value)?;
185187
Ok(DateTime::from_time_private(dt.assume_utc()))
186188
}
187189
}

src/error.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::spec::ElementType;
55
pub type Result<T> = std::result::Result<T, Error>;
66

77
/// An error that can occur in the `bson` crate.
8-
#[derive(Debug, Error)]
8+
#[derive(Clone, Debug, Error)]
99
#[non_exhaustive]
1010
pub struct Error {
1111
/// The kind of error that occurred.
@@ -31,13 +31,22 @@ impl std::fmt::Display for Error {
3131
}
3232

3333
/// The types of errors that can occur in the `bson` crate.
34-
#[derive(Debug, Error)]
34+
#[derive(Clone, Debug, Error)]
3535
#[non_exhaustive]
3636
pub enum ErrorKind {
37+
/// An error occurred when converting a BSON type to an external format.
38+
#[error("Bad conversion: {message}")]
39+
BadConversion { message: String },
40+
41+
/// An error occurred when attempting to parse a value from an external format to BSON.
42+
#[error("Invalid value: {message}")]
43+
#[non_exhaustive]
44+
InvalidValue { message: String },
45+
3746
/// Malformed BSON bytes were encountered.
3847
#[error("Malformed BSON: {message}")]
3948
#[non_exhaustive]
40-
MalformedValue { message: String },
49+
MalformedBytes { message: String },
4150

4251
/// Invalid UTF-8 bytes were encountered.
4352
#[error("Invalid UTF-8")]
@@ -78,7 +87,7 @@ impl From<crate::de::Error> for Error {
7887
}
7988

8089
/// The types of errors that can occur when attempting to access a value in a document.
81-
#[derive(Debug, Error)]
90+
#[derive(Clone, Debug, Error)]
8291
#[non_exhaustive]
8392
pub enum ValueAccessErrorKind {
8493
/// No value for the specified key was present in the document.
@@ -134,8 +143,22 @@ impl Error {
134143
.into()
135144
}
136145

137-
pub(crate) fn malformed_value(message: impl ToString) -> Self {
138-
ErrorKind::MalformedValue {
146+
pub(crate) fn malformed_bytes(message: impl ToString) -> Self {
147+
ErrorKind::MalformedBytes {
148+
message: message.to_string(),
149+
}
150+
.into()
151+
}
152+
153+
pub(crate) fn invalid_value(message: impl ToString) -> Self {
154+
ErrorKind::InvalidValue {
155+
message: message.to_string(),
156+
}
157+
.into()
158+
}
159+
160+
pub(crate) fn bad_conversion(message: impl ToString) -> Self {
161+
ErrorKind::BadConversion {
139162
message: message.to_string(),
140163
}
141164
.into()

src/extjson/de.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ use std::convert::{TryFrom, TryInto};
2525

2626
use serde::de::{Error as _, Unexpected};
2727

28-
use crate::{extjson::models, oid, Bson, Document};
28+
use crate::{extjson::models, Bson, Document};
2929

3030
#[derive(Clone, Debug)]
3131
#[non_exhaustive]
3232
/// Error cases that can occur during deserialization from [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
3333
pub enum Error {
3434
/// Errors that can occur during OID construction and generation from the input data.
35-
InvalidObjectId(oid::Error),
35+
InvalidObjectId(crate::error::Error),
3636

3737
/// A general error encountered during deserialization.
3838
/// See: <https://docs.serde.rs/serde/de/trait.Error.html>
@@ -69,12 +69,6 @@ impl From<serde_json::Error> for Error {
6969
}
7070
}
7171

72-
impl From<oid::Error> for Error {
73-
fn from(err: oid::Error) -> Self {
74-
Self::InvalidObjectId(err)
75-
}
76-
}
77-
7872
pub type Result<T> = std::result::Result<T, Error>;
7973

8074
/// This converts from the input JSON object as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).

src/extjson/models.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ pub(crate) struct ObjectId {
100100

101101
impl ObjectId {
102102
pub(crate) fn parse(self) -> extjson::de::Result<oid::ObjectId> {
103-
let oid = oid::ObjectId::parse_str(self.oid.as_str())?;
103+
let oid = oid::ObjectId::parse_str(self.oid.as_str())
104+
.map_err(extjson::de::Error::InvalidObjectId)?;
104105
Ok(oid)
105106
}
106107
}

src/oid.rs

Lines changed: 17 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
//! Module containing functionality related to BSON ObjectIds.
22
//! For more information, see the documentation for the [`ObjectId`] type.
33
4+
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
5+
use std::{convert::TryInto, time::SystemTime};
46
use std::{
5-
error,
67
fmt,
7-
result,
88
str::FromStr,
99
sync::atomic::{AtomicUsize, Ordering},
1010
};
1111

12-
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
13-
use std::{convert::TryInto, time::SystemTime};
14-
1512
use hex::{self, FromHexError};
1613
use once_cell::sync::Lazy;
1714
use rand::{random, rng, Rng};
1815

16+
use crate::error::{Error, Result};
17+
1918
const TIMESTAMP_SIZE: usize = 4;
2019
const PROCESS_ID_SIZE: usize = 5;
2120
const COUNTER_SIZE: usize = 3;
@@ -29,49 +28,6 @@ const MAX_U24: usize = 0xFF_FFFF;
2928
static OID_COUNTER: Lazy<AtomicUsize> =
3029
Lazy::new(|| AtomicUsize::new(rng().random_range(0..=MAX_U24)));
3130

32-
/// Errors that can occur during [`ObjectId`] construction and generation.
33-
#[derive(Clone, Debug)]
34-
#[non_exhaustive]
35-
pub enum Error {
36-
/// An invalid character was found in the provided hex string. Valid characters are: `0...9`,
37-
/// `a...f`, or `A...F`.
38-
#[non_exhaustive]
39-
InvalidHexStringCharacter { c: char, index: usize, hex: String },
40-
41-
/// An [`ObjectId`]'s hex string representation must be an exactly 12-byte (24-char)
42-
/// hexadecimal string.
43-
#[non_exhaustive]
44-
InvalidHexStringLength { length: usize, hex: String },
45-
}
46-
47-
/// Alias for Result<T, oid::Error>.
48-
pub type Result<T> = result::Result<T, Error>;
49-
50-
impl fmt::Display for Error {
51-
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
52-
match self {
53-
Error::InvalidHexStringCharacter { c, index, hex } => {
54-
write!(
55-
fmt,
56-
"invalid character '{}' was found at index {} in the provided hex string: \
57-
\"{}\"",
58-
c, index, hex
59-
)
60-
}
61-
Error::InvalidHexStringLength { length, hex } => {
62-
write!(
63-
fmt,
64-
"provided hex string representation must be exactly 12 bytes, instead got: \
65-
\"{}\", length {}",
66-
hex, length
67-
)
68-
}
69-
}
70-
}
71-
}
72-
73-
impl error::Error for Error {}
74-
7531
/// A wrapper around a raw 12-byte ObjectId.
7632
///
7733
/// ## `serde` integration
@@ -198,24 +154,22 @@ impl ObjectId {
198154
pub fn parse_str(s: impl AsRef<str>) -> Result<ObjectId> {
199155
let s = s.as_ref();
200156

201-
let bytes: Vec<u8> = hex::decode(s.as_bytes()).map_err(|e| match e {
202-
FromHexError::InvalidHexCharacter { c, index } => Error::InvalidHexStringCharacter {
203-
c,
204-
index,
205-
hex: s.to_string(),
206-
},
207-
FromHexError::InvalidStringLength | FromHexError::OddLength => {
208-
Error::InvalidHexStringLength {
209-
length: s.len(),
210-
hex: s.to_string(),
157+
let bytes: Vec<u8> = hex::decode(s.as_bytes()).map_err(|e| {
158+
let message = match e {
159+
FromHexError::InvalidHexCharacter { c, index } => {
160+
format!("invalid hex character {c} encountered at index {index}")
161+
}
162+
FromHexError::InvalidStringLength | FromHexError::OddLength => {
163+
format!("invalid hex string length {}", s.len())
211164
}
212-
}
165+
};
166+
Error::invalid_value(message)
213167
})?;
214168
if bytes.len() != 12 {
215-
Err(Error::InvalidHexStringLength {
216-
length: s.len(),
217-
hex: s.to_string(),
218-
})
169+
Err(Error::invalid_value(format!(
170+
"invalid object ID byte vector length {}",
171+
bytes.len()
172+
)))
219173
} else {
220174
let mut byte_array: [u8; 12] = [0; 12];
221175
byte_array[..].copy_from_slice(&bytes[..]);

0 commit comments

Comments
 (0)