From d0771957ab3ba424f51ece92c67bf5eeff8a2c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Avi=20=D7=93?= Date: Sun, 23 Dec 2018 07:24:49 -0500 Subject: [PATCH] Simple methods to bring EitherOrBoth inline with either --- src/either_or_both.rs | 136 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/src/either_or_both.rs b/src/either_or_both.rs index 55ae06c6b..03130b128 100644 --- a/src/either_or_both.rs +++ b/src/either_or_both.rs @@ -1,5 +1,7 @@ use EitherOrBoth::*; +use either::Either; + /// Value that either holds a single A or B, or both. #[derive(Clone, PartialEq, Eq, Debug)] pub enum EitherOrBoth { @@ -22,11 +24,35 @@ impl EitherOrBoth { self.as_ref().right().is_some() } + /// If Left, return true otherwise, return false. + /// Exclusive version of [`has_left`]. + pub fn is_left(&self) -> bool { + match *self { + Left(_) => true, + _ => false, + } + } + + /// If Right, return true otherwise, return false. + /// Exclusive version of [`has_right`]. + pub fn is_right(&self) -> bool { + match *self { + Right(_) => true, + _ => false, + } + } + + /// If Right, return true otherwise, return false. + /// Equivalent to `self.as_ref().both().is_some()`. + pub fn is_both(&self) -> bool { + self.as_ref().both().is_some() + } + /// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`. pub fn left(self) -> Option { match self { Left(left) | Both(left, _) => Some(left), - _ => None + _ => None, } } @@ -34,7 +60,15 @@ impl EitherOrBoth { pub fn right(self) -> Option { match self { Right(right) | Both(_, right) => Some(right), - _ => None + _ => None, + } + } + + /// If Both, return `Some` tuple containing left and right. + pub fn both(self) -> Option<(A, B)> { + match self { + Both(a, b) => Some((a, b)), + _ => None, } } @@ -55,4 +89,102 @@ impl EitherOrBoth { Both(ref mut left, ref mut right) => Both(left, right), } } + + /// Convert `EitherOrBoth` to `EitherOrBoth`. + pub fn flip(self) -> EitherOrBoth { + match self { + Left(a) => Right(a), + Right(b) => Left(b), + Both(a, b) => Both(b, a), + } + } + + /// Apply the function `f` on the value `a` in `Left(a)` or `Both(a, b)` variants. If it is + /// present rewrapping the result in `self`'s original variant. + pub fn map_left(self, f: F) -> EitherOrBoth + where + F: FnOnce(A) -> M, + { + match self { + Both(a, b) => Both(f(a), b), + Left(a) => Left(f(a)), + Right(b) => Right(b), + } + } + + /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, b)` variants. + /// If it is present rewrapping the result in `self`'s original variant. + pub fn map_right(self, f: F) -> EitherOrBoth + where + F: FnOnce(B) -> M, + { + match self { + Left(a) => Left(a), + Right(b) => Right(f(b)), + Both(a, b) => Both(a, f(b)), + } + } + + /// Apply the functions `f` and `g` on the value `a` and `b` respectively; + /// found in `Left(a)`, `Right(b)`, or `Both(a, b)` variants. + /// The Result is rewrapped `self`'s original variant. + pub fn map_any(self, f: F, g: G) -> EitherOrBoth + where + F: FnOnce(A) -> L, + G: FnOnce(B) -> R, + { + match self { + Left(a) => Left(f(a)), + Right(b) => Right(g(b)), + Both(a, b) => Both(f(a), g(b)), + } + } + + /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, _)` variants if it is + /// present. + pub fn left_and_then(self, f: F) -> EitherOrBoth + where + F: FnOnce(A) -> EitherOrBoth, + { + match self { + Left(a) | Both(a, _) => f(a), + Right(b) => Right(b), + } + } + + /// Apply the function `f` on the value `a` + /// in `Left(a)` or `Both(a, _)` variants if it is present. + pub fn right_and_then(self, f: F) -> EitherOrBoth + where + F: FnOnce(B) -> EitherOrBoth, + { + match self { + Left(a) => Left(a), + Right(b) | Both(_, b) => f(b), + } + } +} + +impl EitherOrBoth { + /// Return either value of left, right, or the product of `f` applied where `Both` are present. + pub fn reduce(self, f: F) -> T + where + F: FnOnce(T, T) -> T, + { + match self { + Left(a) => a, + Right(b) => b, + Both(a, b) => f(a, b), + } + } +} + +impl Into>> for EitherOrBoth { + fn into(self) -> Option> { + match self { + EitherOrBoth::Left(l) => Some(Either::Left(l)), + EitherOrBoth::Right(r) => Some(Either::Right(r)), + _ => None, + } + } }