summaryrefslogtreecommitdiff
path: root/src/lib.rs
blob: 7bd5342c2435a96e9f704ce38f9582140a71cfa0 (plain)
use varihappy_macros::{
	reverse_expr_type, reverse_tuple_type, tuple_expr_len_rest, tuple_expr_mut, tuple_expr_ref,
	tuple_type_len, tuple_type_len_rest,
};

pub trait Tuple {
	type AsRef<'a>: Tuple
	where
		Self: 'a;
	type AsMut<'a>: Tuple
	where
		Self: 'a;

	type Reversed: Tuple;

	fn as_ref(&self) -> Self::AsRef<'_>;
	fn as_mut(&mut self) -> Self::AsMut<'_>;
	fn rev(self) -> Self::Reversed;
}

pub trait Tuple1: Tuple {
	type Item0;
	type Rest: Tuple;

	fn into_0(self) -> Self::Item0;
	fn split_into(self) -> (Self::Item0, Self::Rest);
	fn into_rest(self) -> Self::Rest;
}

impl Tuple for () {
	type AsRef<'a>
		= ()
	where
		Self: 'a;
	type AsMut<'a>
		= ()
	where
		Self: 'a;

	type Reversed = ();

	fn as_ref(&self) -> Self::AsRef<'_> {}
	fn as_mut(&mut self) -> Self::AsMut<'_> {}
	fn rev(self) -> Self::Reversed {}
}

impl<A> Tuple for (A,) {
	type AsRef<'a>
		= (&'a A,)
	where
		Self: 'a;
	type AsMut<'a>
		= (&'a mut A,)
	where
		Self: 'a;

	type Reversed = (A,);

	fn as_ref(&self) -> Self::AsRef<'_> {
		(&self.0,)
	}
	fn as_mut(&mut self) -> Self::AsMut<'_> {
		(&mut self.0,)
	}
	fn rev(self) -> Self::Reversed {
		self
	}
}

impl<A> Tuple1 for (A,) {
	type Item0 = A;
	type Rest = ();

	fn into_0(self) -> Self::Item0 {
		self.0
	}

	fn split_into(self) -> (Self::Item0, <Self as Tuple1>::Rest) {
		(self.0, ())
	}

	fn into_rest(self) -> Self::Rest {}
}

macro_rules! impl_tuple {
	($length: expr; $($letter: ident),*) => {
		impl<$($letter),*> Tuple for tuple_type_len!($length) {
			type AsRef<'a> = ($(&'a $letter,)*) where Self: 'a;
			type AsMut<'a> = ($(&'a mut $letter,)*) where Self: 'a;
			type Reversed =  reverse_tuple_type!($length);

			fn as_ref(&self) -> Self::AsRef<'_> {
				tuple_expr_ref!($length)
			}

			fn as_mut(&mut self) -> Self::AsMut<'_> {
				tuple_expr_mut!($length)
			}

			fn rev(self) -> Self::Reversed {
				reverse_expr_type!($length)
			}
		}

		impl<$($letter),*> Tuple1 for tuple_type_len!($length) {
			type Item0 = A;
			type Rest = tuple_type_len_rest!($length);

			fn into_0(self) -> Self::Item0 {
				self.0
			}
			fn split_into(self) -> (Self::Item0, Self::Rest) {
				(self.0, tuple_expr_len_rest!($length))
			}

			fn into_rest(self) -> Self::Rest {
				tuple_expr_len_rest!($length)
			}
		}
	};
}

impl_tuple!(2; A, B);
impl_tuple!(3; A, B, C);
impl_tuple!(4; A, B, C, D);
impl_tuple!(5; A, B, C, D, E);
impl_tuple!(6; A, B, C, D, E, F);
impl_tuple!(7; A, B, C, D, E, F, G);
impl_tuple!(8; A, B, C, D, E, F, G, H);
impl_tuple!(9; A, B, C, D, E, F, G, H, I);
impl_tuple!(10; A, B, C, D, E, F, G, H, I, J);
impl_tuple!(11; A, B, C, D, E, F, G, H, I, J, K);
impl_tuple!(12; A, B, C, D, E, F, G, H, I, J, K, L);
impl_tuple!(13; A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_tuple!(14; A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_tuple!(15; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_tuple!(16; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
impl_tuple!(17; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
impl_tuple!(18; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
impl_tuple!(19; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
impl_tuple!(20; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
impl_tuple!(21; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
impl_tuple!(22; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
impl_tuple!(23; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
impl_tuple!(24; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
impl_tuple!(25; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y);
impl_tuple!(26; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);

macro_rules! tuple_trait {
	(trait $trait_name: ident for $trait_minus1: ident {
		type $item_name: ident;
		fn $item_getter: ident;
	}) => {
		pub trait $trait_name: $trait_minus1 {
			type $item_name;
			type Rest: Tuple;

			fn $item_getter(self) -> Self::$item_name;
			fn into_rest(self) -> <Self as $trait_name>::Rest;
		}

		impl<R: Tuple1, T: $trait_minus1<Rest = R>> $trait_name for T {
			type $item_name = R::Item0;
			type Rest = R::Rest;

			fn $item_getter(self) -> Self::$item_name {
				$trait_minus1::into_rest(self).into_0()
			}

			fn into_rest(self) -> <Self as $trait_name>::Rest {
				$trait_minus1::into_rest(self).into_rest()
			}
		}
	};
}

tuple_trait!(trait Tuple2 for Tuple1 { type Item1; fn into_1; });
tuple_trait!(trait Tuple3 for Tuple2 { type Item2; fn into_2; });
tuple_trait!(trait Tuple4 for Tuple3 { type Item3; fn into_3; });
tuple_trait!(trait Tuple5 for Tuple4 { type Item4; fn into_4; });
tuple_trait!(trait Tuple6 for Tuple5 { type Item5; fn into_5; });
tuple_trait!(trait Tuple7 for Tuple6 { type Item6; fn into_6; });
tuple_trait!(trait Tuple8 for Tuple7 { type Item7; fn into_7; });
tuple_trait!(trait Tuple9 for Tuple8 { type Item8; fn into_8; });
tuple_trait!(trait Tuple10 for Tuple9 { type Item9; fn into_9; });
tuple_trait!(trait Tuple11 for Tuple10 { type Item10; fn into_10; });
tuple_trait!(trait Tuple12 for Tuple11 { type Item11; fn into_11; });
tuple_trait!(trait Tuple13 for Tuple12 { type Item12; fn into_12; });
tuple_trait!(trait Tuple14 for Tuple13 { type Item13; fn into_13; });
tuple_trait!(trait Tuple15 for Tuple14 { type Item14; fn into_14; });
tuple_trait!(trait Tuple16 for Tuple15 { type Item15; fn into_15; });
tuple_trait!(trait Tuple17 for Tuple16 { type Item16; fn into_16; });
tuple_trait!(trait Tuple18 for Tuple17 { type Item17; fn into_17; });
tuple_trait!(trait Tuple19 for Tuple18 { type Item18; fn into_18; });
tuple_trait!(trait Tuple20 for Tuple19 { type Item19; fn into_19; });
tuple_trait!(trait Tuple21 for Tuple20 { type Item20; fn into_20; });
tuple_trait!(trait Tuple22 for Tuple21 { type Item21; fn into_21; });
tuple_trait!(trait Tuple23 for Tuple22 { type Item22; fn into_22; });
tuple_trait!(trait Tuple24 for Tuple23 { type Item23; fn into_23; });
tuple_trait!(trait Tuple25 for Tuple24 { type Item24; fn into_24; });
tuple_trait!(trait Tuple26 for Tuple25 { type Item25; fn into_25; });