#![no_std]
pub mod concepts;
pub mod either;
pub mod both;
use core::ops::{Add, Not, Shr, Sub};
pub use crate::{
any_of_x::{AnyOf16, AnyOf4, AnyOf8},
both::BothOf,
concepts::{Any, Couple, LeftOrRight, Map, Pair, Swap, Unwrap},
either::EitherOf,
either::EitherOf::{Left, Right},
AnyOf::{Both, Either, Neither},
};
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub enum AnyOf<L, R = L> {
Neither,
Either(EitherOf<L, R>),
Both(BothOf<L, R>),
}
impl<L, R> AnyOf<L, R> {
pub fn new(left: Option<L>, right: Option<R>) -> Self {
match (left, right) {
(None, None) => Neither,
(Some(l), None) => Either(Left(l)),
(None, Some(r)) => Either(Right(r)),
(Some(l), Some(r)) => Both(BothOf { left: l, right: r }),
}
}
pub fn new_neither() -> Self {
Self::new(None, None)
}
pub fn new_left(left: L) -> Self {
Self::new(Some(left), None)
}
pub fn new_right(right: R) -> Self {
Self::new(None, Some(right))
}
pub fn new_both(l: L, r: R) -> Self {
Self::new(Some(l), Some(r))
}
pub fn from_both(both: BothOf<L, R>) -> Self {
Self::new(Some(both.left), Some(both.right))
}
pub fn from_any(any: Any<L, R>) -> Self {
Self::new(any.0, any.1)
}
pub fn from_either(either: EitherOf<L, R>) -> Self {
Either(either)
}
pub fn into_both(self) -> BothOf<L, R> {
match self {
Both(b) => b,
_ => panic!("Can only convert Either::Both to Both"),
}
}
pub fn into_either(self) -> EitherOf<L, R> {
if let Either(e) = self {
e
} else {
panic!("Can only convert Either::Either to Either");
}
}
pub fn to_either_pair(&self) -> Pair<Option<EitherOf<L, R>>>
where
L: Clone,
R: Clone,
{
let both = self.any();
let left = both.0.map(|l| Left(l.clone()));
let right = both.1.map(|r| Right(r.clone()));
(left, right)
}
pub fn has_left(&self) -> bool {
matches!(self, Either(Left(_)) | Both(_))
}
pub fn has_right(&self) -> bool {
matches!(self, Either(Right(_)) | Both(_))
}
pub fn is_any(&self) -> bool {
matches!(self, Either(Left(_)) | Either(Right(_)) | Both(_))
}
pub fn is_either(&self) -> bool {
matches!(self, Either(_))
}
pub fn is_both(&self) -> bool {
matches!(self, Both(_))
}
pub fn is_neither(&self) -> bool {
matches!(self, Neither)
}
pub fn is_neither_or_both(&self) -> bool {
matches!(self, Neither | Both(_))
}
pub fn both_or_none(&self) -> Option<Couple<&L, &R>> {
Some((self.left()?, self.right()?))
}
pub fn both_or_else(self, f: impl FnOnce() -> BothOf<L, R>) -> BothOf<L, R> {
match self {
Neither => f(),
Either(Left(l)) => BothOf::new(l, f().right),
Either(Right(r)) => BothOf::new(f().left, r),
Both(b) => b,
}
}
pub fn both_or(self, other: BothOf<L, R>) -> BothOf<L, R> {
self.both_or_else(|| other)
}
pub fn unwrap_both(self) -> BothOf<L, R> {
self.both_or_else(|| panic!("Can only unwrap both of Either::Both"))
}
pub fn filter_left(self) -> Self {
match self {
Neither => Neither,
Either(Left(l)) => Either(Left(l)),
Either(Right(_)) => Neither,
Both(BothOf { left: l, .. }) => Either(Left(l)),
}
}
pub fn filter_right(self) -> Self {
match self {
Neither => Neither,
Either(Left(_)) => Neither,
Either(Right(r)) => Either(Right(r)),
Both(BothOf { right: r, .. }) => Either(Right(r)),
}
}
pub fn with_right(self, right: R) -> Self {
match self {
Neither => Either(Right(right)),
Either(Left(l)) => Both(BothOf { left: l, right }),
Either(Right(_)) => Either(Right(right)),
Both(BothOf { left: l, .. }) => Both(BothOf { left: l, right }),
}
}
pub fn with_left(self, left: L) -> Self {
match self {
Neither => Either(Left(left)),
Either(Left(_)) => Either(Left(left)),
Either(Right(r)) => Both(BothOf { left, right: r }),
Both(BothOf { right: r, .. }) => Both(BothOf { left, right: r }),
}
}
pub fn combine(self, other: Self) -> Self {
match self {
Neither => other,
Either(Left(l)) => match other {
Neither => Either(Left(l)),
Either(Left(_)) => Either(Left(l)),
Either(Right(r)) => Both(BothOf { left: l, right: r }),
Both(BothOf { right: r, .. }) => Both(BothOf { left: l, right: r }),
},
Either(Right(r)) => match other {
Neither => Either(Right(r)),
Either(Left(l)) => Both(BothOf { left: l, right: r }),
Either(Right(r2)) => Either(Right(r2)),
Both(BothOf { left: l, .. }) => Both(BothOf { left: l, right: r }),
},
Both(b) => Both(b),
}
}
pub fn filter(self, other: Self) -> Self {
match other {
Neither => self,
Either(Left(_)) => match self {
Either(Left(_)) => Neither,
Either(Right(r)) => Either(Right(r)),
Both(BothOf { right: r, .. }) => Either(Right(r)),
_ => self,
},
Either(Right(_)) => match self {
Either(Left(l)) => Either(Left(l)),
Either(Right(_)) => Neither,
Both(BothOf { left: l, .. }) => Either(Left(l)),
_ => self,
},
Both(_) => Neither,
}
}
}
impl<L, R> Add for AnyOf<L, R> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
self.combine(rhs)
}
}
impl<L, R> Sub for AnyOf<L, R> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
self.filter(rhs)
}
}
impl<L, R> Not for AnyOf<L, R> {
type Output = AnyOf<R, L>;
fn not(self) -> Self::Output {
match self {
Neither => AnyOf::<R, L>::Neither,
Either(e) => AnyOf::<R, L>::Either(e.swap()),
Both(b) => AnyOf::<R, L>::Both(b.swap()),
}
}
}
impl<L, R> Swap<L, R> for AnyOf<L, R> {
type Output = <Self as Not>::Output;
}
impl<L, R> LeftOrRight<L, R> for AnyOf<L, R> {
fn left(&self) -> Option<&L> {
match self {
Neither => None,
Either(e) => e.left(),
Both(b) => b.left(),
}
}
fn right(&self) -> Option<&R> {
match self {
Neither => None,
Either(e) => e.right(),
Both(b) => b.right(),
}
}
}
impl<L, R> Map<L, R> for AnyOf<L, R> {
type Output<L2, R2> = AnyOf<L2, R2>;
fn map<FL, FR, L2, R2>(self, fl: FL, fr: FR) -> Self::Output<L2, R2>
where
FL: FnOnce(L) -> L2,
FR: FnOnce(R) -> R2
{
self >> (fl, fr).into()
}
}
impl<L, R> Unwrap<L, R> for AnyOf<L, R> {
fn left_or_else(self, f: impl FnOnce() -> L) -> L {
match self {
Neither => f(),
Either(Left(l)) => l,
Either(Right(_)) => f(),
Both(BothOf { left: l, .. }) => l,
}
}
fn right_or_else(self, f: impl FnOnce() -> R) -> R {
match self {
Neither => f(),
Either(Left(_)) => f(),
Either(Right(r)) => r,
Both(BothOf { right: r, .. }) => r,
}
}
}
impl<L, R, FL, FR, L2, R2> Shr<BothOf<FL, FR>> for AnyOf<L, R>
where
FL: FnOnce(L) -> L2,
FR: FnOnce(R) -> R2,
{
type Output = AnyOf<L2, R2>;
fn shr(self, rhs: BothOf<FL, FR>) -> Self::Output {
match self {
Neither => AnyOf::<L2, R2>::Neither,
Either(e) => AnyOf::<L2, R2>::Either(e >> rhs),
Both(b) => AnyOf::<L2, R2>::Both(b >> rhs),
}
}
}
pub mod conversions;
pub mod any_of_x;
#[cfg(test)]
mod tests;