-
Notifications
You must be signed in to change notification settings - Fork 151
RUST-1406 Add type-specific errors to standard error type #555
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
6380979
a10b680
33a6a6f
950965c
d7e05d4
d368d4c
ec54947
a74e72e
3d8e887
54c7dbb
2176ad6
5b0057c
1ee3a41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,6 @@ use crate::{ | |
| base64, | ||
| error::{Error, Result}, | ||
| spec::BinarySubtype, | ||
| Document, | ||
| RawBinaryRef, | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,9 @@ pub struct Error { | |
| /// The kind of error that occurred. | ||
| pub kind: ErrorKind, | ||
|
|
||
| /// An optional message describing the error. | ||
| pub message: Option<String>, | ||
|
|
||
| /// The document key associated with the error, if any. | ||
| pub key: Option<String>, | ||
|
|
||
|
|
@@ -28,13 +31,19 @@ pub struct Error { | |
|
|
||
| impl std::fmt::Display for Error { | ||
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| write!(f, "BSON error")?; | ||
|
|
||
| if let Some(key) = self.key.as_deref() { | ||
| write!(f, "Error at key \"{key}\": ")?; | ||
| write!(f, " at key \"{key}\"")?; | ||
| } else if let Some(index) = self.index { | ||
| write!(f, "Error at array index {index}: ")?; | ||
| write!(f, " at array index {index}")?; | ||
| } | ||
|
|
||
| write!(f, "{}", self.kind) | ||
| write!(f, ". Kind: {}", self.kind)?; | ||
| if let Some(ref message) = self.message { | ||
| write!(f, ". Message: {}", message)?; | ||
| } | ||
| write!(f, ".") | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -43,47 +52,44 @@ impl std::fmt::Display for Error { | |
| #[non_exhaustive] | ||
| pub enum ErrorKind { | ||
| /// An error related to the [`Binary`](crate::Binary) type occurred. | ||
| #[error("A Binary-related error occurred: {message}")] | ||
| Binary { | ||
| /// A message describing the error. | ||
| message: String, | ||
| }, | ||
| #[error("A Binary-related error occurred")] | ||
| #[non_exhaustive] | ||
| Binary {}, | ||
|
|
||
| /// An error related to the [`DateTime`](crate::DateTime) type occurred. | ||
| #[error("A DateTime-related error occurred: {message}")] | ||
| DateTime { | ||
| /// A message describing the error. | ||
| message: String, | ||
| }, | ||
| #[error("A DateTime-related error occurred")] | ||
| #[non_exhaustive] | ||
| DateTime {}, | ||
|
|
||
| /// An error related to the [`Decimal128`](crate::Decimal128) type occurred. | ||
| #[error("A Decimal128-related error occurred: {kind}")] | ||
| #[non_exhaustive] | ||
| Decimal128 { | ||
| /// The kind of error that occurred. | ||
| kind: Decimal128ErrorKind, | ||
| }, | ||
|
|
||
| /// Malformed BSON bytes were encountered. | ||
| #[error("Malformed BSON bytes: {message}")] | ||
| #[error("Malformed BSON bytes")] | ||
| #[non_exhaustive] | ||
| MalformedBytes { | ||
| /// A message describing the error. | ||
| message: String, | ||
| }, | ||
| MalformedBytes {}, | ||
|
|
||
| /// An error related to the [`ObjectId`](crate::oid::ObjectId) type occurred. | ||
| #[error("An ObjectId-related error occurred: {kind}")] | ||
| #[non_exhaustive] | ||
| ObjectId { | ||
| /// The kind of error that occurred. | ||
| kind: ObjectIdErrorKind, | ||
| }, | ||
|
|
||
| /// Invalid UTF-8 bytes were encountered. | ||
| #[error("Invalid UTF-8")] | ||
| Utf8Encoding, | ||
| #[non_exhaustive] | ||
| Utf8Encoding {}, | ||
|
|
||
| /// An error related to the [`Uuid`](crate::uuid::Uuid) type occurred. | ||
| #[error("A UUID-related error occurred: {kind}")] | ||
| #[non_exhaustive] | ||
| Uuid { | ||
| /// The kind of error that occurred. | ||
| kind: UuidErrorKind, | ||
|
|
@@ -98,8 +104,9 @@ pub enum ErrorKind { | |
| }, | ||
|
|
||
| /// A [`std::io::Error`] occurred. | ||
| #[error("An IO error occurred: {0}")] | ||
| Io(std::io::Error), | ||
| #[error("An IO error occurred")] | ||
| #[non_exhaustive] | ||
| Io {}, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. switched this over to a stringified version of the error -
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might want to carry the |
||
|
|
||
| /// A wrapped deserialization error. | ||
| /// TODO RUST-1406: collapse this | ||
|
|
@@ -114,13 +121,14 @@ impl From<ErrorKind> for Error { | |
| kind, | ||
| key: None, | ||
| index: None, | ||
| message: None, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl From<std::io::Error> for Error { | ||
| fn from(value: std::io::Error) -> Self { | ||
| ErrorKind::Io(value).into() | ||
| Error::from(ErrorKind::Io {}).with_message(value) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -142,29 +150,25 @@ impl Error { | |
| self | ||
| } | ||
|
|
||
| pub(crate) fn with_message(mut self, message: impl ToString) -> Self { | ||
| self.message = Some(message.to_string()); | ||
| self | ||
| } | ||
|
|
||
| pub(crate) fn binary(message: impl ToString) -> Self { | ||
| ErrorKind::Binary { | ||
| message: message.to_string(), | ||
| } | ||
| .into() | ||
| Self::from(ErrorKind::Binary {}).with_message(message) | ||
| } | ||
|
|
||
| pub(crate) fn datetime(message: impl ToString) -> Self { | ||
| ErrorKind::DateTime { | ||
| message: message.to_string(), | ||
| } | ||
| .into() | ||
| Self::from(ErrorKind::DateTime {}).with_message(message) | ||
| } | ||
|
|
||
| pub(crate) fn malformed_bytes(message: impl ToString) -> Self { | ||
| ErrorKind::MalformedBytes { | ||
| message: message.to_string(), | ||
| } | ||
| .into() | ||
| Self::from(ErrorKind::MalformedBytes {}).with_message(message) | ||
| } | ||
|
|
||
| #[cfg(all(test, feature = "serde"))] | ||
| pub(crate) fn is_malformed_value(&self) -> bool { | ||
| matches!(self.kind, ErrorKind::MalformedValue { .. },) | ||
| pub(crate) fn is_malformed_bytes(&self) -> bool { | ||
| matches!(self.kind, ErrorKind::MalformedBytes { .. },) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exposing how arbitrary it is which of our errors carry a string and which carry a subkind enum; that's got a bit of a code smell to it but I can't decide if it's actually a problem worth addressing. Do you have thoughts here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't love this design; I agree that it's arbitrary and inconsistent. My concern, however, is that users who do have some kind of programmatic use for the values in these errors will be less inclined to migrate to the new version, so my instinct here is to err on the side of portability for lower-priority changes. Certainly open to other designs here if you had something else in mind though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sketch of a proposal:
messageto an optional field ofError, with corresponding code in theDisplayimpl to append it if it's present.ErrorKindare required to be#[non_exhaustive]struct variants, even if they're empty (which a lot now will be withmessagestripped out)Kindtypes follow the same pattern (sub-Kindsalso don't need to havemessagesince they're ultimately attached to anError!)This makes the error space a lot more uniform, gives us a lot of flexibility for future error evolution, and doesn't introduce substantial migration burden.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this a lot more - updated with your suggestions!