use crate::{tuple, tuple_t, Tuple, TupleLike, Unit};
use std::ops::{Add, Deref, DerefMut, Mul};
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::borrow::ToOwned;
pub trait Poppable: TupleLike {
type PopFrontOutput: TupleLike;
type PopFrontElement;
type PopBackOutput: TupleLike;
type PopBackElement;
fn pop(self) -> (Self::PopBackOutput, Self::PopBackElement);
fn pop_front(self) -> (Self::PopFrontOutput, Self::PopFrontElement);
fn pop_back(self) -> (Self::PopBackOutput, Self::PopBackElement)
where
Self: Sized,
{
Poppable::pop(self)
}
}
impl<First, Other> Poppable for Tuple<First, Other>
where
Other: Poppable,
{
type PopFrontOutput = Other;
type PopFrontElement = First;
type PopBackOutput = Tuple<First, Other::PopBackOutput>;
type PopBackElement = Other::PopBackElement;
fn pop(self) -> (Self::PopBackOutput, Self::PopBackElement) {
let (tup, elem) = Poppable::pop(self.1);
(Tuple(self.0, tup), elem)
}
fn pop_front(self) -> (Self::PopFrontOutput, Self::PopFrontElement) {
(self.1, self.0)
}
}
impl<First> Poppable for Tuple<First, Unit> {
type PopFrontOutput = Unit;
type PopFrontElement = First;
type PopBackOutput = Unit;
type PopBackElement = First;
fn pop(self) -> (Self::PopBackOutput, Self::PopBackElement) {
(Unit, self.0)
}
fn pop_front(self) -> (Self::PopFrontOutput, Self::PopFrontElement) {
(Unit, self.0)
}
}
pub trait Rotatable: TupleLike {
type RotLeftOutput: TupleLike;
type RotRightOutput: TupleLike;
fn rot_l(self) -> Self::RotLeftOutput;
fn rot_r(self) -> Self::RotRightOutput;
}
impl Rotatable for Unit {
type RotLeftOutput = Unit;
type RotRightOutput = Unit;
fn rot_l(self) -> Unit {
self
}
fn rot_r(self) -> Unit {
self
}
}
impl<First, Other> Rotatable for Tuple<First, Other>
where
Other: TupleLike,
Self: Poppable,
{
type RotLeftOutput = Other::PushBackOutput<First>;
type RotRightOutput =
Tuple<<Self as Poppable>::PopBackElement, <Self as Poppable>::PopBackOutput>;
fn rot_l(self) -> Self::RotLeftOutput {
let Tuple(first, other) = self;
other.push(first)
}
fn rot_r(self) -> Self::RotRightOutput {
let (out, elem) = Poppable::pop(self);
Tuple(elem, out)
}
}
pub trait Cloned: TupleLike {
type ClonedOutput: TupleLike;
fn cloned(&self) -> Self::ClonedOutput;
}
impl Cloned for Unit {
type ClonedOutput = Unit;
fn cloned(&self) -> Self::ClonedOutput {
Self
}
}
impl<First, Other> Cloned for Tuple<&First, Other>
where
First: Clone,
Other: Cloned,
{
type ClonedOutput = Tuple<First, Other::ClonedOutput>;
fn cloned(&self) -> Self::ClonedOutput {
Tuple(Clone::clone(self.0), Cloned::cloned(&self.1))
}
}
impl<First, Other> Cloned for Tuple<&mut First, Other>
where
First: Clone,
Other: Cloned,
{
type ClonedOutput = Tuple<First, Other::ClonedOutput>;
fn cloned(&self) -> Self::ClonedOutput {
Tuple(Clone::clone(self.0), Cloned::cloned(&self.1))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
pub trait Owned: TupleLike {
type OwnedOutput: TupleLike;
fn owned(&self) -> Self::OwnedOutput;
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl Owned for Unit {
type OwnedOutput = Unit;
fn owned(&self) -> Self::OwnedOutput {
Self
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<First, Other> Owned for Tuple<&First, Other>
where
First: ToOwned + ?Sized,
Other: Owned,
{
type OwnedOutput = Tuple<First::Owned, Other::OwnedOutput>;
fn owned(&self) -> Self::OwnedOutput {
Tuple(ToOwned::to_owned(self.0), Owned::owned(&self.1))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<First, Other> Owned for Tuple<&mut First, Other>
where
First: ToOwned + ?Sized,
Other: Owned,
{
type OwnedOutput = Tuple<First::Owned, Other::OwnedOutput>;
fn owned(&self) -> Self::OwnedOutput {
Tuple(ToOwned::to_owned(self.0), Owned::owned(&self.1))
}
}
pub trait Copied: TupleLike {
type CopiedOutput: TupleLike;
fn copied(&self) -> Self::CopiedOutput;
}
impl Copied for Unit {
type CopiedOutput = Unit;
fn copied(&self) -> Self::CopiedOutput {
Self
}
}
impl<First, Other> Copied for Tuple<&First, Other>
where
First: Copy,
Other: Copied,
{
type CopiedOutput = Tuple<First, Other::CopiedOutput>;
fn copied(&self) -> Self::CopiedOutput {
Tuple(*self.0, Copied::copied(&self.1))
}
}
impl<First, Other> Copied for Tuple<&mut First, Other>
where
First: Copy,
Other: Copied,
{
type CopiedOutput = Tuple<First, Other::CopiedOutput>;
fn copied(&self) -> Self::CopiedOutput {
Tuple(*self.0, Copied::copied(&self.1))
}
}
pub trait Enumerable: TupleLike {
type EnumerateOutput: TupleLike;
fn enumerate(self, from: usize) -> Self::EnumerateOutput;
}
impl Enumerable for Unit {
type EnumerateOutput = Unit;
fn enumerate(self, _: usize) -> Self::EnumerateOutput {
Unit
}
}
impl<First, Other> Enumerable for Tuple<First, Other>
where
Other: Enumerable,
{
type EnumerateOutput = Tuple<(usize, First), Other::EnumerateOutput>;
fn enumerate(self, from: usize) -> Self::EnumerateOutput {
Tuple((from, self.0), Enumerable::enumerate(self.1, from + 1))
}
}
pub trait AsDeref: TupleLike {
type AsDerefOutput<'a>: TupleLike
where
Self: 'a;
fn as_deref(&self) -> Self::AsDerefOutput<'_>;
}
impl AsDeref for Unit {
type AsDerefOutput<'a> = Unit;
fn as_deref(&self) -> Self::AsDerefOutput<'_> {
Unit
}
}
impl<First, Other> AsDeref for Tuple<First, Other>
where
First: Deref,
Other: AsDeref,
{
type AsDerefOutput<'a> = Tuple<&'a First::Target, Other::AsDerefOutput<'a>> where Self: 'a;
fn as_deref(&self) -> Self::AsDerefOutput<'_> {
Tuple(self.0.deref(), AsDeref::as_deref(&self.1))
}
}
pub trait AsDerefMut: TupleLike {
type AsDerefMutOutput<'a>: TupleLike
where
Self: 'a;
fn as_deref_mut(&mut self) -> Self::AsDerefMutOutput<'_>;
}
impl AsDerefMut for Unit {
type AsDerefMutOutput<'a> = Unit;
fn as_deref_mut(&mut self) -> Self::AsDerefMutOutput<'_> {
Unit
}
}
impl<First, Other> AsDerefMut for Tuple<First, Other>
where
First: DerefMut,
Other: AsDerefMut,
{
type AsDerefMutOutput<'a> = Tuple<&'a mut First::Target, Other::AsDerefMutOutput<'a>> where Self: 'a;
fn as_deref_mut(&mut self) -> Self::AsDerefMutOutput<'_> {
Tuple(self.0.deref_mut(), AsDerefMut::as_deref_mut(&mut self.1))
}
}
pub trait Untupleable: TupleLike {
type UntupleOutput: TupleLike;
fn untuple(self) -> Self::UntupleOutput;
}
impl Untupleable for Unit {
type UntupleOutput = Unit;
fn untuple(self) -> Self::UntupleOutput {
self
}
}
impl<First, Other> Untupleable for Tuple<First, Other>
where
First: TupleLike,
Other: Untupleable,
{
type UntupleOutput = First::JoinOutput<Other::UntupleOutput>;
fn untuple(self) -> Self::UntupleOutput {
self.0.join(Untupleable::untuple(self.1))
}
}
pub trait Dot<T = Self> {
type Output;
fn dot(self, rhs: T) -> Self::Output;
}
impl Dot for Unit {
type Output = Unit;
fn dot(self, _: Self) -> Self::Output {
Self
}
}
impl<First1, Other1, First2, Other2> Dot<Tuple<First2, Other2>> for Tuple<First1, Other1>
where
First1: Mul<First2>,
Other1: Dot<Other2> + TupleLike,
Other2: TupleLike,
<Other1 as Dot<Other2>>::Output: Add<<First1 as Mul<First2>>::Output>,
{
type Output = <<Other1 as Dot<Other2>>::Output as Add<<First1 as Mul<First2>>::Output>>::Output;
fn dot(self, rhs: Tuple<First2, Other2>) -> Self::Output {
Dot::dot(self.1, rhs.1) + self.0 * rhs.0
}
}
impl<'a, First1, Other1, First2, Other2> Dot<&'a Tuple<First2, Other2>> for Tuple<First1, Other1>
where
First1: Mul<&'a First2>,
Other1: Dot<&'a Other2> + TupleLike,
Other2: TupleLike,
<Other1 as Dot<&'a Other2>>::Output: Add<<First1 as Mul<&'a First2>>::Output>,
{
type Output =
<<Other1 as Dot<&'a Other2>>::Output as Add<<First1 as Mul<&'a First2>>::Output>>::Output;
fn dot(self, rhs: &'a Tuple<First2, Other2>) -> Self::Output {
Dot::dot(self.1, &rhs.1) + self.0 * &rhs.0
}
}
impl<'a, First1, Other1, First2, Other2> Dot<Tuple<First2, Other2>> for &'a Tuple<First1, Other1>
where
&'a First1: Mul<First2>,
&'a Other1: Dot<Other2>,
Other1: TupleLike,
Other2: TupleLike,
<&'a Other1 as Dot<Other2>>::Output: Add<<&'a First1 as Mul<First2>>::Output>,
{
type Output =
<<&'a Other1 as Dot<Other2>>::Output as Add<<&'a First1 as Mul<First2>>::Output>>::Output;
fn dot(self, rhs: Tuple<First2, Other2>) -> Self::Output {
Dot::dot(&self.1, rhs.1) + &self.0 * rhs.0
}
}
impl<'a, 'b, First1, Other1, First2, Other2> Dot<&'a Tuple<First2, Other2>>
for &'b Tuple<First1, Other1>
where
&'b First1: Mul<&'a First2>,
&'b Other1: Dot<&'a Other2>,
Other1: TupleLike,
Other2: TupleLike,
<&'b Other1 as Dot<&'a Other2>>::Output: Add<<&'b First1 as Mul<&'a First2>>::Output>,
{
type Output = <<&'b Other1 as Dot<&'a Other2>>::Output as Add<
<&'b First1 as Mul<&'a First2>>::Output,
>>::Output;
fn dot(self, rhs: &'a Tuple<First2, Other2>) -> Self::Output {
Dot::dot(&self.1, &rhs.1) + &self.0 * &rhs.0
}
}
pub trait Zippable<T>: TupleLike {
type ZipOutput: TupleLike;
type ZipOutput2: TupleLike;
fn zip(self, rhs: T) -> Self::ZipOutput;
fn zip2(self, rhs: T) -> Self::ZipOutput2;
}
impl Zippable<Unit> for Unit {
type ZipOutput = Unit;
type ZipOutput2 = Unit;
fn zip(self, _: Unit) -> Self::ZipOutput {
self
}
fn zip2(self, _: Unit) -> Self::ZipOutput2 {
self
}
}
impl<First1, Other1, First2, Other2> Zippable<Tuple<First2, Other2>> for Tuple<First1, Other1>
where
Other1: Zippable<Other2>,
Other2: TupleLike,
{
type ZipOutput = Tuple<tuple_t!(First1, First2), Other1::ZipOutput>;
type ZipOutput2 = Tuple<(First1, First2), Other1::ZipOutput2>;
fn zip(self, rhs: Tuple<First2, Other2>) -> Self::ZipOutput {
Tuple(tuple!(self.0, rhs.0), Zippable::zip(self.1, rhs.1))
}
fn zip2(self, rhs: Tuple<First2, Other2>) -> Self::ZipOutput2 {
Tuple((self.0, rhs.0), Zippable::zip2(self.1, rhs.1))
}
}
pub trait Unzippable: TupleLike {
type UnzipOutputLeft: TupleLike;
type UnzipOutputRight: TupleLike;
fn unzip(self) -> (Self::UnzipOutputLeft, Self::UnzipOutputRight);
}
impl Unzippable for Unit {
type UnzipOutputLeft = Unit;
type UnzipOutputRight = Unit;
fn unzip(self) -> (Self::UnzipOutputLeft, Self::UnzipOutputRight) {
(self, self)
}
}
impl<FirstLeft, FirstRight, Other> Unzippable
for Tuple<Tuple<FirstLeft, Tuple<FirstRight, Unit>>, Other>
where
Other: Unzippable,
{
type UnzipOutputLeft = Tuple<FirstLeft, Other::UnzipOutputLeft>;
type UnzipOutputRight = Tuple<FirstRight, Other::UnzipOutputRight>;
fn unzip(self) -> (Self::UnzipOutputLeft, Self::UnzipOutputRight) {
let Tuple(left, Tuple(right, ..)) = self.0;
let (lefts, rights) = Unzippable::unzip(self.1);
(Tuple(left, lefts), Tuple(right, rights))
}
}
impl<FirstLeft, FirstRight, Other> Unzippable for Tuple<(FirstLeft, FirstRight), Other>
where
Other: Unzippable,
{
type UnzipOutputLeft = Tuple<FirstLeft, Other::UnzipOutputLeft>;
type UnzipOutputRight = Tuple<FirstRight, Other::UnzipOutputRight>;
fn unzip(self) -> (Self::UnzipOutputLeft, Self::UnzipOutputRight) {
let (left, right) = self.0;
let (lefts, rights) = Unzippable::unzip(self.1);
(Tuple(left, lefts), Tuple(right, rights))
}
}
pub trait Extendable<T>: TupleLike {
type ExtendFrontOutput: TupleLike;
type ExtendBackOutput: TupleLike;
fn extend(self, rhs: T) -> Self::ExtendBackOutput;
fn extend_front(self, rhs: T) -> Self::ExtendFrontOutput;
fn extend_back(self, rhs: T) -> Self::ExtendBackOutput
where
Self: Sized,
{
Extendable::extend(self, rhs)
}
}
impl Extendable<Unit> for Unit {
type ExtendFrontOutput = Unit;
type ExtendBackOutput = Unit;
fn extend(self, _: Unit) -> Self::ExtendBackOutput {
self
}
fn extend_front(self, _: Unit) -> Self::ExtendFrontOutput {
self
}
}
impl<First1, Other1, First2, Other2> Extendable<Tuple<First2, Other2>> for Tuple<First1, Other1>
where
First1: TupleLike,
Other1: Extendable<Other2>,
{
type ExtendFrontOutput = Tuple<First1::PushFrontOutput<First2>, Other1::ExtendFrontOutput>;
type ExtendBackOutput = Tuple<First1::PushBackOutput<First2>, Other1::ExtendBackOutput>;
fn extend(self, rhs: Tuple<First2, Other2>) -> Self::ExtendBackOutput {
Tuple(self.0.push(rhs.0), Extendable::extend(self.1, rhs.1))
}
fn extend_front(self, rhs: Tuple<First2, Other2>) -> Self::ExtendFrontOutput {
Tuple(
self.0.push_front(rhs.0),
Extendable::extend_front(self.1, rhs.1),
)
}
}
pub trait Shrinkable: TupleLike {
type ShrinkFrontOutput: TupleLike;
type ShrinkFrontElements: TupleLike;
type ShrinkBackOutput: TupleLike;
type ShrinkBackElements: TupleLike;
fn shrink(self) -> (Self::ShrinkBackOutput, Self::ShrinkBackElements);
fn shrink_front(self) -> (Self::ShrinkFrontOutput, Self::ShrinkFrontElements);
fn shrink_back(self) -> (Self::ShrinkBackOutput, Self::ShrinkBackElements)
where
Self: Sized,
{
Shrinkable::shrink(self)
}
}
impl Shrinkable for Unit {
type ShrinkFrontOutput = Unit;
type ShrinkFrontElements = Unit;
type ShrinkBackOutput = Unit;
type ShrinkBackElements = Unit;
fn shrink(self) -> (Unit, Unit) {
(self, self)
}
fn shrink_front(self) -> (Self::ShrinkFrontOutput, Self::ShrinkFrontElements) {
(self, self)
}
}
impl<First, Other> Shrinkable for Tuple<First, Other>
where
First: Poppable,
Other: Shrinkable,
{
type ShrinkFrontOutput = Tuple<First::PopFrontOutput, Other::ShrinkFrontOutput>;
type ShrinkFrontElements = Tuple<First::PopFrontElement, Other::ShrinkFrontElements>;
type ShrinkBackOutput = Tuple<First::PopBackOutput, Other::ShrinkBackOutput>;
type ShrinkBackElements = Tuple<First::PopBackElement, Other::ShrinkBackElements>;
fn shrink(self) -> (Self::ShrinkBackOutput, Self::ShrinkBackElements) {
let (first, elem) = Poppable::pop(self.0);
let (other, elems) = Shrinkable::shrink(self.1);
(Tuple(first, other), Tuple(elem, elems))
}
fn shrink_front(self) -> (Self::ShrinkFrontOutput, Self::ShrinkFrontElements) {
let (first, elem) = Poppable::pop_front(self.0);
let (other, elems) = Shrinkable::shrink_front(self.1);
(Tuple(first, other), Tuple(elem, elems))
}
}
pub trait Combinable<T>: TupleLike {
type CombineOutput: TupleLike;
fn combine(self, rhs: T) -> Self::CombineOutput;
}
impl Combinable<Unit> for Unit {
type CombineOutput = Unit;
fn combine(self, _: Unit) -> Unit {
self
}
}
impl<First1, Other1, First2, Other2> Combinable<Tuple<First2, Other2>> for Tuple<First1, Other1>
where
First1: TupleLike,
First2: TupleLike,
Other1: Combinable<Other2>,
{
type CombineOutput = Tuple<First1::JoinOutput<First2>, Other1::CombineOutput>;
fn combine(self, rhs: Tuple<First2, Other2>) -> Self::CombineOutput {
Tuple(self.0.join(rhs.0), Combinable::combine(self.1, rhs.1))
}
}
pub trait HeadReplaceable<T: TupleLike>: TupleLike {
type ReplaceOutput: TupleLike;
type Replaced: TupleLike;
fn replace_head(self, rhs: T) -> (Self::ReplaceOutput, Self::Replaced);
}
impl<T> HeadReplaceable<Unit> for T
where
Self: TupleLike,
{
type ReplaceOutput = Self;
type Replaced = Unit;
fn replace_head(self, rhs: Unit) -> (Self::ReplaceOutput, Self::Replaced) {
(self, rhs)
}
}
impl<First1, Other1, First2, Other2> HeadReplaceable<Tuple<First2, Other2>>
for Tuple<First1, Other1>
where
Other1: HeadReplaceable<Other2>,
Other2: TupleLike,
{
type ReplaceOutput = Tuple<First2, Other1::ReplaceOutput>;
type Replaced = Tuple<First1, Other1::Replaced>;
fn replace_head(self, rhs: Tuple<First2, Other2>) -> (Self::ReplaceOutput, Self::Replaced) {
let (output, replaced) = HeadReplaceable::replace_head(self.1, rhs.1);
(Tuple(rhs.0, output), Tuple(self.0, replaced))
}
}
pub struct PhantomClone;
pub struct PhantomMut;
pub trait Callable<T, P>: TupleLike {
type Output: TupleLike;
fn call(&self, rhs: T) -> Self::Output;
}
impl<T, P> Callable<T, P> for Unit {
type Output = Unit;
fn call(&self, _: T) -> Self::Output {
Unit
}
}
impl<T, R, First, Other> Callable<T, PhantomClone> for Tuple<First, Other>
where
T: Clone,
First: Fn(T) -> R,
Other: Callable<T, PhantomClone>,
{
type Output = Tuple<R, Other::Output>;
fn call(&self, rhs: T) -> Self::Output {
Tuple((self.0)(rhs.clone()), Callable::call(&self.1, rhs))
}
}
impl<'a, T, R, First, Other> Callable<&'a mut T, PhantomMut> for Tuple<First, Other>
where
First: Fn(&mut T) -> R,
R: 'a,
Other: Callable<&'a mut T, PhantomMut>,
{
type Output = Tuple<R, <Other as Callable<&'a mut T, PhantomMut>>::Output>;
fn call(&self, rhs: &'a mut T) -> Self::Output {
Tuple((self.0)(&mut *rhs), Callable::call(&self.1, &mut *rhs))
}
}
pub trait MutCallable<T, P>: TupleLike {
type Output: TupleLike;
fn call_mut(&mut self, rhs: T) -> Self::Output;
}
impl<T, P> MutCallable<T, P> for Unit {
type Output = Unit;
fn call_mut(&mut self, _: T) -> Self::Output {
Unit
}
}
impl<T, R, First, Other> MutCallable<T, PhantomClone> for Tuple<First, Other>
where
T: Clone,
First: FnMut(T) -> R,
Other: MutCallable<T, PhantomClone>,
{
type Output = Tuple<R, Other::Output>;
fn call_mut(&mut self, rhs: T) -> Self::Output {
Tuple(
(self.0)(rhs.clone()),
MutCallable::call_mut(&mut self.1, rhs),
)
}
}
impl<'a, T, R, First, Other> MutCallable<&'a mut T, PhantomMut> for Tuple<First, Other>
where
First: FnMut(&mut T) -> R,
R: 'a,
Other: MutCallable<&'a mut T, PhantomMut>,
{
type Output = Tuple<R, <Other as MutCallable<&'a mut T, PhantomMut>>::Output>;
fn call_mut(&mut self, rhs: &'a mut T) -> Self::Output {
Tuple(
(self.0)(&mut *rhs),
MutCallable::call_mut(&mut self.1, &mut *rhs),
)
}
}
pub trait OnceCallable<T, P>: TupleLike {
type Output: TupleLike;
fn call_once(self, rhs: T) -> Self::Output;
}
impl<T, P> OnceCallable<T, P> for Unit {
type Output = Unit;
fn call_once(self, _: T) -> Self::Output {
Unit
}
}
impl<T, R, First, Other> OnceCallable<T, PhantomClone> for Tuple<First, Other>
where
T: Clone,
First: FnOnce(T) -> R,
Other: OnceCallable<T, PhantomClone>,
{
type Output = Tuple<R, Other::Output>;
fn call_once(self, rhs: T) -> Self::Output {
Tuple((self.0)(rhs.clone()), OnceCallable::call_once(self.1, rhs))
}
}
impl<'a, T, R, First, Other> OnceCallable<&'a mut T, PhantomMut> for Tuple<First, Other>
where
First: FnOnce(&mut T) -> R,
R: 'a,
Other: OnceCallable<&'a mut T, PhantomMut>,
{
type Output = Tuple<R, <Other as OnceCallable<&'a mut T, PhantomMut>>::Output>;
fn call_once(self, rhs: &'a mut T) -> Self::Output {
Tuple(
(self.0)(&mut *rhs),
OnceCallable::call_once(self.1, &mut *rhs),
)
}
}