#![cfg_attr(not(feature = "std"), no_std)] #![warn(clippy::nursery)] #![warn(clippy::pedantic)] use core::fmt::{self, Debug, Display}; #[cfg(feature = "std")] use std::error::Error; pub use Expect::{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 Expect { /// Contains the expected error type Expected(E), /// Contains an unexpected error Unexpected(U), } impl Display for Expect { 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 Expect { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { Expected(ref e) => Some(e), Unexpected(ref u) => Some(u), } } } impl From for Expect { fn from(e: E) -> Self { Expected(e) } } impl Expect { /// 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) -> Expect<&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) -> Expect { 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) -> Expect { 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, or use [`unwrap_or`] or [`unwrap_or_else`]. /// /// [`unwrap_or`]: Expect::unwrap_or /// [`unwrap_or_else`]: Expect::unwrap_or_else /// /// # 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, } } /// Returns the contained [`Expected`] value, or a provided default. /// /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are /// passing the result of a function call, it is recommended to use /// [`unwrap_or_else`], which is lazily evaluated. /// /// [`unwrap_or_else`]: Expect::unwrap_or_else /// /// # Examples /// /// Basic usage: /// /// ``` /// use exun::*; /// /// let default = 2; /// let x: Expect = Expected(9); /// assert_eq!(x.unwrap_or(default), 9); /// /// let x: Expect = Unexpected("unexpected"); /// assert_eq!(x.unwrap_or(default), 2); /// ``` #[allow(clippy::missing_const_for_fn)] pub fn unwrap_or(self, default: E) -> E { match self { Expected(e) => e, Unexpected(_) => default, } } /// Returns the contained [`Expected`] value, or computes it from a /// closure. /// /// # Examples /// /// Basic usage: /// /// ``` /// use exun::*; /// /// fn count(x: &str) -> usize { x.len() } /// /// assert_eq!(Expected(2).unwrap_or_else(count), 2); /// assert_eq!(Unexpected("foo").unwrap_or_else(count), 3); /// ``` pub fn unwrap_or_else E>(self, op: F) -> E { match self { Expected(e) => e, Unexpected(u) => op(u), } } }