use core::fmt::Debug; #[cfg(feature = "std")] use std::error::Error; use crate::{unexpected::Errorable, Exun, RawUnexpected}; mod sealed { pub trait Sealed {} impl Sealed for Result {} impl Sealed for Option {} } use sealed::Sealed; /// Provides [`Result::unexpect`] /// /// [`Result::unexpect`]: `ResultErrorExt::unexpect` #[cfg(feature = "std")] pub trait ResultErrorExt: Sealed { /// Converts [`Result`] to [`Result`]. /// /// # Examples /// /// ``` /// use exun::*; /// use core::fmt::Error; /// /// let res: Result = Err(Error); /// let res: Result = res.unexpect(); /// ``` /// /// Use with the try operator /// /// ``` /// use exun::*; /// use core::fmt::Error; /// /// fn foo() -> Result { /// let res: Result = Err(Error); /// Ok(res.unexpect()?) /// } /// ``` /// /// Use with the try operator and [`Exun`] /// /// ``` /// use exun::*; /// use core::fmt::Error; /// /// fn foo() -> Result> { /// let res: Result = Err(Error); /// Ok(res.unexpect()?) /// } /// ``` /// /// [`Exun`]: `crate::Exun` #[allow(clippy::missing_errors_doc)] fn unexpect(self) -> Result; } #[cfg(feature = "std")] impl ResultErrorExt for Result { fn unexpect(self) -> Result { self.map_err(RawUnexpected::new) } } #[cfg(feature = "std")] impl ResultErrorExt for Result { fn unexpect(self) -> Self { self } } #[cfg(feature = "std")] impl ResultErrorExt for Option { fn unexpect(self) -> Result { self.ok_or_else(RawUnexpected::none) } } /// Provides [`Result::unexpect_msg`] /// /// [`Result::unexpect_msg`]: `ResultMsgExt::unexpect_msg` #[cfg(feature = "alloc")] pub trait ResultMsgExt: Sealed { /// Converts [`Result`] to [`Result`]. /// /// This is provided for compatibility with `no_std`. If your type /// implements [`Error`], then you should prefer that instead. /// /// # Examples /// /// ``` /// use exun::*; /// /// let res: Result = Err("failure"); /// let res: Result = res.unexpect_msg(); /// ``` /// /// Use with the try operator /// /// ``` /// use exun::*; /// /// fn foo() -> Result { /// let res: Result = Err("failure"); /// Ok(res.unexpect_msg()?) /// } /// ``` /// /// Use with the try operator and [`Exun`] /// /// ``` /// use exun::*; /// /// fn foo() -> Result> { /// let res: Result = Err("failure"); /// Ok(res.unexpect_msg()?) /// } /// ``` /// /// [`Exun`]: `crate::Exun` #[allow(clippy::missing_errors_doc)] fn unexpect_msg(self) -> Result; } #[cfg(feature = "alloc")] impl ResultMsgExt for Result { fn unexpect_msg(self) -> Result { self.map_err(RawUnexpected::msg) } } pub trait ResultExunExt: Sealed { /// Converts [`Result>`] to [`Option`]. /// /// Converts self into an [`Option`], consuming `self`, and discarding /// success value and the unexpected error, if any. /// /// # Examples /// /// ``` /// use exun::{Expected, Exun, ResultExunExt}; /// /// let x: Result> = Ok(2); /// assert_eq!(x.expected_err(), None); /// /// let x: Result> = Err(Expected("expected")); /// assert_eq!(x.expected_err(), Some("expected")); /// ``` fn expected_err(self) -> Option; /// Converts [`Result>`] to [`Option`]. /// /// Converts self into an [`Option`], consuming `self`, and discarding /// success value and the expected error, if any. /// /// # Examples /// /// ``` /// use exun::{Exun, ResultExunExt, Unexpected}; /// /// let x: Result> = Ok(2); /// assert_eq!(x.unexpected_err(), None); /// /// let x: Result> = Err(Unexpected("unexpected")); /// assert_eq!(x.unexpected_err(), Some("unexpected")); /// ``` fn unexpected_err(self) -> Option; /// Maps a [`Result>`] to `Result>` by applying /// a function to a contained `Err(Expected)` value, leaving the `Ok` and /// `Err(Unexpected)` values untouched. /// /// This function can be used to pass through a successful result while /// handling an expected error. /// /// # Examples /// /// ``` /// use exun::{Exun, ResultExunExt, Expected}; /// /// fn stringify(x: u32) -> String { format!("error code: {x}") } /// /// let x: Result> = Ok(2); /// assert_eq!(x.map_expected_err(stringify), Ok(2)); /// /// let x: Result> = Err(Expected(13)); /// assert_eq!(x.map_expected_err(stringify), Err(Expected("error code: 13".to_string()))); /// ``` fn map_expected_err(self, op: impl FnOnce(E) -> F) -> Result>; /// Maps a [`Result>`] to `Result>` by applying /// a function to a contained `Err(Unexpected)` value, leaving the `Ok` and /// `Err(Expected)` values untouched. /// /// This function can be used to pass through a successful result while /// handling an unexpected error. /// /// # Examples /// /// ``` /// use exun::{Exun, ResultExunExt, Unexpected}; /// /// fn stringify(x: &str) -> String { format!("error: {x}") } /// /// let x: Result> = Ok(2); /// assert_eq!(x.map_unexpected_err(stringify), Ok(2)); /// /// let x: Result> = Err(Unexpected("hi")); /// assert_eq!(x.map_unexpected_err(stringify), Err(Unexpected("error: hi".to_string()))); /// ``` fn map_unexpected_err(self, op: impl FnOnce(U) -> F) -> Result>; /// Converts [`Result>`] to `Result`, 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 an [`Unexpected`], with a panic message provided /// by the [`Unexpected`]'s value. /// /// # Examples /// /// ``` /// use exun::{Exun, ResultExunExt}; /// /// let x: Result> = Ok(2); /// assert_eq!(x.unwrap_result(), Ok(2)); /// ``` /// /// [`Unexpected`]: crate::Unexpected fn unwrap_result(self) -> Result where U: Debug; /// 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 an [`Unexpected`], with a panic message provided /// by the [`Unexpected`]'s value. /// /// # Examples /// /// ``` /// use exun::{Expected, Exun, ResultExunExt}; /// /// let x: Result> = Err(Expected("failure")); /// assert_eq!(x.unwrap_expected_err(), "failure"); /// ``` /// /// [`Expected`]: crate::Expected /// [`Unexpected`]: crate::Unexpected fn unwrap_expected_err(self) -> E where T: Debug, U: Debug; /// Returns the contained [`Unexpected`] value, consuming the `self` value. /// /// Because this function may panic, its use is generally discouraged. /// Instead, prefer to use pattern matching and handle the [`Expected`] /// case explicitly. /// /// # Panics /// /// Panics if the value is an [`Expected`], with a panic message provided /// by the [`Expected`]'s value. /// /// # Examples /// /// ``` /// use exun::{Exun, ResultExunExt, Unexpected}; /// /// let x: Result> = Err(Unexpected("failure")); /// assert_eq!(x.unwrap_unexpected_err(), "failure"); /// ``` /// /// [`Expected`]: crate::Expected /// [`Unexpected`]: crate::Unexpected fn unwrap_unexpected_err(self) -> U where T: Debug, E: Debug; } impl ResultExunExt for Result> { fn expected_err(self) -> Option { self.err()?.expected() } fn unexpected_err(self) -> Option { self.err()?.unexpected() } fn map_expected_err(self, op: impl FnOnce(E) -> F) -> Result> { self.map_err(|e| e.map(op)) } fn map_unexpected_err(self, op: impl FnOnce(U) -> F) -> Result> { self.map_err(|e| e.map_unexpected(op)) } fn unwrap_result(self) -> Result where U: Debug, { match self { Ok(value) => Ok(value), Err(error) => Err(error.unwrap()), } } fn unwrap_expected_err(self) -> E where T: Debug, U: Debug, { self.unwrap_err().unwrap() } fn unwrap_unexpected_err(self) -> U where T: Debug, E: Debug, { self.unwrap_err().unwrap_unexpected() } }