diff --git a/src/either.rs b/src/either.rs index b7137d8..f3ba30f 100644 --- a/src/either.rs +++ b/src/either.rs @@ -1,18 +1,39 @@ use std::{ convert::identity, + fmt, hint, - ops::{Deref, DerefMut} + ops::{Deref, DerefMut}, + process::{ExitCode, Termination}, }; -use Either::{Inl, Inr}; use crate::convert::{clone, clone_mut, copy, copy_mut, Empty}; +pub use Either::{Inl, Inr}; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Either { Inl(L), Inr(R), } impl Either { + /// Returns a new `Either` that is `Inl` if the given result is `Ok`, and `Inr` if the given + /// result is `Err`. + /// + /// ``` + /// # use libshire::either::{Either, Inl, Inr}; + /// let res = u8::try_from(123u32); + /// assert_eq!(Either::from_result(res), Inl(123)); + /// ``` + #[inline] + #[must_use] + pub fn from_result(result: Result) -> Self { + match result { + Ok(l) => Inl(l), + Err(r) => Inr(r), + } + } + #[inline] #[must_use] pub const fn as_ref(&self) -> Either<&L, &R> { @@ -132,7 +153,7 @@ impl Either { #[inline] #[must_use] - pub fn select(self, if_l: T, if_r: T) -> T { + pub fn select(&self, if_l: T, if_r: T) -> T { match self { Inl(_) => if_l, Inr(_) => if_r, @@ -163,13 +184,13 @@ impl Either { #[inline] #[must_use] - pub fn is_l(self) -> bool { + pub fn is_l(&self) -> bool { self.select(true, false) } #[inline] #[must_use] - pub fn is_r(self) -> bool { + pub fn is_r(&self) -> bool { self.select(false, true) } @@ -512,17 +533,80 @@ impl Either { } } -impl Empty for Either { +impl Either { + #[inline] + #[must_use] + pub fn from_option(option: Option) -> Self { + option.map_or(Inr(()), Inl) + } + + #[inline] + #[must_use] + pub fn into_option(self) -> Option { + self.fold(Some, |_| None) + } +} + +impl From> for Option { + #[inline] + fn from(either: Either) -> Self { + either.into_option() + } +} + +impl From> for Either { + #[inline] + fn from(option: Option) -> Self { + Either::from_option(option) + } +} + +impl From> for Result { + #[inline] + fn from(either: Either) -> Self { + either.into_result() + } +} + +impl From> for Either { + #[inline] + fn from(result: Result) -> Self { + Either::from_result(result) + } +} + +impl Empty for Either +where + L: Empty, + R: Empty, +{ + #[inline] fn elim(self) -> T { self.fold(::elim, ::elim) } } -impl Clone for Either { +impl Termination for Either +where + L: Termination, + R: Termination, +{ #[inline] - fn clone(&self) -> Self { - self.as_ref().map(::clone, ::clone) + fn report(self) -> ExitCode { + self.fold(::report, ::report) } } -impl Copy for Either {} +impl fmt::Display for Either +where + L: fmt::Display, + R: fmt::Display, +{ + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Inl(l) => ::fmt(l, f), + Inr(r) => ::fmt(r, f), + } + } +}