#![cfg_attr(not(feature = "std"), no_std)]
use core::{convert::identity, iter::FusedIterator, ops::Add};
pub use Either::{Both, Left, Right};
pub mod prelude;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Either<L, R> {
Left(L),
Right(R),
Both(L, R),
}
#[inline]
pub const fn neither<L, R>() -> MaybeEither<L, R> {
None
}
pub type MaybeEither<L, R> = Option<Either<L, R>>;
impl<L, R> Either<L, R> {
pub fn from_options(left: Option<L>, right: Option<R>) -> MaybeEither<L, R> {
let either = match (left, right) {
(None, None) => return None,
(Some(l), None) => Left(l),
(None, Some(r)) => Right(r),
(Some(l), Some(r)) => Both(l, r),
};
Some(either)
}
pub const fn as_ref(&self) -> Either<&L, &R> {
match *self {
Left(ref l) => Left(l),
Right(ref r) => Right(r),
Both(ref l, ref r) => Both(l, r),
}
}
pub fn left(self) -> Option<L> {
match self {
Left(l) | Both(l, _) => Some(l),
Right(_) => None,
}
}
pub fn only_left(self) -> Option<L> {
match self {
Left(l) => Some(l),
_ => None,
}
}
pub fn right(self) -> Option<R> {
match self {
Right(r) | Both(_, r) => Some(r),
Left(_) => None,
}
}
pub fn only_right(self) -> Option<R> {
match self {
Right(r) => Some(r),
_ => None,
}
}
pub fn both(self) -> Option<(L, R)> {
match self {
Both(l, r) => Some((l, r)),
_ => None,
}
}
pub fn expect_left(self, message: &str) -> L {
match self {
Left(l) | Both(l, _) => l,
Right(_) => panic!("{message}"),
}
}
pub fn expect_only_left(self, message: &str) -> L {
if let Left(l) = self {
l
} else {
panic!("{message}")
}
}
pub fn expect_right(self, message: &str) -> R {
match self {
Right(r) | Both(_, r) => r,
Left(_) => panic!("{message}"),
}
}
pub fn expect_only_right(self, message: &str) -> R {
if let Right(r) = self {
r
} else {
panic!("{message}")
}
}
pub fn expect_both(self, message: &str) -> (L, R) {
if let Both(l, r) = self {
(l, r)
} else {
panic!("{message}")
}
}
#[inline]
pub fn unwrap_left(self) -> L {
self.expect_left("unwrap_left called on Right")
}
#[inline]
pub fn unwrap_only_left(self) -> L {
self.expect_only_left("unwrap_only_left called on Right or Both")
}
#[inline]
pub fn unwrap_right(self) -> R {
self.expect_right("unwrap_right called on Left")
}
#[inline]
pub fn unwrap_only_right(self) -> R {
self.expect_only_right("unwrap_only_right called on Left or Both")
}
#[inline]
pub fn unwrap_both(self) -> (L, R) {
self.expect_both("unwrap_both called on Left or Right")
}
pub fn unwrap_left_or_default(self) -> L
where
L: Default,
{
match self {
Left(l) | Both(l, _) => l,
Right(_) => L::default(),
}
}
pub fn unwrap_only_left_or_default(self) -> L
where
L: Default,
{
match self {
Left(l) => l,
_ => L::default(),
}
}
pub fn unwrap_right_or_default(self) -> R
where
R: Default,
{
match self {
Right(r) | Both(_, r) => r,
Left(_) => R::default(),
}
}
pub fn unwrap_only_right_or_default(self) -> R
where
R: Default,
{
match self {
Right(r) => r,
_ => R::default(),
}
}
pub fn unwrap_both_or_default(self) -> (L, R)
where
L: Default,
R: Default,
{
match self {
Left(l) => (l, R::default()),
Right(r) => (L::default(), r),
Both(l, r) => (l, r),
}
}
pub fn unwrap_only_both_or_default(self) -> (L, R)
where
L: Default,
R: Default,
{
match self {
Both(l, r) => (l, r),
_ => Default::default(),
}
}
#[inline]
pub fn map<L2, R2, LF, RF>(self, left: LF, right: RF) -> Either<L2, R2>
where
LF: FnOnce(L) -> L2,
RF: FnOnce(R) -> R2,
{
match self {
Left(l) => Left(left(l)),
Right(r) => Right(right(r)),
Both(l, r) => Both(left(l), right(r)),
}
}
#[inline]
pub fn map_left<L2, F>(self, f: F) -> Either<L2, R>
where
F: FnOnce(L) -> L2,
{
self.map(f, identity)
}
#[inline]
pub fn map_right<R2, F>(self, f: F) -> Either<L, R2>
where
F: FnOnce(R) -> R2,
{
self.map(identity, f)
}
pub fn inspect<LF, RF>(self, left: LF, right: RF) -> Self
where
LF: FnOnce(&L),
RF: FnOnce(&R),
{
match self {
Left(ref l) => left(l),
Right(ref r) => right(r),
Both(ref l, ref r) => {
left(l);
right(r);
}
}
self
}
#[inline]
pub fn inspect_left<F>(self, f: F) -> Self
where
F: FnOnce(&L),
{
self.inspect(f, noop1)
}
pub fn inspect_only_left<F>(self, f: F) -> Self
where
F: FnOnce(&L),
{
if let Left(ref l) = self {
f(l);
}
self
}
#[inline]
pub fn inspect_right<F>(self, f: F) -> Self
where
F: FnOnce(&R),
{
self.inspect(noop1, f)
}
pub fn inspect_only_right<F>(self, f: F) -> Self
where
F: FnOnce(&R),
{
if let Right(ref r) = self {
f(r);
}
self
}
pub fn inspect_both<F>(self, f: F) -> Self
where
F: FnOnce(&L, &R),
{
if let Both(ref l, ref r) = self {
f(l, r);
}
self
}
pub fn fill_left(self, left: L) -> Either<L, R> {
match self {
Left(l) => Left(l),
Right(r) => Both(left, r),
Both(l, r) => Both(l, r),
}
}
pub fn fill_left_lazy<F>(self, f: F) -> Either<L, R>
where
F: FnOnce() -> L,
{
match self {
Left(l) => Left(l),
Right(r) => Both(f(), r),
Both(l, r) => Both(l, r),
}
}
pub fn fill_right(self, right: R) -> Either<L, R> {
match self {
Left(l) => Both(l, right),
Right(r) => Right(r),
Both(l, r) => Both(l, r),
}
}
pub fn fill_right_lazy<F>(self, f: F) -> Either<L, R>
where
F: FnOnce() -> R,
{
match self {
Left(l) => Both(l, f()),
Right(r) => Right(r),
Both(l, r) => Both(l, r),
}
}
#[inline]
pub const fn is_left(&self) -> bool {
matches!(self, Left(_))
}
#[inline]
pub const fn is_right(&self) -> bool {
matches!(self, Right(_))
}
#[inline]
pub const fn is_both(&self) -> bool {
matches!(self, Both(_, _))
}
#[inline]
pub const fn has_left(&self) -> bool {
matches!(self, Left(_) | Both(_, _))
}
#[inline]
pub const fn has_right(&self) -> bool {
matches!(self, Right(_) | Both(_, _))
}
pub fn has_left_and<F>(&self, f: F) -> bool
where
F: FnOnce(&L) -> bool,
{
match self {
Self::Left(l) | Self::Both(l, _) => f(l),
Self::Right(_) => false,
}
}
pub fn is_left_and<F>(&self, f: F) -> bool
where
F: FnOnce(&L) -> bool,
{
if let Left(l) = self { f(l) } else { false }
}
pub fn has_right_and<F>(&self, f: F) -> bool
where
F: FnOnce(&R) -> bool,
{
match self {
Self::Right(r) | Self::Both(_, r) => f(r),
Self::Left(_) => false,
}
}
pub fn is_right_and<F>(&self, f: F) -> bool
where
F: FnOnce(&R) -> bool,
{
if let Right(r) = self { f(r) } else { false }
}
pub fn is_both_and<F>(&self, f: F) -> bool
where
F: FnOnce(&L, &R) -> bool,
{
if let Both(l, r) = self {
f(l, r)
} else {
false
}
}
pub fn has_left_or<F>(&self, f: F) -> bool
where
F: FnOnce(&R) -> bool,
{
match self {
Left(_) | Both(_, _) => true,
Right(r) => f(r),
}
}
pub fn is_left_or<F>(&self, f: F) -> bool
where
F: FnOnce(&R) -> bool,
{
match self {
Left(_) => true,
Right(r) | Both(_, r) => f(r),
}
}
pub fn has_right_or<F>(&self, f: F) -> bool
where
F: FnOnce(&L) -> bool,
{
match self {
Right(_) | Both(_, _) => true,
Left(l) => f(l),
}
}
pub fn is_right_or<F>(&self, f: F) -> bool
where
F: FnOnce(&L) -> bool,
{
match self {
Left(l) | Both(l, _) => f(l),
Right(_) => true,
}
}
pub fn swap(self) -> Either<R, L> {
match self {
Left(l) => Right(l),
Right(r) => Left(r),
Both(l, r) => Both(r, l),
}
}
#[inline]
pub fn fold<T, F>(self, default_left: L, default_right: R, f: F) -> T
where
F: FnOnce(L, R) -> T,
{
self.fold_with(|| default_left, || default_right, f)
}
pub fn fold_with<T, F, DLF, DRF>(self, default_left: DLF, default_right: DRF, f: F) -> T
where
F: FnOnce(L, R) -> T,
DLF: FnOnce() -> L,
DRF: FnOnce() -> R,
{
let (left, right) = match self {
Left(l) => (l, default_right()),
Right(r) => (default_left(), r),
Both(l, r) => (l, r),
};
f(left, right)
}
#[inline]
const fn count_usize(&self) -> usize {
if self.is_both() { 2 } else { 1 }
}
}
impl<L, R> Either<&L, R> {
pub fn left_copied(self) -> Either<L, R>
where
L: Copy,
{
match self {
Left(&l) => Left(l),
Right(r) => Right(r),
Both(&l, r) => Both(l, r),
}
}
#[inline]
pub fn left_cloned(self) -> Either<L, R>
where
L: Clone,
{
self.map_left(|l| l.clone())
}
}
impl<L, R> Either<L, &R> {
pub fn right_copied(self) -> Either<L, R>
where
R: Copy,
{
match self {
Left(l) => Left(l),
Right(&r) => Right(r),
Both(l, &r) => Both(l, r),
}
}
#[inline]
pub fn right_cloned(self) -> Either<L, R>
where
R: Clone,
{
self.map_right(|r| r.clone())
}
}
impl<L, R> Either<&L, &R> {
pub const fn copied(self) -> Either<L, R>
where
L: Copy,
R: Copy,
{
match self {
Left(&l) => Left(l),
Right(&r) => Right(r),
Both(&l, &r) => Both(l, r),
}
}
#[inline]
pub fn cloned(self) -> Either<L, R>
where
L: Clone,
R: Clone,
{
self.map(Clone::clone, Clone::clone)
}
}
impl<L, R> Either<&mut L, R> {
pub fn left_copied(self) -> Either<L, R>
where
L: Copy,
{
match self {
Left(&mut l) => Left(l),
Right(r) => Right(r),
Both(&mut l, r) => Both(l, r),
}
}
#[inline]
pub fn left_cloned(self) -> Either<L, R>
where
L: Clone,
{
self.map_left(|l| l.clone())
}
}
impl<L, R> Either<L, &mut R> {
pub fn right_copied(self) -> Either<L, R>
where
R: Copy,
{
match self {
Left(l) => Left(l),
Right(&mut r) => Right(r),
Both(l, &mut r) => Both(l, r),
}
}
#[inline]
pub fn right_cloned(self) -> Either<L, R>
where
R: Clone,
{
self.map_right(|r| r.clone())
}
}
impl<L, R> Either<&mut L, &mut R> {
pub const fn copied(self) -> Either<L, R>
where
L: Copy,
R: Copy,
{
match self {
Left(&mut l) => Left(l),
Right(&mut r) => Right(r),
Both(&mut l, &mut r) => Both(l, r),
}
}
#[inline]
pub fn cloned(self) -> Either<L, R>
where
L: Clone,
R: Clone,
{
self.map(|l| l.clone(), |r| r.clone())
}
}
impl<L, R> Either<Option<L>, Option<R>> {
pub fn transpose(self) -> MaybeEither<L, R> {
match self {
Left(None) | Right(None) | Both(None, None) => None,
Left(Some(l)) | Both(Some(l), None) => Some(Left(l)),
Right(Some(r)) | Both(None, Some(r)) => Some(Right(r)),
Both(Some(l), Some(r)) => Some(Both(l, r)),
}
}
}
impl<L, EL, R, ER> Either<Result<L, EL>, Result<R, ER>> {
pub fn transpose(self, prefer_ok: bool) -> Result<Either<L, R>, Either<EL, ER>> {
match self {
Left(Ok(l)) => Ok(Left(l)),
Left(Err(el)) => Err(Left(el)),
Right(Ok(r)) => Ok(Right(r)),
Right(Err(er)) => Err(Right(er)),
Both(Ok(l), Ok(r)) => Ok(Both(l, r)),
Both(Err(el), Err(er)) => Err(Both(el, er)),
Both(Ok(l), Err(er)) => {
if prefer_ok {
Ok(Left(l))
} else {
Err(Right(er))
}
}
Both(Err(el), Ok(r)) => {
if prefer_ok {
Ok(Right(r))
} else {
Err(Left(el))
}
}
}
}
}
impl<T> Either<T, T> {
pub fn total(self) -> T
where
T: Add<T, Output = T>,
{
match self {
Left(l) => l,
Right(r) => r,
Both(l, r) => l + r,
}
}
pub fn iter(&self) -> Iter<'_, T> {
Iter {
inner: Some(self.as_ref()),
}
}
}
pub struct Iter<'a, T> {
inner: MaybeEither<&'a T, &'a T>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self.inner {
None => None,
Some(Left(v)) | Some(Right(v)) => {
self.inner = None;
Some(v)
}
Some(Both(l, r)) => {
self.inner = Some(Right(r));
Some(l)
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.inner.as_ref().map(|e| e.count_usize()).unwrap_or(0);
(size, Some(size))
}
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
match self.inner {
None => None,
Some(Left(v)) | Some(Right(v)) => {
self.inner = None;
Some(v)
}
Some(Both(l, r)) => {
self.inner = Some(Left(l));
Some(r)
}
}
}
}
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
impl<'a, T> FusedIterator for Iter<'a, T> {}
impl<L, R> From<(L, R)> for Either<L, R> {
#[inline]
fn from((left, right): (L, R)) -> Self {
Self::Both(left, right)
}
}
#[inline]
const fn noop1<T>(_: &T) {}
#[cfg(feature = "either")]
mod either_interop;
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[rstest]
#[case(Left(()), Some(()))]
#[case(Right(()), None)]
#[case(Both((), ()), Some(()))]
fn test_left(#[case] variant: Either<(), ()>, #[case] expected: Option<()>) {
assert_eq!(variant.left(), expected);
}
#[rstest]
#[case(Left(()), Some(()))]
#[case(Right(()), None)]
#[case(Both((), ()), None)]
fn test_only_left(#[case] variant: Either<(), ()>, #[case] expected: Option<()>) {
assert_eq!(variant.only_left(), expected);
}
#[rstest]
#[case(Left(()), None)]
#[case(Right(()), Some(()))]
#[case(Both((), ()), Some(()))]
fn test_right(#[case] variant: Either<(), ()>, #[case] expected: Option<()>) {
assert_eq!(variant.right(), expected);
}
#[rstest]
#[case(Left(()), None)]
#[case(Right(()), Some(()))]
#[case(Both((), ()), None)]
fn test_only_right(#[case] variant: Either<(), ()>, #[case] expected: Option<()>) {
assert_eq!(variant.only_right(), expected);
}
#[rstest]
#[case(Left(()))]
#[case(Both((), ()))]
fn ok_test_unwrap_left(#[case] either: Either<(), ()>) {
either.unwrap_left()
}
#[test]
fn ok_test_unwrap_only_left() {
let left: Either<_, ()> = Left(());
left.unwrap_only_left()
}
#[rstest]
#[case(Right(()))]
#[case(Both((), ()))]
fn ok_test_unwrap_right(#[case] either: Either<(), ()>) {
either.unwrap_right()
}
#[test]
fn ok_test_unwrap_only_right() {
let right: Either<(), _> = Right(());
right.unwrap_only_right()
}
#[rstest]
#[case(Left(()))]
#[case(Both((), ()))]
fn ok_test_expect_left(#[case] either: Either<(), ()>) {
either.expect_left("left value to exist")
}
#[test]
fn ok_test_expect_only_left() {
let left: Either<_, ()> = Left(());
left.expect_only_left("only left value to exist")
}
#[rstest]
#[case(Right(()))]
#[case(Both((), ()))]
fn ok_test_expect_right(#[case] either: Either<(), ()>) {
either.expect_right("right value to exist")
}
#[test]
fn ok_test_expect_only_right() {
let right: Either<(), _> = Right(());
right.expect_only_right("only right value to exist")
}
#[test]
#[should_panic(expected = "unwrap_left called on Right")]
fn panic_test_unwrap_left() {
let right: Either<(), _> = Right(());
right.unwrap_left()
}
#[rstest]
#[case(Right(()))]
#[case(Both((), ()))]
#[should_panic(expected = "unwrap_only_left called on Right or Both")]
fn panic_test_unwrap_only_left(#[case] either: Either<(), ()>) {
either.unwrap_only_left()
}
#[test]
#[should_panic(expected = "unwrap_right called on Left")]
fn panic_test_unwrap_right() {
let left: Either<_, ()> = Left(());
left.unwrap_right()
}
#[rstest]
#[case(Left(()))]
#[case(Both((), ()))]
#[should_panic(expected = "unwrap_only_right called on Left or Both")]
fn panic_test_unwrap_only_right(#[case] either: Either<(), ()>) {
either.unwrap_only_right()
}
#[test]
#[should_panic(expected = "left value to exist")]
fn panic_test_expect_left() {
let right: Either<(), _> = Right(());
right.expect_left("left value to exist")
}
#[rstest]
#[case(Right(()))]
#[case(Both((), ()))]
#[should_panic(expected = "only left value to exist")]
fn panic_test_expect_only_left(#[case] either: Either<(), ()>) {
either.expect_only_left("only left value to exist")
}
#[test]
#[should_panic(expected = "right value to exist")]
fn panic_test_expect_right() {
let left: Either<_, ()> = Left(());
left.expect_right("right value to exist")
}
#[rstest]
#[case(Left(()))]
#[case(Both((), ()))]
#[should_panic(expected = "only right value to exist")]
fn panic_test_expect_only_right(#[case] either: Either<(), ()>) {
either.expect_only_right("only right value to exist")
}
#[rstest]
#[case(Left(1), Left(1))]
#[case(Right(2), Both(100, 2))]
#[case(Both(1, 2), Both(1, 2))]
fn test_fill_left(#[case] either: Either<u8, u8>, #[case] expected: Either<u8, u8>) {
assert_eq!(either.fill_left(100), expected);
}
#[rstest]
#[case(Left(1), Left(1))]
#[case(Right(2), Both(100, 2))]
#[case(Both(1, 2), Both(1, 2))]
fn test_fill_left_lazy(#[case] either: Either<u8, u8>, #[case] expected: Either<u8, u8>) {
assert_eq!(either.fill_left_lazy(|| 100), expected);
}
#[rstest]
#[case(Left(1), Both(1, 100))]
#[case(Right(2), Right(2))]
#[case(Both(1, 2), Both(1, 2))]
fn test_fill_right(#[case] either: Either<u8, u8>, #[case] expected: Either<u8, u8>) {
assert_eq!(either.fill_right(100), expected);
}
#[rstest]
#[case(Left(1), Both(1, 100))]
#[case(Right(2), Right(2))]
#[case(Both(1, 2), Both(1, 2))]
fn test_fill_right_lazy(#[case] either: Either<u8, u8>, #[case] expected: Either<u8, u8>) {
assert_eq!(either.fill_right_lazy(|| 100), expected);
}
#[rstest]
#[case(Left(()), true)]
#[case(Right(()), false)]
#[case(Both((), ()), false)]
fn test_is_left(#[case] either: Either<(), ()>, #[case] expected: bool) {
assert_eq!(either.is_left(), expected);
}
#[rstest]
#[case(Left(()), false)]
#[case(Right(()), true)]
#[case(Both((), ()), false)]
fn test_is_right(#[case] either: Either<(), ()>, #[case] expected: bool) {
assert_eq!(either.is_right(), expected);
}
#[rstest]
#[case(Left(()), false)]
#[case(Right(()), false)]
#[case(Both((), ()), true)]
fn test_is_both(#[case] either: Either<(), ()>, #[case] expected: bool) {
assert_eq!(either.is_both(), expected);
}
#[rstest]
#[case(Left(()), true)]
#[case(Right(()), false)]
#[case(Both((), ()), true)]
fn test_has_left(#[case] either: Either<(), ()>, #[case] expected: bool) {
assert_eq!(either.has_left(), expected);
}
#[rstest]
#[case(Left(()), false)]
#[case(Right(()), true)]
#[case(Both((), ()), true)]
fn test_has_right(#[case] either: Either<(), ()>, #[case] expected: bool) {
assert_eq!(either.has_right(), expected);
}
#[rstest]
#[case(Left(()), true, false)]
#[case(Right(()), false, true)]
#[case(Both((), ()), true, true)]
fn test_inspect(
#[case] either: Either<(), ()>,
#[case] should_call_left: bool,
#[case] should_call_right: bool,
) {
let mut left_called = false;
let mut right_called = false;
either.inspect(
|_| {
left_called = true;
},
|_| {
right_called = true;
},
);
assert_eq!(left_called, should_call_left);
assert_eq!(right_called, should_call_right);
}
#[rstest]
#[case(Left(()), true)]
#[case(Right(()), false)]
#[case(Both((), ()), true)]
fn test_inspect_left(#[case] either: Either<(), ()>, #[case] should_call: bool) {
let mut called = false;
either.inspect_left(|_| {
called = true;
});
assert_eq!(called, should_call);
}
#[rstest]
#[case(Left(()), true)]
#[case(Right(()), false)]
#[case(Both((), ()), false)]
fn test_inspect_only_left(#[case] either: Either<(), ()>, #[case] should_call: bool) {
let mut called = false;
either.inspect_only_left(|_| {
called = true;
});
assert_eq!(called, should_call);
}
#[rstest]
#[case(Left(()), false)]
#[case(Right(()), true)]
#[case(Both((), ()), true)]
fn test_inspect_right(#[case] either: Either<(), ()>, #[case] should_call: bool) {
let mut called = false;
either.inspect_right(|_| {
called = true;
});
assert_eq!(called, should_call);
}
#[rstest]
#[case(Left(()), false)]
#[case(Right(()), true)]
#[case(Both((), ()), false)]
fn test_inspect_only_right(#[case] either: Either<(), ()>, #[case] should_call: bool) {
let mut called = false;
either.inspect_only_right(|_| {
called = true;
});
assert_eq!(called, should_call);
}
#[rstest]
#[case(Left(()), false)]
#[case(Right(()), false)]
#[case(Both((), ()), true)]
fn test_inspect_both(#[case] either: Either<(), ()>, #[case] should_call: bool) {
let mut called = false;
either.inspect_both(|_, _| {
called = true;
});
assert_eq!(called, should_call);
}
}