use std::ops::Add;
pub use len::*;
pub mod len {
#[cfg(feature = "len-generic")]
use super::TupleY;
macro_rules! impl_trait {
($trait:ident; $($tt:tt)*) => {
#[cfg(feature = "len-generic")]
impl<T: TupleY, const LEN: usize> $trait<LEN> for T where
[(); $($tt)*]: {}
};
}
pub trait TupleLenEq<const LEN: usize> {}
pub trait TupleLenGe<const LEN: usize> {}
pub trait TupleLenGt<const LEN: usize> {}
pub trait TupleLenLe<const LEN: usize> {}
pub trait TupleLenLt<const LEN: usize> {}
pub trait TupleLenRange<const LEFT: usize, const RIGHT: usize> {}
#[cfg(feature = "len-generic")]
impl<T: TupleY> TupleLenEq<{ Self::LEN }> for T {}
impl_trait!(TupleLenGe; Self::LEN - LEN);
impl_trait!(TupleLenGt; Self::LEN - LEN - 1);
impl_trait!(TupleLenLe; LEN - Self::LEN);
impl_trait!(TupleLenLt; LEN - 1 - Self::LEN);
#[rustfmt::skip]
#[cfg(feature = "len-generic")]
impl<T: TupleY, const LEFT: usize, const RIGHT: usize> TupleLenRange<LEFT, RIGHT> for T where
T: TupleLenGe<LEFT> + TupleLenLt<RIGHT>, {}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Tuple<First, Tail>(pub First, pub Tail);
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Unit;
pub trait NonEmptyTuple: TupleY {}
pub trait EmptyTuple: TupleY {}
impl<First, Tail: TupleY> NonEmptyTuple for Tuple<First, Tail> {}
impl EmptyTuple for Unit {}
pub trait TupleY: Sized {
const LEN: usize;
type PushBackOutput<T>;
type PushFrontOutput<T>;
type AsRefOutput<'a>
where
Self: 'a;
type AsMutOutput<'a>
where
Self: 'a;
type ToSomeOutput;
type ToOkOutput<E>;
#[inline]
fn is_empty(&self) -> bool {
Self::LEN == 0
}
#[inline]
fn len(&self) -> usize {
Self::LEN
}
fn push_back<T>(self, value: T) -> Self::PushBackOutput<T>;
fn push_front<T>(self, value: T) -> Self::PushFrontOutput<T>;
fn as_ref(&self) -> Self::AsRefOutput<'_>;
fn as_mut(&mut self) -> Self::AsMutOutput<'_>;
fn to_some(self) -> Self::ToSomeOutput;
fn to_ok<E>(self) -> Self::ToOkOutput<E>;
}
impl<First, Tail: TupleY> TupleY for Tuple<First, Tail> {
const LEN: usize = <Tail as TupleY>::LEN + 1;
type PushBackOutput<T> = Tuple<First, Tail::PushBackOutput<T>>;
type PushFrontOutput<T> = Tuple<T, Self>;
type AsRefOutput<'a> = Tuple<&'a First, Tail::AsRefOutput<'a>> where Self: 'a;
type AsMutOutput<'a> = Tuple<&'a mut First, Tail::AsMutOutput<'a>> where Self: 'a;
type ToSomeOutput = Tuple<Option<First>, Tail::ToSomeOutput>;
type ToOkOutput<E> = Tuple<Result<First, E>, Tail::ToOkOutput<E>>;
fn push_back<T>(self, value: T) -> Self::PushBackOutput<T> {
Tuple(self.0, self.1.push_back(value))
}
fn push_front<T>(self, value: T) -> Self::PushFrontOutput<T> {
Tuple(value, self)
}
fn as_ref(&self) -> Self::AsRefOutput<'_> {
Tuple(&self.0, self.1.as_ref())
}
fn as_mut(&mut self) -> Self::AsMutOutput<'_> {
Tuple(&mut self.0, self.1.as_mut())
}
fn to_some(self) -> Self::ToSomeOutput {
Tuple(Some(self.0), self.1.to_some())
}
fn to_ok<E>(self) -> Self::ToOkOutput<E> {
Tuple(Ok(self.0), self.1.to_ok())
}
}
impl TupleY for Unit {
const LEN: usize = 0;
type PushBackOutput<T> = Tuple<T, Unit>;
type PushFrontOutput<T> = Tuple<T, Unit>;
type AsRefOutput<'a> = Unit;
type AsMutOutput<'a> = Unit;
type ToSomeOutput = Unit;
type ToOkOutput<E> = Unit;
fn push_back<T>(self, value: T) -> Self::PushBackOutput<T> {
Tuple(value, Unit)
}
fn push_front<T>(self, value: T) -> Self::PushFrontOutput<T> {
Tuple(value, Unit)
}
fn as_ref(&self) -> Self::AsRefOutput<'_> {
Unit
}
fn as_mut(&mut self) -> Self::AsMutOutput<'_> {
Unit
}
fn to_some(self) -> Self::ToSomeOutput {
Unit
}
fn to_ok<E>(self) -> Self::ToOkOutput<E> {
Unit
}
}
impl<Rhs> Add<Rhs> for Unit
where
Rhs: TupleY,
{
type Output = Rhs;
fn add(self, rhs: Rhs) -> Rhs {
rhs
}
}
impl<First, Tail, Rhs> Add<Rhs> for Tuple<First, Tail>
where
Rhs: TupleY,
Tail: Add<Rhs>,
{
type Output = Tuple<First, <Tail as Add<Rhs>>::Output>;
fn add(self, rhs: Rhs) -> Self::Output {
Tuple(self.0, self.1 + rhs)
}
}