diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 9 | ||||
| -rw-r--r-- | src/unexpected.rs | 86 |
2 files changed, 95 insertions, 0 deletions
@@ -1,14 +1,23 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(clippy::nursery)] #![warn(clippy::pedantic)] +#![allow(clippy::module_name_repetitions)] + +#[cfg(all(feature = "alloc", not(feature = "std")))] +extern crate alloc; use core::fmt::{self, Debug, Display}; #[cfg(feature = "std")] use std::error::Error; +#[cfg(feature = "alloc")] +pub use unexpected::UnexpectedError; pub use Expect::{Expected, Unexpected}; +#[cfg(feature = "alloc")] +mod unexpected; + /// `Expect` is a type that represents either the expected error type /// ([`Expected`]) or an unexpected error ([`Unexpected`]). /// diff --git a/src/unexpected.rs b/src/unexpected.rs new file mode 100644 index 0000000..6e5548b --- /dev/null +++ b/src/unexpected.rs @@ -0,0 +1,86 @@ +use core::fmt::{self, Debug, Display}; + +#[cfg(not(feature = "std"))] +use alloc::boxed::Box; + +#[cfg(feature = "std")] +use std::error::Error; + +pub trait Errorable: Display + Debug {} +impl<T: Display + Debug> Errorable for T {} + +#[derive(Debug)] +#[non_exhaustive] +enum ErrorTy { + Message(Box<dyn Errorable + 'static>), + #[cfg(feature = "std")] + Error(Box<dyn Error + 'static>), +} + +#[derive(Debug)] +pub struct UnexpectedError { + internal: ErrorTy, +} + +impl Display for UnexpectedError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.internal { + ErrorTy::Message(m) => Display::fmt(&m, f), + #[cfg(feature = "std")] + ErrorTy::Error(e) => Display::fmt(&e, f), + } + } +} + +#[cfg(feature = "std")] +impl Error for UnexpectedError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match &self.internal { + ErrorTy::Message(_) => None, + #[cfg(feature = "std")] + ErrorTy::Error(e) => Some(&**e), + } + } +} + +impl UnexpectedError { + /// Create a new `UnexpectedError` from any [`Error`] type. + /// + /// The error must be `'static` so that the `UnexpectedError` will be too. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use exun::*; + /// + /// let err = UnexpectedError::new(core::fmt::Error); + /// ``` + #[cfg(feature = "std")] + pub fn new<E: Error + 'static>(e: E) -> Self { + Self { + internal: ErrorTy::Error(Box::new(e)), + } + } + + /// Create an error message from a printable error message. + /// + /// If the argument implements [`Error`], prefer [`UnexpectedError::new`] + /// instead, which preserves the source. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use exun::*; + /// + /// let err = UnexpectedError::msg("failed"); + /// ``` + pub fn msg<E: Errorable + 'static>(e: E) -> Self { + Self { + internal: ErrorTy::Message(Box::new(e)), + } + } +} |
