use core::fmt::{self, Debug, Display}; #[cfg(feature = "std")] use std::error::Error; pub use Exun::{Expected, Unexpected}; /// `Expect` is a type that represents either the expected error type /// ([`Expected`]) or an unexpected error ([`Unexpected`]). /// /// See the [crate documentation](self) for details. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum Exun { /// Contains the expected error type Expected(E), /// Contains an unexpected error Unexpected(U), } impl Display for Exun { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Expected(e) => e.fmt(f), Unexpected(u) => u.fmt(f), } } } #[cfg(feature = "std")] impl Error for Exun { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { Expected(ref e) => Some(e), Unexpected(ref u) => Some(u), } } } impl From for Exun { fn from(e: E) -> Self { Expected(e) } } impl Exun { /// Converts from `Expect` to [`Option`]. /// /// Converts `self` into an [`Option`], consuming `self`, and discarding /// the unexpected value, if any. /// /// # Examples /// Basic usage: /// ``` /// use exun::*; /// /// let x: Expect = Expected(2); /// assert_eq!(x.expected(), Some(2)); /// /// let x: Expect = Unexpected("Nothing here"); /// assert_eq!(x.expected(), None); /// ``` #[allow(clippy::missing_const_for_fn)] pub fn expected(self) -> Option { match self { Expected(e) => Some(e), Unexpected(_) => None, } } /// Converts from `Expect` to [`Option`]. /// /// Converts `self` into an [`Option`], consuming `self`, and discarding /// the expected value, if any. /// /// # Examples /// /// Basic usage: /// /// ``` /// use exun::*; /// /// let x: Expect = Expected(2); /// assert_eq!(x.unexpected(), None); /// /// let x: Expect = Unexpected("Nothing here"); /// assert_eq!(x.unexpected(), Some("Nothing here")); /// ``` #[allow(clippy::missing_const_for_fn)] pub fn unexpected(self) -> Option { match self { Expected(_) => None, Unexpected(u) => Some(u), } } /// Converts from `&mut Expect` to `Expect<&mut E, &mut U>`. /// /// # Examples /// /// Basic usage: /// /// ``` /// use exun::*; /// /// fn mutate(r: &mut Expect) { /// match r.as_mut() { /// Expected(e) => *e = 42, /// Unexpected(u) => *u = 0, /// } /// } /// /// let mut x = Expected(2); /// mutate(&mut x); /// assert_eq!(x.unwrap(), 42); /// /// let mut x = Unexpected(13); /// mutate(&mut x); /// assert_eq!(x.unwrap_unexpected(), 0); /// ``` pub fn as_mut(&mut self) -> Exun<&mut E, &mut U> { match self { Expected(ref mut e) => Expected(e), Unexpected(ref mut u) => Unexpected(u), } } /// Maps a `Expect` to `Expect` by applying a function to a /// contained [`Expected`] value, leaving an [`Unexpected`] value /// untouched. /// /// This function can be used to compose the results of two functions. /// /// # Examples /// /// Basic usage: /// /// ``` /// use exun::*; /// /// let x: Expect = Expected(2); /// assert_eq!(x.map(|i| i * 10), Expected(20)); /// /// let x: Expect = Unexpected("unexpected"); /// assert_eq!(x.map(|i| i * 10), Unexpected("unexpected")); /// ``` pub fn map T>(self, op: F) -> Exun { match self { Expected(e) => Expected(op(e)), Unexpected(u) => Unexpected(u), } } /// Maps a `Expect` to `Expect` by applying a function to a /// contained [`Unexpected`] value, leaving an [`Expected`] value /// untouched. /// /// This function can be used to pass through an expected result while /// handling an error. /// /// # Examples /// /// Basic usage: /// /// ``` /// use exun::*; /// /// fn stringify(x: u32) -> String { format!("error code: {x}") } /// /// let x: Expect = Expected(2); /// assert_eq!(x.map_unexpected(stringify), Expected(2)); /// /// let x: Expect = Unexpected(13); /// assert_eq!(x.map_unexpected(stringify), Unexpected("error code: 13".to_string())); /// ``` pub fn map_unexpected T>(self, op: F) -> Exun { match self { Expected(e) => Expected(e), Unexpected(u) => Unexpected(op(u)), } } /// Returns the contained [`Expected`] value, consuming the `self` value. /// /// Because this function may panic, its use is generally discouraged. /// Instead, prefer to use pattern matching and handle the [`Unexpected`] /// case explicitly. /// /// # Panics /// /// Panics if the value is [`Unexpected`], with an panic message provided /// by the [`Unexpected`]'s value. /// /// # Examples /// /// Basic usage: /// /// ``` /// use exun::*; /// /// let x: Expect = Expected(2); /// assert_eq!(x.unwrap(), 2); /// ``` /// /// ```should_panic /// use exun::*; /// /// let x: Expect = Unexpected("emergency failure"); /// x.unwrap(); // panics with `emergency failure` /// ``` pub fn unwrap(self) -> E where U: Debug, { match self { Expected(e) => e, Unexpected(u) => panic!("called `Expect::unwrap` on an `Unexpected` value: {:?}", u), } } /// Returns the contained [`Unexpected`] value, consuming the `self` value. /// /// # Panics /// /// Panics if the value is [`Expected`], with an panic message provided by /// the [`Expected`]'s value. /// /// # Examples /// /// Basic usage: /// /// ```should_panic /// use exun::*; /// /// let x: Expect = Expected(2); /// x.unwrap_unexpected(); // panics wirh `2` /// ``` /// /// ``` /// use exun::*; /// /// let x: Expect = Unexpected("emergency failure"); /// assert_eq!(x.unwrap_unexpected(), "emergency failure"); /// ``` pub fn unwrap_unexpected(self) -> U where E: Debug, { match self { Expected(e) => panic!( "called `Expect::unwrap_unexpected` on an `Expected` value: {:?}", e ), Unexpected(u) => u, } } }