diff --git a/src/bson.rs b/src/bson.rs index 8f35899d..ab778734 100644 --- a/src/bson.rs +++ b/src/bson.rs @@ -911,6 +911,36 @@ impl Bson { .collect(), ) } + + /// Method for converting a given [`Bson`] value to a [`serde::de::Unexpected`] for error + /// reporting. + #[cfg(feature = "serde")] + pub(crate) fn as_unexpected(&self) -> serde::de::Unexpected { + use serde::de::Unexpected; + match self { + Bson::Array(_) => Unexpected::Seq, + Bson::Binary(b) => Unexpected::Bytes(b.bytes.as_slice()), + Bson::Boolean(b) => Unexpected::Bool(*b), + Bson::DbPointer(_) => Unexpected::Other("dbpointer"), + Bson::Document(_) => Unexpected::Map, + Bson::Double(f) => Unexpected::Float(*f), + Bson::Int32(i) => Unexpected::Signed(*i as i64), + Bson::Int64(i) => Unexpected::Signed(*i), + Bson::JavaScriptCode(_) => Unexpected::Other("javascript code"), + Bson::JavaScriptCodeWithScope(_) => Unexpected::Other("javascript code with scope"), + Bson::MaxKey => Unexpected::Other("maxkey"), + Bson::MinKey => Unexpected::Other("minkey"), + Bson::Null => Unexpected::Unit, + Bson::Undefined => Unexpected::Other("undefined"), + Bson::ObjectId(_) => Unexpected::Other("objectid"), + Bson::RegularExpression(_) => Unexpected::Other("regex"), + Bson::String(s) => Unexpected::Str(s.as_str()), + Bson::Symbol(_) => Unexpected::Other("symbol"), + Bson::Timestamp(_) => Unexpected::Other("timestamp"), + Bson::DateTime(_) => Unexpected::Other("datetime"), + Bson::Decimal128(_) => Unexpected::Other("decimal128"), + } + } } /// Value helpers diff --git a/src/datetime.rs b/src/datetime.rs index e87e342b..6ed887f1 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -70,7 +70,7 @@ use crate::error::{Error, Result}; /// chrono_datetime: chrono::DateTime, /// } /// -/// # fn main() -> bson::ser::Result<()> { +/// # fn main() -> bson::error::Result<()> { /// let f = Foo { date_time: bson::DateTime::now(), chrono_datetime: chrono::Utc::now() }; /// println!("{:?}", bson::serialize_to_document(&f)?); /// # Ok(()) diff --git a/src/de.rs b/src/de.rs index 76a9bcda..969e6a50 100644 --- a/src/de.rs +++ b/src/de.rs @@ -21,19 +21,16 @@ //! Deserializer -mod error; mod raw; mod serde; -pub use self::{ - error::{Error, Result}, - serde::Deserializer, -}; +pub use self::serde::Deserializer; use std::io::Read; use crate::{ bson::{Bson, Document}, + error::{Error, Result}, raw::reader_to_vec, spec::BinarySubtype, }; diff --git a/src/de/error.rs b/src/de/error.rs deleted file mode 100644 index 1d6eed0d..00000000 --- a/src/de/error.rs +++ /dev/null @@ -1,152 +0,0 @@ -use std::{error, fmt, fmt::Display, io, string, sync::Arc}; - -use serde::de::{self, Unexpected}; - -use crate::Bson; - -/// Possible errors that can arise during decoding. -#[derive(Clone, Debug)] -#[non_exhaustive] -pub enum Error { - /// A [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) encountered while deserializing. - Io(Arc), - - /// A [`std::string::FromUtf8Error`](https://doc.rust-lang.org/std/string/struct.FromUtf8Error.html) encountered - /// while decoding a UTF-8 String from the input data. - InvalidUtf8String(string::FromUtf8Error), - - /// While decoding a [`Document`](crate::Document) from bytes, an unexpected or unsupported - /// element type was encountered. - #[non_exhaustive] - UnrecognizedDocumentElementType { - /// The key at which an unexpected/unsupported element type was encountered. - key: String, - - /// The encountered element type. - element_type: u8, - }, - - /// The end of the BSON input was reached too soon. - EndOfStream, - - /// A general error encountered during deserialization. - /// See: - #[non_exhaustive] - DeserializationError { - /// A message describing the error. - message: String, - }, - - #[cfg(feature = "serde_path_to_error")] - #[cfg_attr(docsrs, doc(cfg(feature = "serde_path_to_error")))] - #[non_exhaustive] - WithPath { - /// The path to the error. - path: serde_path_to_error::Path, - - /// The original error. - source: Box, - }, -} - -impl Error { - pub(crate) fn deserialization(msg: impl ToString) -> Self { - Self::DeserializationError { - message: msg.to_string(), - } - } - - #[cfg(feature = "serde_path_to_error")] - pub(crate) fn with_path(err: serde_path_to_error::Error) -> Self { - let path = err.path().clone(); - let source = Box::new(err.into_inner()); - Self::WithPath { path, source } - } -} - -impl From for Error { - fn from(err: io::Error) -> Error { - Error::Io(Arc::new(err)) - } -} - -impl From for Error { - fn from(err: string::FromUtf8Error) -> Error { - Error::InvalidUtf8String(err) - } -} - -impl From for Error { - fn from(error: crate::error::Error) -> Self { - Self::deserialization(error.to_string()) - } -} - -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::Io(inner) => inner.fmt(fmt), - Error::InvalidUtf8String(inner) => inner.fmt(fmt), - Error::UnrecognizedDocumentElementType { key, element_type } => write!( - fmt, - "unrecognized element type for key \"{}\": `{:#x}`", - key, element_type - ), - Error::EndOfStream => fmt.write_str("end of stream"), - Error::DeserializationError { message } => message.fmt(fmt), - #[cfg(feature = "serde_path_to_error")] - Error::WithPath { path, source } => write!(fmt, "error at {}: {}", path, source), - } - } -} - -impl error::Error for Error { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - Error::Io(ref inner) => Some(inner.as_ref()), - Error::InvalidUtf8String(ref inner) => Some(inner), - _ => None, - } - } -} - -impl de::Error for Error { - fn custom(msg: T) -> Error { - Error::DeserializationError { - message: msg.to_string(), - } - } -} - -/// Alias for `Result`. -pub type Result = std::result::Result; - -impl Bson { - /// Method for converting a given [`Bson`] value to a [`serde::de::Unexpected`] for error - /// reporting. - pub(crate) fn as_unexpected(&self) -> Unexpected { - match self { - Bson::Array(_) => Unexpected::Seq, - Bson::Binary(b) => Unexpected::Bytes(b.bytes.as_slice()), - Bson::Boolean(b) => Unexpected::Bool(*b), - Bson::DbPointer(_) => Unexpected::Other("dbpointer"), - Bson::Document(_) => Unexpected::Map, - Bson::Double(f) => Unexpected::Float(*f), - Bson::Int32(i) => Unexpected::Signed(*i as i64), - Bson::Int64(i) => Unexpected::Signed(*i), - Bson::JavaScriptCode(_) => Unexpected::Other("javascript code"), - Bson::JavaScriptCodeWithScope(_) => Unexpected::Other("javascript code with scope"), - Bson::MaxKey => Unexpected::Other("maxkey"), - Bson::MinKey => Unexpected::Other("minkey"), - Bson::Null => Unexpected::Unit, - Bson::Undefined => Unexpected::Other("undefined"), - Bson::ObjectId(_) => Unexpected::Other("objectid"), - Bson::RegularExpression(_) => Unexpected::Other("regex"), - Bson::String(s) => Unexpected::Str(s.as_str()), - Bson::Symbol(_) => Unexpected::Other("symbol"), - Bson::Timestamp(_) => Unexpected::Other("timestamp"), - Bson::DateTime(_) => Unexpected::Other("datetime"), - Bson::Decimal128(_) => Unexpected::Other("decimal128"), - } - } -} diff --git a/src/de/raw.rs b/src/de/raw.rs index 4f809df1..1739cbc1 100644 --- a/src/de/raw.rs +++ b/src/de/raw.rs @@ -61,7 +61,7 @@ impl<'de> Deserializer<'de> { } fn value(&self) -> Result> { - Ok(self.element.value()?) + self.element.value() } /// Deserialize the element, using the type of the element along with the @@ -419,7 +419,7 @@ impl<'de> serde::de::EnumAccess<'de> for DocumentAccess<'de> { self.advance()?; let elem = match &self.elem { Some(e) => e, - None => return Err(Error::EndOfStream), + None => return Err(Error::end_of_stream()), }; let de: BorrowedStrDeserializer<'_, Error> = BorrowedStrDeserializer::new(elem.key()); let key = seed.deserialize(de)?; @@ -1077,7 +1077,7 @@ impl<'de> serde::de::MapAccess<'de> for CodeWithScopeAccess<'de> { self.stage = match self.stage { CodeWithScopeDeserializationStage::Code => CodeWithScopeDeserializationStage::Scope, CodeWithScopeDeserializationStage::Scope => CodeWithScopeDeserializationStage::Done, - CodeWithScopeDeserializationStage::Done => return Err(Error::EndOfStream), + CodeWithScopeDeserializationStage::Done => return Err(Error::end_of_stream()), }; Ok(value) } @@ -1105,7 +1105,7 @@ impl<'de> serde::de::Deserializer<'de> for &CodeWithScopeAccess<'de> { _ => visitor.visit_map(DocumentAccess::new(scope, self.options.clone())?), } } - CodeWithScopeDeserializationStage::Done => Err(Error::EndOfStream), + CodeWithScopeDeserializationStage::Done => Err(Error::end_of_stream()), } } diff --git a/src/de/serde.rs b/src/de/serde.rs index bba415a4..88f3769c 100644 --- a/src/de/serde.rs +++ b/src/de/serde.rs @@ -11,7 +11,7 @@ use serde::de::{ DeserializeSeed, Deserializer as _, EnumAccess, - Error, + Error as _, MapAccess, SeqAccess, Unexpected, @@ -24,6 +24,7 @@ use crate::{ bson::{Bson, DbPointer, JavaScriptCodeWithScope, Regex, Timestamp}, datetime::DateTime, document::{Document, IntoIter}, + error::{Error, Result}, oid::ObjectId, raw::{RawBsonRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, serde_helpers::HUMAN_READABLE_NEWTYPE, @@ -71,7 +72,7 @@ impl<'de> Visitor<'de> for ObjectIdVisitor { } #[inline] - fn visit_map(self, mut visitor: V) -> Result + fn visit_map(self, mut visitor: V) -> std::result::Result where V: MapAccess<'de>, { @@ -82,7 +83,7 @@ impl<'de> Visitor<'de> for ObjectIdVisitor { "expected map containing extended-JSON formatted ObjectId, instead found {}", bson ); - Err(de::Error::custom(err)) + Err(serde::de::Error::custom(err)) } } } @@ -103,7 +104,7 @@ impl<'de> Deserialize<'de> for ObjectId { impl<'de> Deserialize<'de> for Document { /// Deserialize this value given this [`Deserializer`]. - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { @@ -112,7 +113,7 @@ impl<'de> Deserialize<'de> for Document { Ok(doc) } else { let err = format!("expected document, found extended JSON data type: {}", bson); - Err(de::Error::invalid_type(Unexpected::Map, &&err[..])) + Err(serde::de::Error::invalid_type(Unexpected::Map, &&err[..])) } }) } @@ -120,7 +121,7 @@ impl<'de> Deserialize<'de> for Document { impl<'de> Deserialize<'de> for Bson { #[inline] - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { @@ -136,102 +137,102 @@ impl<'de> Visitor<'de> for BsonVisitor { } #[inline] - fn visit_bool(self, value: bool) -> Result + fn visit_bool(self, value: bool) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(Bson::Boolean(value)) } #[inline] - fn visit_i8(self, value: i8) -> Result + fn visit_i8(self, value: i8) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(Bson::Int32(value as i32)) } #[inline] - fn visit_u8(self, value: u8) -> Result + fn visit_u8(self, value: u8) -> std::result::Result where - E: Error, + E: serde::de::Error, { convert_unsigned_to_signed(value as u64) } #[inline] - fn visit_i16(self, value: i16) -> Result + fn visit_i16(self, value: i16) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(Bson::Int32(value as i32)) } #[inline] - fn visit_u16(self, value: u16) -> Result + fn visit_u16(self, value: u16) -> std::result::Result where - E: Error, + E: serde::de::Error, { convert_unsigned_to_signed(value as u64) } #[inline] - fn visit_i32(self, value: i32) -> Result + fn visit_i32(self, value: i32) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(Bson::Int32(value)) } #[inline] - fn visit_u32(self, value: u32) -> Result + fn visit_u32(self, value: u32) -> std::result::Result where - E: Error, + E: serde::de::Error, { convert_unsigned_to_signed(value as u64) } #[inline] - fn visit_i64(self, value: i64) -> Result + fn visit_i64(self, value: i64) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(Bson::Int64(value)) } #[inline] - fn visit_u64(self, value: u64) -> Result + fn visit_u64(self, value: u64) -> std::result::Result where - E: Error, + E: serde::de::Error, { convert_unsigned_to_signed(value) } #[inline] - fn visit_f64(self, value: f64) -> Result { + fn visit_f64(self, value: f64) -> std::result::Result { Ok(Bson::Double(value)) } #[inline] - fn visit_str(self, value: &str) -> Result + fn visit_str(self, value: &str) -> std::result::Result where - E: de::Error, + E: serde::de::Error, { self.visit_string(String::from(value)) } #[inline] - fn visit_string(self, value: String) -> Result { + fn visit_string(self, value: String) -> std::result::Result { Ok(Bson::String(value)) } #[inline] - fn visit_none(self) -> Result { + fn visit_none(self) -> std::result::Result { Ok(Bson::Null) } #[inline] - fn visit_some(self, deserializer: D) -> Result + fn visit_some(self, deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { @@ -239,12 +240,12 @@ impl<'de> Visitor<'de> for BsonVisitor { } #[inline] - fn visit_unit(self) -> Result { + fn visit_unit(self) -> std::result::Result { Ok(Bson::Null) } #[inline] - fn visit_seq(self, mut visitor: V) -> Result + fn visit_seq(self, mut visitor: V) -> std::result::Result where V: SeqAccess<'de>, { @@ -257,7 +258,7 @@ impl<'de> Visitor<'de> for BsonVisitor { Ok(Bson::Array(values)) } - fn visit_map(self, mut visitor: V) -> Result + fn visit_map(self, mut visitor: V) -> std::result::Result where V: MapAccess<'de>, { @@ -274,7 +275,7 @@ impl<'de> Visitor<'de> for BsonVisitor { } impl<'a, 'de: 'a> Deserialize<'de> for BytesOrHex<'a> { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { @@ -287,9 +288,12 @@ impl<'de> Visitor<'de> for BsonVisitor { write!(formatter, "hexstring or byte array") } - fn visit_str(self, v: &str) -> Result + fn visit_str( + self, + v: &str, + ) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(BytesOrHex::Hex(Cow::Owned(v.to_string()))) } @@ -297,18 +301,23 @@ impl<'de> Visitor<'de> for BsonVisitor { fn visit_borrowed_str( self, v: &'de str, - ) -> Result + ) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(BytesOrHex::Hex(Cow::Borrowed(v))) } - fn visit_bytes(self, v: &[u8]) -> Result + fn visit_bytes( + self, + v: &[u8], + ) -> std::result::Result where - E: Error, + E: serde::de::Error, { - Ok(BytesOrHex::Bytes(v.try_into().map_err(Error::custom)?)) + Ok(BytesOrHex::Bytes( + v.try_into().map_err(serde::de::Error::custom)?, + )) } } @@ -377,7 +386,7 @@ impl<'de> Visitor<'de> for BsonVisitor { return Ok(Bson::Binary( extjson::models::Binary { body: v } .parse() - .map_err(Error::custom)?, + .map_err(serde::de::Error::custom)?, )); } @@ -385,7 +394,7 @@ impl<'de> Visitor<'de> for BsonVisitor { let v: String = visitor.next_value()?; let uuid = extjson::models::Uuid { value: v } .parse() - .map_err(Error::custom)?; + .map_err(serde::de::Error::custom)?; return Ok(Bson::Binary(uuid)); } @@ -399,7 +408,7 @@ impl<'de> Visitor<'de> for BsonVisitor { scope, })); } else { - return Err(Error::unknown_field(key.as_str(), &["$scope"])); + return Err(serde::de::Error::unknown_field(key.as_str(), &["$scope"])); } } else { return Ok(Bson::JavaScriptCode(code)); @@ -416,10 +425,10 @@ impl<'de> Visitor<'de> for BsonVisitor { scope, })); } else { - return Err(Error::unknown_field(key.as_str(), &["$code"])); + return Err(serde::de::Error::unknown_field(key.as_str(), &["$code"])); } } else { - return Err(Error::missing_field("$code")); + return Err(serde::de::Error::missing_field("$code")); } } @@ -439,7 +448,7 @@ impl<'de> Visitor<'de> for BsonVisitor { "$dbPointer" => { let dbp = visitor.next_value::()?; return Ok(Bson::DbPointer(DbPointer { - id: dbp.id.parse().map_err(Error::custom)?, + id: dbp.id.parse().map_err(serde::de::Error::custom)?, namespace: dbp.ref_ns, })); } @@ -449,7 +458,7 @@ impl<'de> Visitor<'de> for BsonVisitor { return Ok(Bson::DateTime( extjson::models::DateTime { body: dt } .parse() - .map_err(Error::custom)?, + .map_err(serde::de::Error::custom)?, )); } @@ -457,21 +466,21 @@ impl<'de> Visitor<'de> for BsonVisitor { let i = visitor.next_value::()?; return extjson::models::MaxKey { value: i } .parse() - .map_err(Error::custom); + .map_err(serde::de::Error::custom); } "$minKey" => { let i = visitor.next_value::()?; return extjson::models::MinKey { value: i } .parse() - .map_err(Error::custom); + .map_err(serde::de::Error::custom); } "$undefined" => { let b = visitor.next_value::()?; return extjson::models::Undefined { value: b } .parse() - .map_err(Error::custom); + .map_err(serde::de::Error::custom); } "$numberDecimal" => { @@ -504,9 +513,9 @@ impl<'de> Visitor<'de> for BsonVisitor { } #[inline] - fn visit_bytes(self, v: &[u8]) -> Result + fn visit_bytes(self, v: &[u8]) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(Bson::Binary(Binary { subtype: BinarySubtype::Generic, @@ -515,9 +524,9 @@ impl<'de> Visitor<'de> for BsonVisitor { } #[inline] - fn visit_byte_buf(self, v: Vec) -> Result + fn visit_byte_buf(self, v: Vec) -> std::result::Result where - E: Error, + E: serde::de::Error, { Ok(Bson::Binary(Binary { subtype: BinarySubtype::Generic, @@ -526,7 +535,7 @@ impl<'de> Visitor<'de> for BsonVisitor { } #[inline] - fn visit_newtype_struct(self, deserializer: D) -> Result + fn visit_newtype_struct(self, deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { @@ -539,35 +548,37 @@ enum BsonInteger { Int64(i64), } -fn _convert_unsigned(value: u64) -> Result { +fn convert_unsigned(value: u64) -> std::result::Result { if let Ok(int32) = i32::try_from(value) { Ok(BsonInteger::Int32(int32)) } else if let Ok(int64) = i64::try_from(value) { Ok(BsonInteger::Int64(int64)) } else { - Err(Error::custom(format!( + Err(serde::de::Error::custom(format!( "cannot represent {} as a signed number", value ))) } } -fn convert_unsigned_to_signed(value: u64) -> Result +fn convert_unsigned_to_signed(value: u64) -> std::result::Result where - E: Error, + E: serde::de::Error, { - let bi = _convert_unsigned(value)?; + let bi = convert_unsigned(value)?; match bi { BsonInteger::Int32(i) => Ok(Bson::Int32(i)), BsonInteger::Int64(i) => Ok(Bson::Int64(i)), } } -pub(crate) fn convert_unsigned_to_signed_raw<'a, E>(value: u64) -> Result, E> +pub(crate) fn convert_unsigned_to_signed_raw<'a, E>( + value: u64, +) -> std::result::Result, E> where - E: Error, + E: serde::de::Error, { - let bi = _convert_unsigned(value)?; + let bi = convert_unsigned(value)?; match bi { BsonInteger::Int32(i) => Ok(RawBsonRef::Int32(i)), BsonInteger::Int64(i) => Ok(RawBsonRef::Int64(i)), @@ -603,17 +614,13 @@ impl Deserializer { } } - fn deserialize_next<'de, V>( - mut self, - visitor: V, - hint: DeserializerHint, - ) -> Result + fn deserialize_next<'de, V>(mut self, visitor: V, hint: DeserializerHint) -> Result where V: serde::de::Visitor<'de>, { let value = match self.value.take() { Some(value) => value, - None => return Err(crate::de::Error::EndOfStream), + None => return Err(Error::end_of_stream()), }; let is_rawbson = matches!(hint, DeserializerHint::RawBson); @@ -621,7 +628,7 @@ impl Deserializer { if let DeserializerHint::BinarySubtype(expected_subtype) = hint { if let Bson::Binary(ref binary) = value { if binary.subtype != expected_subtype { - return Err(Error::custom(format!( + return Err(serde::de::Error::custom(format!( "expected Binary with subtype {:?}, instead got subtype {:?}", expected_subtype, binary.subtype ))); @@ -695,7 +702,7 @@ macro_rules! forward_to_deserialize { } impl<'de> de::Deserializer<'de> for Deserializer { - type Error = crate::de::Error; + type Error = Error; #[allow(deprecated)] fn is_human_readable(&self) -> bool { @@ -703,7 +710,7 @@ impl<'de> de::Deserializer<'de> for Deserializer { } #[inline] - fn deserialize_any(self, visitor: V) -> crate::de::Result + fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { @@ -711,7 +718,7 @@ impl<'de> de::Deserializer<'de> for Deserializer { } #[inline] - fn deserialize_bytes(self, visitor: V) -> Result + fn deserialize_bytes(self, visitor: V) -> std::result::Result where V: Visitor<'de>, { @@ -724,14 +731,14 @@ impl<'de> de::Deserializer<'de> for Deserializer { } #[inline] - fn deserialize_option(self, visitor: V) -> crate::de::Result + fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Some(Bson::Null) => visitor.visit_none(), Some(_) => visitor.visit_some(self), - None => Err(crate::de::Error::EndOfStream), + None => Err(Error::end_of_stream()), } } @@ -741,7 +748,7 @@ impl<'de> de::Deserializer<'de> for Deserializer { _name: &str, _variants: &'static [&'static str], visitor: V, - ) -> crate::de::Result + ) -> Result where V: Visitor<'de>, { @@ -757,13 +764,10 @@ impl<'de> de::Deserializer<'de> for Deserializer { }); } Some(v) => { - return Err(crate::de::Error::invalid_type( - v.as_unexpected(), - &"expected an enum", - )); + return Err(Error::invalid_type(v.as_unexpected(), &"expected an enum")); } None => { - return Err(crate::de::Error::EndOfStream); + return Err(Error::end_of_stream()); } }; @@ -772,7 +776,7 @@ impl<'de> de::Deserializer<'de> for Deserializer { let (variant, value) = match iter.next() { Some(v) => v, None => { - return Err(crate::de::Error::invalid_value( + return Err(Error::invalid_value( Unexpected::Other("empty document"), &"variant name", )) @@ -781,7 +785,7 @@ impl<'de> de::Deserializer<'de> for Deserializer { // enums are encoded in json as maps with a single key:value pair match iter.next() { - Some((k, _)) => Err(crate::de::Error::invalid_value( + Some((k, _)) => Err(Error::invalid_value( Unexpected::Map, &format!("expected map with a single key, got extra key \"{}\"", k).as_str(), )), @@ -796,11 +800,7 @@ impl<'de> de::Deserializer<'de> for Deserializer { } #[inline] - fn deserialize_newtype_struct( - mut self, - name: &'static str, - visitor: V, - ) -> crate::de::Result + fn deserialize_newtype_struct(mut self, name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { @@ -873,9 +873,9 @@ struct EnumDeserializer { } impl<'de> EnumAccess<'de> for EnumDeserializer { - type Error = crate::de::Error; + type Error = Error; type Variant = VariantDeserializer; - fn variant_seed(self, seed: V) -> crate::de::Result<(V::Value, Self::Variant)> + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>, { @@ -891,9 +891,9 @@ struct VariantDeserializer { } impl<'de> VariantAccess<'de> for VariantDeserializer { - type Error = crate::de::Error; + type Error = Error; - fn unit_variant(mut self) -> crate::de::Result<()> { + fn unit_variant(mut self) -> Result<()> { match self.val.take() { None => Ok(()), Some(val) => { @@ -902,22 +902,22 @@ impl<'de> VariantAccess<'de> for VariantDeserializer { } } - fn newtype_variant_seed(mut self, seed: T) -> crate::de::Result + fn newtype_variant_seed(mut self, seed: T) -> Result where T: DeserializeSeed<'de>, { let dec = Deserializer::new_with_options( - self.val.take().ok_or(crate::de::Error::EndOfStream)?, + self.val.take().ok_or_else(Error::end_of_stream)?, self.options, ); seed.deserialize(dec) } - fn tuple_variant(mut self, _len: usize, visitor: V) -> crate::de::Result + fn tuple_variant(mut self, _len: usize, visitor: V) -> Result where V: Visitor<'de>, { - match self.val.take().ok_or(crate::de::Error::EndOfStream)? { + match self.val.take().ok_or_else(Error::end_of_stream)? { Bson::Array(fields) => { let de = SeqDeserializer { len: fields.len(), @@ -926,22 +926,18 @@ impl<'de> VariantAccess<'de> for VariantDeserializer { }; de.deserialize_any(visitor) } - other => Err(crate::de::Error::invalid_type( + other => Err(Error::invalid_type( other.as_unexpected(), &"expected a tuple", )), } } - fn struct_variant( - mut self, - _fields: &'static [&'static str], - visitor: V, - ) -> crate::de::Result + fn struct_variant(mut self, _fields: &'static [&'static str], visitor: V) -> Result where V: Visitor<'de>, { - match self.val.take().ok_or(crate::de::Error::EndOfStream)? { + match self.val.take().ok_or_else(Error::end_of_stream)? { Bson::Document(fields) => { let de = MapDeserializer { len: fields.len(), @@ -951,7 +947,7 @@ impl<'de> VariantAccess<'de> for VariantDeserializer { }; de.deserialize_any(visitor) } - ref other => Err(crate::de::Error::invalid_type( + ref other => Err(Error::invalid_type( other.as_unexpected(), &"expected a struct", )), @@ -966,10 +962,10 @@ struct SeqDeserializer { } impl<'de> de::Deserializer<'de> for SeqDeserializer { - type Error = crate::de::Error; + type Error = Error; #[inline] - fn deserialize_any(self, visitor: V) -> crate::de::Result + fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { @@ -1013,9 +1009,9 @@ impl<'de> de::Deserializer<'de> for SeqDeserializer { } impl<'de> SeqAccess<'de> for SeqDeserializer { - type Error = crate::de::Error; + type Error = Error; - fn next_element_seed(&mut self, seed: T) -> crate::de::Result> + fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { @@ -1057,9 +1053,9 @@ impl MapDeserializer { } impl<'de> MapAccess<'de> for MapDeserializer { - type Error = crate::de::Error; + type Error = Error; - fn next_key_seed(&mut self, seed: K) -> crate::de::Result> + fn next_key_seed(&mut self, seed: K) -> Result> where K: DeserializeSeed<'de>, { @@ -1078,11 +1074,11 @@ impl<'de> MapAccess<'de> for MapDeserializer { } } - fn next_value_seed(&mut self, seed: V) -> crate::de::Result + fn next_value_seed(&mut self, seed: V) -> Result where V: DeserializeSeed<'de>, { - let value = self.value.take().ok_or(crate::de::Error::EndOfStream)?; + let value = self.value.take().ok_or_else(Error::end_of_stream)?; let de = Deserializer::new_with_options(value, self.options.clone()); seed.deserialize(de) } @@ -1093,10 +1089,10 @@ impl<'de> MapAccess<'de> for MapDeserializer { } impl<'de> de::Deserializer<'de> for MapDeserializer { - type Error = crate::de::Error; + type Error = Error; #[inline] - fn deserialize_any(self, visitor: V) -> crate::de::Result + fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { @@ -1136,49 +1132,51 @@ impl<'de> de::Deserializer<'de> for MapDeserializer { } impl<'de> Deserialize<'de> for Timestamp { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::Timestamp(timestamp) => Ok(timestamp), - _ => Err(D::Error::custom("expecting Timestamp")), + _ => Err(serde::de::Error::custom("expecting Timestamp")), } } } impl<'de> Deserialize<'de> for Regex { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::RegularExpression(regex) => Ok(regex), - _ => Err(D::Error::custom("expecting Regex")), + _ => Err(serde::de::Error::custom("expecting Regex")), } } } impl<'de> Deserialize<'de> for JavaScriptCodeWithScope { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::JavaScriptCodeWithScope(code_with_scope) => Ok(code_with_scope), - _ => Err(D::Error::custom("expecting JavaScriptCodeWithScope")), + _ => Err(serde::de::Error::custom( + "expecting JavaScriptCodeWithScope", + )), } } } impl<'de> Deserialize<'de> for Binary { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::Binary(binary) => Ok(binary), - d => Err(D::Error::custom(format!( + d => Err(serde::de::Error::custom(format!( "expecting Binary but got {:?} instead", d ))), @@ -1187,13 +1185,13 @@ impl<'de> Deserialize<'de> for Binary { } impl<'de> Deserialize<'de> for Decimal128 { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::Decimal128(d128) => Ok(d128), - o => Err(D::Error::custom(format!( + o => Err(serde::de::Error::custom(format!( "expecting Decimal128, got {:?}", o ))), @@ -1202,25 +1200,25 @@ impl<'de> Deserialize<'de> for Decimal128 { } impl<'de> Deserialize<'de> for DateTime { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::DateTime(dt) => Ok(dt), - _ => Err(D::Error::custom("expecting DateTime")), + _ => Err(serde::de::Error::custom("expecting DateTime")), } } } impl<'de> Deserialize<'de> for DbPointer { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::DbPointer(db_pointer) => Ok(db_pointer), - _ => Err(D::Error::custom("expecting DbPointer")), + _ => Err(serde::de::Error::custom("expecting DbPointer")), } } } diff --git a/src/document.rs b/src/document.rs index 5af4026b..6069f8d7 100644 --- a/src/document.rs +++ b/src/document.rs @@ -685,7 +685,7 @@ impl Document { /// library. /// /// ``` - /// # fn main() -> bson::ser::Result<()> { + /// # fn main() -> bson::error::Result<()> { /// use bson::doc; /// /// let mut v: Vec = Vec::new(); diff --git a/src/error.rs b/src/error.rs index d3ed5740..7b9d5918 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,6 +27,10 @@ pub struct Error { /// The array index associated with the error, if any. pub index: Option, + + /// The path to a deserialization error, if any. + #[cfg(feature = "serde_path_to_error")] + pub path: Option, } impl std::fmt::Display for Error { @@ -43,6 +47,11 @@ impl std::fmt::Display for Error { if let Some(ref message) = self.message { write!(f, ". Message: {}", message)?; } + #[cfg(feature = "serde_path_to_error")] + if let Some(ref path) = self.path { + write!(f, ". Path: {}", path)?; + } + write!(f, ".") } } @@ -69,6 +78,18 @@ pub enum ErrorKind { kind: Decimal128ErrorKind, }, + /// A general error occurred during deserialization. This variant is constructed in the + /// [`serde::de::Error`] implementation for the [`Error`](struct@Error) type. + #[cfg(feature = "serde")] + #[error("A deserialization-related error occurred")] + #[non_exhaustive] + Deserialization {}, + + /// The end of the BSON input was reached too soon. + #[error("End of stream")] + #[non_exhaustive] + EndOfStream {}, + /// Malformed BSON bytes were encountered. #[error("Malformed BSON bytes")] #[non_exhaustive] @@ -82,6 +103,21 @@ pub enum ErrorKind { kind: ObjectIdErrorKind, }, + /// A general error occurred during serialization. This variant is constructed in the + /// [`serde::ser::Error`] implementation for the [`Error`](struct@Error) type. + #[cfg(feature = "serde")] + #[error("A serialization error occurred")] + #[non_exhaustive] + Serialization {}, + + /// An unsigned integer could not fit into a BSON integer type. + #[error("Unsigned integer {n} cannot fit into BSON")] + #[non_exhaustive] + TooLargeUnsignedInteger { + /// The too-large unsigned integer. + n: u64, + }, + /// Invalid UTF-8 bytes were encountered. #[error("Invalid UTF-8")] #[non_exhaustive] @@ -103,16 +139,10 @@ pub enum ErrorKind { kind: ValueAccessErrorKind, }, - /// A [`std::io::Error`] occurred. + /// An IO error occurred. #[error("An IO error occurred")] #[non_exhaustive] Io {}, - - /// A wrapped deserialization error. - /// TODO RUST-1406: collapse this - #[cfg(feature = "serde")] - #[error("Deserialization error: {0}")] - DeError(crate::de::Error), } impl From for Error { @@ -122,6 +152,8 @@ impl From for Error { key: None, index: None, message: None, + #[cfg(feature = "serde_path_to_error")] + path: None, } } } @@ -133,9 +165,22 @@ impl From for Error { } #[cfg(feature = "serde")] -impl From for Error { - fn from(value: crate::de::Error) -> Self { - ErrorKind::DeError(value).into() +impl serde::de::Error for Error { + fn custom(message: T) -> Self + where + T: std::fmt::Display, + { + Self::deserialization(message) + } +} + +#[cfg(feature = "serde")] +impl serde::ser::Error for Error { + fn custom(message: T) -> Self + where + T: std::fmt::Display, + { + Self::serialization(message) } } @@ -155,6 +200,14 @@ impl Error { self } + #[cfg(feature = "serde_path_to_error")] + pub(crate) fn with_path(error: serde_path_to_error::Error) -> Self { + let path = error.path().clone(); + let mut error = error.into_inner(); + error.path = Some(path); + error + } + pub(crate) fn binary(message: impl ToString) -> Self { Self::from(ErrorKind::Binary {}).with_message(message) } @@ -163,6 +216,26 @@ impl Error { Self::from(ErrorKind::DateTime {}).with_message(message) } + #[cfg(feature = "serde")] + pub(crate) fn serialization(message: impl ToString) -> Self { + Self::from(ErrorKind::Serialization {}).with_message(message) + } + + #[cfg(feature = "serde")] + pub(crate) fn invalid_key_type(key: impl AsRef) -> Self { + Self::serialization(format!("invalid document key type: {}", key.as_ref())) + } + + #[cfg(feature = "serde")] + pub(crate) fn deserialization(message: impl ToString) -> Self { + Self::from(ErrorKind::Deserialization {}).with_message(message) + } + + #[cfg(feature = "serde")] + pub(crate) fn end_of_stream() -> Self { + ErrorKind::EndOfStream {}.into() + } + pub(crate) fn malformed_bytes(message: impl ToString) -> Self { Self::from(ErrorKind::MalformedBytes {}).with_message(message) } @@ -171,4 +244,9 @@ impl Error { pub(crate) fn is_malformed_bytes(&self) -> bool { matches!(self.kind, ErrorKind::MalformedBytes { .. },) } + + #[cfg(feature = "serde")] + pub(crate) fn too_large_integer(n: u64) -> Self { + Self::from(ErrorKind::TooLargeUnsignedInteger { n }) + } } diff --git a/src/extjson/de.rs b/src/extjson/de.rs index f147ad43..df5bbd4a 100644 --- a/src/extjson/de.rs +++ b/src/extjson/de.rs @@ -25,52 +25,19 @@ use std::convert::{TryFrom, TryInto}; use serde::de::{Error as _, Unexpected}; -use crate::{extjson::models, Bson, Document}; - -#[derive(Clone, Debug)] -#[non_exhaustive] -/// Error cases that can occur during deserialization from [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). -pub enum Error { - /// Errors that can occur during OID construction and generation from the input data. - InvalidObjectId(crate::error::Error), - - /// A general error encountered during deserialization. - /// See: - DeserializationError { message: String }, -} - -impl std::fmt::Display for Error { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - Self::InvalidObjectId(ref err) => err.fmt(fmt), - Self::DeserializationError { ref message } => message.fmt(fmt), - } - } -} - -impl std::error::Error for Error {} - -impl serde::de::Error for Error { - fn custom(msg: T) -> Self - where - T: std::fmt::Display, - { - Self::DeserializationError { - message: format!("{}", msg), - } - } -} +use crate::{ + error::{Error, Result}, + extjson::models, + Bson, + Document, +}; impl From for Error { - fn from(err: serde_json::Error) -> Self { - Self::DeserializationError { - message: err.to_string(), - } + fn from(error: serde_json::Error) -> Self { + Self::deserialization(error) } } -pub type Result = std::result::Result; - /// 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/). impl TryFrom> for Bson { type Error = Error; diff --git a/src/extjson/models.rs b/src/extjson/models.rs index caccd12f..31c137c7 100644 --- a/src/extjson/models.rs +++ b/src/extjson/models.rs @@ -1,13 +1,20 @@ //! A module defining serde models for the extended JSON representations of the various BSON types. use serde::{ - de::{Error, Unexpected}, + de::{Error as _, Unexpected}, Deserialize, Serialize, }; use std::borrow::Cow; -use crate::{base64, extjson, oid, raw::serde::CowStr, spec::BinarySubtype, Bson}; +use crate::{ + base64, + error::{Error, Result}, + oid, + raw::serde::CowStr, + spec::BinarySubtype, + Bson, +}; #[derive(Deserialize)] #[serde(deny_unknown_fields)] @@ -17,14 +24,10 @@ pub(crate) struct Int32 { } impl Int32 { - pub(crate) fn parse(self) -> extjson::de::Result { - let i: i32 = self.value.parse().map_err(|_| { - extjson::de::Error::invalid_value( - Unexpected::Str(self.value.as_str()), - &"i32 as a string", - ) - })?; - Ok(i) + pub(crate) fn parse(self) -> Result { + self.value.parse().map_err(|_| { + Error::invalid_value(Unexpected::Str(self.value.as_str()), &"i32 as a string") + }) } } @@ -36,14 +39,10 @@ pub(crate) struct Int64 { } impl Int64 { - pub(crate) fn parse(self) -> extjson::de::Result { - let i: i64 = self.value.parse().map_err(|_| { - extjson::de::Error::invalid_value( - Unexpected::Str(self.value.as_str()), - &"i64 as a string", - ) - })?; - Ok(i) + pub(crate) fn parse(self) -> Result { + self.value.parse().map_err(|_| { + Error::invalid_value(Unexpected::Str(self.value.as_str()), &"i64 as a string") + }) } } @@ -55,20 +54,14 @@ pub(crate) struct Double { } impl Double { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { match self.value.as_str() { "Infinity" => Ok(f64::INFINITY), "-Infinity" => Ok(f64::NEG_INFINITY), "NaN" => Ok(f64::NAN), - other => { - let d: f64 = other.parse().map_err(|_| { - extjson::de::Error::invalid_value( - Unexpected::Str(other), - &"bson double as string", - ) - })?; - Ok(d) - } + other => other.parse().map_err(|_| { + Error::invalid_value(Unexpected::Str(other), &"bson double as string") + }), } } } @@ -81,12 +74,9 @@ pub(crate) struct Decimal128 { } impl Decimal128 { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { self.value.parse().map_err(|_| { - extjson::de::Error::invalid_value( - Unexpected::Str(&self.value), - &"bson decimal128 as string", - ) + Error::invalid_value(Unexpected::Str(&self.value), &"bson decimal128 as string") }) } } @@ -99,10 +89,8 @@ pub(crate) struct ObjectId { } impl ObjectId { - pub(crate) fn parse(self) -> extjson::de::Result { - let oid = oid::ObjectId::parse_str(self.oid.as_str()) - .map_err(extjson::de::Error::InvalidObjectId)?; - Ok(oid) + pub(crate) fn parse(self) -> Result { + oid::ObjectId::parse_str(self.oid.as_str()) } } @@ -156,16 +144,16 @@ pub(crate) struct BinaryBody { } impl Binary { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { let bytes = base64::decode(self.body.base64.as_str()).map_err(|_| { - extjson::de::Error::invalid_value( + Error::invalid_value( Unexpected::Str(self.body.base64.as_str()), &"base64 encoded bytes", ) })?; let subtype = hex::decode(self.body.subtype.as_str()).map_err(|_| { - extjson::de::Error::invalid_value( + Error::invalid_value( Unexpected::Str(self.body.subtype.as_str()), &"hexadecimal number as a string", ) @@ -177,7 +165,7 @@ impl Binary { subtype: subtype[0].into(), }) } else { - Err(extjson::de::Error::invalid_value( + Err(Error::invalid_value( Unexpected::Bytes(subtype.as_slice()), &"one byte subtype", )) @@ -193,9 +181,9 @@ pub(crate) struct Uuid { } impl Uuid { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { let uuid = uuid::Uuid::parse_str(&self.value).map_err(|_| { - extjson::de::Error::invalid_value( + Error::invalid_value( Unexpected::Str(&self.value), &"$uuid value does not follow RFC 4122 format regarding length and hyphens", ) @@ -269,7 +257,7 @@ impl DateTimeBody { } impl DateTime { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { match self.body { DateTimeBody::Canonical(date) => { let date = date.parse()?; @@ -277,7 +265,7 @@ impl DateTime { } DateTimeBody::Relaxed(date) => { let datetime = crate::DateTime::parse_rfc3339_str(date.as_str()).map_err(|_| { - extjson::de::Error::invalid_value( + Error::invalid_value( Unexpected::Str(date.as_str()), &"rfc3339 formatted utc datetime", ) @@ -297,11 +285,11 @@ pub(crate) struct MinKey { } impl MinKey { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { if self.value == 1 { Ok(Bson::MinKey) } else { - Err(extjson::de::Error::invalid_value( + Err(Error::invalid_value( Unexpected::Unsigned(self.value as u64), &"value of $minKey should always be 1", )) @@ -317,11 +305,11 @@ pub(crate) struct MaxKey { } impl MaxKey { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { if self.value == 1 { Ok(Bson::MaxKey) } else { - Err(extjson::de::Error::invalid_value( + Err(Error::invalid_value( Unexpected::Unsigned(self.value as u64), &"value of $maxKey should always be 1", )) @@ -347,7 +335,7 @@ pub(crate) struct DbPointerBody { } impl DbPointer { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { Ok(crate::DbPointer { namespace: self.body.ref_ns, id: self.body.id.parse()?, @@ -363,11 +351,11 @@ pub(crate) struct Undefined { } impl Undefined { - pub(crate) fn parse(self) -> extjson::de::Result { + pub(crate) fn parse(self) -> Result { if self.value { Ok(Bson::Undefined) } else { - Err(extjson::de::Error::invalid_value( + Err(Error::invalid_value( Unexpected::Bool(false), &"$undefined should always be true", )) diff --git a/src/lib.rs b/src/lib.rs index c5572c5d..98b791d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -218,7 +218,7 @@ //! When serializing values that cannot be represented in BSON, or deserialzing from BSON that does //! not match the format expected by the type, the default error will only report the specific field //! that failed. To aid debugging, enabling the `serde_path_to_error` feature will -//! [augment errors](crate::de::Error::WithPath) with the full field path from root object to +//! [augment errors](crate::error::Error::path) with the full field path from root object to //! failing field. This feature does incur a small CPU and memory overhead during (de)serialization //! and should be enabled with care in performance-sensitive environments. //! diff --git a/src/ser.rs b/src/ser.rs index 5d925ab6..4100d40e 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -21,20 +21,17 @@ //! Serializer -mod error; mod raw; mod serde; -pub use self::{ - error::{Error, Result}, - serde::Serializer, -}; +pub use self::serde::Serializer; #[rustfmt::skip] use ::serde::{ser::Error as SerdeError, Serialize}; use crate::{ bson::{Bson, Document}, + error::{Error, Result}, ser::serde::SerializerOptions, RawDocumentBuf, }; @@ -79,12 +76,10 @@ where { match serialize_to_bson(value)? { Bson::Document(doc) => Ok(doc), - bson => Err(Error::SerializationError { - message: format!( - "Could not be serialized to Document, got {:?} instead", - bson.element_type() - ), - }), + bson => Err(Error::serialization(format!( + "expected to serialize document, got type {:?} instead", + bson.element_type() + ))), } } diff --git a/src/ser/error.rs b/src/ser/error.rs deleted file mode 100644 index 1bddb7df..00000000 --- a/src/ser/error.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::{error, fmt, fmt::Display, io, sync::Arc}; - -use serde::ser; - -use crate::bson::Bson; - -/// Possible errors that can arise during encoding. -#[derive(Clone, Debug)] -#[non_exhaustive] -pub enum Error { - /// A [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) encountered while serializing. - Io(Arc), - - /// A key could not be serialized to a BSON string. - InvalidDocumentKey(Bson), - - /// A general error that occurred during serialization. - /// See: - #[non_exhaustive] - SerializationError { - /// A message describing the error. - message: String, - }, - - /// An unsigned integer type could not fit into a signed integer type. - UnsignedIntegerExceededRange(u64), - - #[cfg(feature = "serde_path_to_error")] - #[cfg_attr(docsrs, doc(cfg(feature = "serde_path_to_error")))] - #[non_exhaustive] - WithPath { - /// The path to the error. - path: serde_path_to_error::Path, - - /// The original error. - source: Box, - }, - - /// TODO RUST-1406 remove this - Crate(Arc), -} - -impl Error { - #[cfg(feature = "serde_path_to_error")] - pub(crate) fn with_path(err: serde_path_to_error::Error) -> Self { - let path = err.path().clone(); - let source = Box::new(err.into_inner()); - Self::WithPath { path, source } - } - - #[cfg(test)] - pub(crate) fn strip_path(self) -> Self { - #[cfg(feature = "serde_path_to_error")] - match self { - Self::WithPath { path: _, source } => *source, - _ => self, - } - #[cfg(not(feature = "serde_path_to_error"))] - { - self - } - } -} - -impl From for Error { - fn from(err: io::Error) -> Error { - Error::Io(Arc::new(err)) - } -} - -impl From for Error { - fn from(err: crate::error::Error) -> Error { - Error::Crate(Arc::new(err)) - } -} - -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::Io(inner) => inner.fmt(fmt), - Error::InvalidDocumentKey(key) => write!(fmt, "Invalid map key type: {}", key), - Error::SerializationError { message } => message.fmt(fmt), - Error::UnsignedIntegerExceededRange(value) => write!( - fmt, - "BSON does not support unsigned integers. - An attempt to serialize the value: {} in a signed type failed due to the value's \ - size.", - value - ), - #[cfg(feature = "serde_path_to_error")] - Error::WithPath { path, source } => write!(fmt, "error at {}: {}", path, source), - Error::Crate(inner) => inner.fmt(fmt), - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::Io(ref inner) => Some(inner.as_ref()), - _ => None, - } - } -} - -impl ser::Error for Error { - fn custom(msg: T) -> Error { - Error::SerializationError { - message: msg.to_string(), - } - } -} - -/// Alias for `Result`. -pub type Result = std::result::Result; diff --git a/src/ser/raw.rs b/src/ser/raw.rs index 6980423b..c376c479 100644 --- a/src/ser/raw.rs +++ b/src/ser/raw.rs @@ -175,7 +175,7 @@ impl<'a> serde::Serializer for &'a mut Serializer { match i64::try_from(v) { Ok(ivalue) => self.serialize_i64(ivalue), - Err(_) => Err(Error::UnsignedIntegerExceededRange(v)), + Err(_) => Err(Error::too_large_integer(v)), } } diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs index 55da28d2..21587da6 100644 --- a/src/ser/raw/document_serializer.rs +++ b/src/ser/raw/document_serializer.rs @@ -1,10 +1,8 @@ use serde::{ser::Impossible, Serialize}; use crate::{ + error::{Error, Result}, raw::write_cstring, - ser::{Error, Result}, - serialize_to_bson, - Bson, RawBsonRef, }; @@ -185,12 +183,6 @@ struct KeySerializer<'a> { root_serializer: &'a mut Serializer, } -impl KeySerializer<'_> { - fn invalid_key(v: T) -> Error { - Error::InvalidDocumentKey(serialize_to_bson(&v).unwrap_or(Bson::Null)) - } -} - impl serde::Serializer for KeySerializer<'_> { type Ok = (); @@ -205,78 +197,78 @@ impl serde::Serializer for KeySerializer<'_> { type SerializeStructVariant = Impossible<(), Error>; #[inline] - fn serialize_bool(self, v: bool) -> Result { - Err(Self::invalid_key(v)) + fn serialize_bool(self, _v: bool) -> Result { + Err(Error::invalid_key_type("bool")) } #[inline] - fn serialize_i8(self, v: i8) -> Result { - Err(Self::invalid_key(v)) + fn serialize_i8(self, _v: i8) -> Result { + Err(Error::invalid_key_type("i8")) } #[inline] - fn serialize_i16(self, v: i16) -> Result { - Err(Self::invalid_key(v)) + fn serialize_i16(self, _v: i16) -> Result { + Err(Error::invalid_key_type("i16")) } #[inline] - fn serialize_i32(self, v: i32) -> Result { - Err(Self::invalid_key(v)) + fn serialize_i32(self, _v: i32) -> Result { + Err(Error::invalid_key_type("i32")) } #[inline] - fn serialize_i64(self, v: i64) -> Result { - Err(Self::invalid_key(v)) + fn serialize_i64(self, _v: i64) -> Result { + Err(Error::invalid_key_type("i64")) } #[inline] - fn serialize_u8(self, v: u8) -> Result { - Err(Self::invalid_key(v)) + fn serialize_u8(self, _v: u8) -> Result { + Err(Error::invalid_key_type("u8")) } #[inline] - fn serialize_u16(self, v: u16) -> Result { - Err(Self::invalid_key(v)) + fn serialize_u16(self, _v: u16) -> Result { + Err(Error::invalid_key_type("u16")) } #[inline] - fn serialize_u32(self, v: u32) -> Result { - Err(Self::invalid_key(v)) + fn serialize_u32(self, _v: u32) -> Result { + Err(Error::invalid_key_type("u32")) } #[inline] - fn serialize_u64(self, v: u64) -> Result { - Err(Self::invalid_key(v)) + fn serialize_u64(self, _v: u64) -> Result { + Err(Error::invalid_key_type("u64")) } #[inline] - fn serialize_f32(self, v: f32) -> Result { - Err(Self::invalid_key(v)) + fn serialize_f32(self, _v: f32) -> Result { + Err(Error::invalid_key_type("f32")) } #[inline] - fn serialize_f64(self, v: f64) -> Result { - Err(Self::invalid_key(v)) + fn serialize_f64(self, _v: f64) -> Result { + Err(Error::invalid_key_type("f64")) } #[inline] - fn serialize_char(self, v: char) -> Result { - Err(Self::invalid_key(v)) + fn serialize_char(self, _v: char) -> Result { + Err(Error::invalid_key_type("char")) } #[inline] fn serialize_str(self, v: &str) -> Result { - Ok(write_cstring(&mut self.root_serializer.bytes, v)?) + write_cstring(&mut self.root_serializer.bytes, v) } #[inline] - fn serialize_bytes(self, v: &[u8]) -> Result { - Err(Self::invalid_key(v)) + fn serialize_bytes(self, _v: &[u8]) -> Result { + Err(Error::invalid_key_type("bytes")) } #[inline] fn serialize_none(self) -> Result { - Err(Self::invalid_key(Bson::Null)) + Err(Error::invalid_key_type("none")) } #[inline] @@ -289,12 +281,12 @@ impl serde::Serializer for KeySerializer<'_> { #[inline] fn serialize_unit(self) -> Result { - Err(Self::invalid_key(Bson::Null)) + Err(Error::invalid_key_type("unit")) } #[inline] - fn serialize_unit_struct(self, _name: &'static str) -> Result { - Err(Self::invalid_key(Bson::Null)) + fn serialize_unit_struct(self, name: &'static str) -> Result { + Err(Error::invalid_key_type(name)) } #[inline] @@ -318,65 +310,65 @@ impl serde::Serializer for KeySerializer<'_> { #[inline] fn serialize_newtype_variant( self, - _name: &'static str, + name: &'static str, _variant_index: u32, - _variant: &'static str, - value: &T, + variant: &'static str, + _value: &T, ) -> Result where T: Serialize + ?Sized, { - Err(Self::invalid_key(value)) + Err(Error::invalid_key_type(format!("{}::{}", name, variant))) } #[inline] fn serialize_seq(self, _len: Option) -> Result { - Err(Self::invalid_key(Bson::Array(vec![]))) + Err(Error::invalid_key_type("sequence")) } #[inline] fn serialize_tuple(self, _len: usize) -> Result { - Err(Self::invalid_key(Bson::Array(vec![]))) + Err(Error::invalid_key_type("tuple")) } #[inline] fn serialize_tuple_struct( self, - _name: &'static str, + name: &'static str, _len: usize, ) -> Result { - Err(Self::invalid_key(Bson::Document(doc! {}))) + Err(Error::invalid_key_type(name)) } #[inline] fn serialize_tuple_variant( self, - _name: &'static str, + name: &'static str, _variant_index: u32, - _variant: &'static str, + variant: &'static str, _len: usize, ) -> Result { - Err(Self::invalid_key(Bson::Array(vec![]))) + Err(Error::invalid_key_type(format!("{}::{}", name, variant))) } #[inline] fn serialize_map(self, _len: Option) -> Result { - Err(Self::invalid_key(Bson::Document(doc! {}))) + Err(Error::invalid_key_type("map")) } #[inline] - fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { - Err(Self::invalid_key(Bson::Document(doc! {}))) + fn serialize_struct(self, name: &'static str, _len: usize) -> Result { + Err(Error::invalid_key_type(name)) } #[inline] fn serialize_struct_variant( self, - _name: &'static str, + name: &'static str, _variant_index: u32, - _variant: &'static str, + variant: &'static str, _len: usize, ) -> Result { - Err(Self::invalid_key(Bson::Document(doc! {}))) + Err(Error::invalid_key_type(format!("{}::{}", name, variant))) } } diff --git a/src/ser/serde.rs b/src/ser/serde.rs index 99abc7c9..b7cb203b 100644 --- a/src/ser/serde.rs +++ b/src/ser/serde.rs @@ -15,6 +15,7 @@ use crate::{ base64, bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp}, datetime::DateTime, + error::{Error, Result}, extjson, oid::ObjectId, raw::{RawDbPointerRef, RawRegexRef, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, @@ -25,11 +26,11 @@ use crate::{ Decimal128, }; -use super::{to_bson_with_options, Error}; +use super::to_bson_with_options; impl Serialize for ObjectId { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: serde::ser::Serializer, { @@ -41,7 +42,7 @@ impl Serialize for ObjectId { impl Serialize for Document { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { @@ -55,7 +56,7 @@ impl Serialize for Document { impl Serialize for Bson { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { @@ -193,7 +194,7 @@ impl ser::Serializer for Serializer { match i64::try_from(value) { Ok(ivalue) => Ok(Bson::Int64(ivalue)), - Err(_) => Err(Error::UnsignedIntegerExceededRange(value)), + Err(_) => Err(Error::too_large_integer(value)), } } @@ -525,10 +526,10 @@ impl SerializeMap for MapSerializer { type Ok = Bson; type Error = Error; - fn serialize_key(&mut self, key: &T) -> crate::ser::Result<()> { + fn serialize_key(&mut self, key: &T) -> Result<()> { self.next_key = match to_bson_with_options(&key, self.options.clone())? { Bson::String(s) => Some(s), - other => return Err(Error::InvalidDocumentKey(other)), + other => return Err(Error::invalid_key_type(other.element_type().name())), }; Ok(()) } @@ -603,7 +604,7 @@ impl SerializeStructVariant for StructVariantSerializer { impl Serialize for Timestamp { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { @@ -619,7 +620,7 @@ impl Serialize for Timestamp { impl Serialize for Regex { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { @@ -633,7 +634,7 @@ impl Serialize for Regex { impl Serialize for JavaScriptCodeWithScope { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { @@ -646,7 +647,7 @@ impl Serialize for JavaScriptCodeWithScope { impl Serialize for Binary { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { @@ -666,7 +667,7 @@ impl Serialize for Binary { impl Serialize for Decimal128 { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { @@ -683,7 +684,7 @@ impl Serialize for Decimal128 { impl Serialize for DateTime { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { @@ -696,7 +697,7 @@ impl Serialize for DateTime { impl Serialize for DbPointer { #[inline] - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> std::result::Result where S: ser::Serializer, { diff --git a/src/spec.rs b/src/spec.rs index dc082ff7..a7b07200 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -148,6 +148,33 @@ impl ElementType { _ => return None, }) } + + #[cfg(feature = "serde")] + pub(crate) fn name(&self) -> &'static str { + match self { + Self::Double => "double", + Self::String => "string", + Self::EmbeddedDocument => "document", + Self::Array => "array", + Self::Binary => "binary", + Self::Undefined => "undefined", + Self::ObjectId => "object ID", + Self::Boolean => "boolean", + Self::DateTime => "datetime", + Self::Null => "null", + Self::RegularExpression => "regular expression", + Self::DbPointer => "DB pointer", + Self::JavaScriptCode => "javascript code", + Self::Symbol => "symbol", + Self::JavaScriptCodeWithScope => "javascript code with scope", + Self::Int32 => "int32", + Self::Timestamp => "timestamp", + Self::Int64 => "int64", + Self::Decimal128 => "decimal128", + Self::MaxKey => "max key", + Self::MinKey => "min key", + } + } } /// The available binary subtypes, plus a user-defined slot. diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs index 8e16f3b6..bca4defe 100644 --- a/src/tests/modules/ser.rs +++ b/src/tests/modules/ser.rs @@ -4,8 +4,8 @@ use assert_matches::assert_matches; use crate::{ deserialize_from_bson, + error::ErrorKind, oid::ObjectId, - ser, serialize_to_bson, serialize_to_vec, tests::LOCK, @@ -119,8 +119,11 @@ fn uint64_u2i() { let deser_min: u64 = deserialize_from_bson(obj_min).unwrap(); assert_eq!(deser_min, u64::MIN); - let err: ser::Error = serialize_to_bson(&u64::MAX).unwrap_err().strip_path(); - assert_matches!(err, ser::Error::UnsignedIntegerExceededRange(u64::MAX)); + let error = serialize_to_bson(&u64::MAX).unwrap_err(); + assert_matches!( + error.kind, + ErrorKind::TooLargeUnsignedInteger { n: u64::MAX } + ); } #[test] @@ -172,9 +175,6 @@ fn cstring_null_bytes_error() { assert!(err.is_malformed_bytes(), "unexpected error: {:?}", err); let result = serialize_to_vec(&doc); assert!(result.is_err(), "unexpected success"); - match result.unwrap_err().strip_path() { - ser::Error::Crate(inner) if inner.is_malformed_bytes() => (), - err => panic!("unexpected error: {:?}", err), - }; + assert!(result.unwrap_err().is_malformed_bytes()); } } diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs index 2afc6a73..67bc6d09 100644 --- a/src/tests/modules/serializer_deserializer.rs +++ b/src/tests/modules/serializer_deserializer.rs @@ -9,7 +9,6 @@ use crate::{ de::deserialize_from_document, doc, oid::ObjectId, - ser::Error, serialize_to_document, spec::BinarySubtype, tests::LOCK, @@ -542,15 +541,12 @@ fn test_serialize_deserialize_document() { let x = 1; let err = serialize_to_document(&x).unwrap_err(); - match err { - Error::SerializationError { message } => { - assert!(message.contains("Could not be serialized to Document")); - } - e => panic!("expected SerializationError, got {}", e), - } + assert!(err + .message + .is_some_and(|message| message.contains("expected to serialize document"))); let bad_point = doc! { "x": "one", "y": "two" }; - let bad_point: Result = deserialize_from_document(bad_point); + let bad_point = deserialize_from_document::(bad_point); assert!(bad_point.is_err()); } diff --git a/src/tests/serde.rs b/src/tests/serde.rs index aedc739d..17a308ba 100644 --- a/src/tests/serde.rs +++ b/src/tests/serde.rs @@ -1075,12 +1075,8 @@ mod serde_path_to_error { }; let result: Result = crate::deserialize_from_document(src); assert!(result.is_err()); - match result.unwrap_err() { - crate::de::Error::WithPath { source: _, path } => { - assert_eq!("two.value", path.to_string()) - } - e => panic!("unexpected error: {:?}", e), - } + let path = result.unwrap_err().path.unwrap(); + assert_eq!(path.to_string(), "two.value"); } #[test] @@ -1096,12 +1092,8 @@ mod serde_path_to_error { .into_bytes(); let result: Result = crate::deserialize_from_slice(&src); assert!(result.is_err()); - match result.unwrap_err() { - crate::de::Error::WithPath { source: _, path } => { - assert_eq!("two.value", path.to_string()) - } - e => panic!("unexpected error: {:?}", e), - } + let path = result.unwrap_err().path.unwrap(); + assert_eq!(path.to_string(), "two.value"); } #[test] @@ -1112,12 +1104,8 @@ mod serde_path_to_error { }; let result = crate::serialize_to_bson(&src); assert!(result.is_err()); - match result.unwrap_err() { - crate::ser::Error::WithPath { source: _, path } => { - assert_eq!("two.value", path.to_string()) - } - e => panic!("unexpected error: {:?}", e), - } + let path = result.unwrap_err().path.unwrap(); + assert_eq!(path.to_string(), "two.value"); } #[test] @@ -1128,11 +1116,7 @@ mod serde_path_to_error { }; let result = crate::serialize_to_vec(&src); assert!(result.is_err()); - match result.unwrap_err() { - crate::ser::Error::WithPath { source: _, path } => { - assert_eq!("two.value", path.to_string()) - } - e => panic!("unexpected error: {:?}", e), - } + let path = result.unwrap_err().path.unwrap(); + assert_eq!(path.to_string(), "two.value"); } }