I gave this (in particular Question 2) a go, too (without looking at previous comments while implementing this) and I guess my approach is a bit different.
This is what I got so far as proof of concept. Next step would be to add the methods to the traits.
trait PushLeftTo<List> {
type Pushed;
//fn push_left_to(self, l: List) -> Self::Pushed;
}
pub struct A<T>(pub T);
impl PushLeftTo<()> for () {
type Pushed = ();
}
impl<T> PushLeftTo<()> for A<T> {
type Pushed = A<T>;
}
impl<S> PushLeftTo<A<S>> for () {
type Pushed = A<S>;
}
impl<S, T> PushLeftTo<A<S>> for A<T> {
type Pushed = (A<T>, A<S>);
}
impl<X, Y> PushLeftTo<(X, Y)> for () {
type Pushed = (X, Y);
}
impl<X, Y, T> PushLeftTo<(X, Y)> for A<T> {
type Pushed = (A<T>, (X, Y));
}
trait SplitTupleLeftPushableTo<List> {
type Init: PushLeftTo<<Self::Last as PushLeftTo<List>>::Pushed>;
type Last: PushLeftTo<List>;
//fn split_tuple(self) -> (Self::Init, Self::Last);
}
impl<Tup, List> PushLeftTo<List> for Tup
where
Tup: SplitTupleLeftPushableTo<List>,
{
type Pushed = <<Self as SplitTupleLeftPushableTo<List>>::Init as PushLeftTo<
<<Self as SplitTupleLeftPushableTo<List>>::Last as PushLeftTo<List>>::Pushed,
>>::Pushed;
}
macro_rules! split_tuple {
($Last:ident $(, $($T:ident),+$(,)?)?) => {
impl<$($($T,)+)? $Last, List> SplitTupleLeftPushableTo<List> for ($($($T,)+)? $Last,)
where
$Last: PushLeftTo<List>,
($($($T,)+)?): PushLeftTo<$Last::Pushed>,
{
type Init = ($($($T,)+)?);
type Last = $Last;
}
}
}
split_tuple!(T1);
split_tuple!(T2, T1);
split_tuple!(T3, T1, T2);
split_tuple!(T4, T1, T2, T3);
split_tuple!(T5, T1, T2, T3, T4);
split_tuple!(T6, T1, T2, T3, T4, T5);
split_tuple!(T7, T1, T2, T3, T4, T5, T6);
split_tuple!(T8, T1, T2, T3, T4, T5, T6, T7);
trait IntoRightLeaning {
type Output;
//fn into_right_leaning(self) -> Self::Output;
}
impl<T> IntoRightLeaning for T
where T: PushLeftTo<()> {
type Output = T::Pushed;
}
/*
()
((), ())
(A<u32>, ())
((), ((), A<String>))
((A<f64>, A<i64>), A<char>)
((), (((), (((), A<bool>), ())), A<f32>))
*/
fn main() {
println!("Hello, world!");
macro_rules! type_for {
($t:ty) => {
println!("{}", std::any::type_name::<<$t as IntoRightLeaning>::Output>());
}
}
type_for!(());
type_for!(((), ()));
type_for!((A<u32>, ()));
type_for!(((), ((), A<String>)));
type_for!(((A<f64>, A<i64>), A<char>));
type_for!(((), (((), (((), A<bool>), ())), A<f32>)));
}
Hello, world!
()
()
crate_name::A<u32>
crate_name::A<alloc::string::String>
(crate_name::A<f64>, (crate_name::A<i64>, crate_name::A<char>))
(crate_name::A<bool>, crate_name::A<f32>)
Edit: And here’s the missing methods added: Rust Playground
Edit2: Simplified by removing support for longer tuples: Rust Playground