summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs9
-rw-r--r--src/unexpected.rs86
2 files changed, 95 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index dcd75dd..111b343 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)),
+ }
+ }
+}