#![feature(tuple_trait)]
#![feature(unboxed_closures)]
#![feature(fn_traits)]
#![feature(generic_const_exprs)]
#![feature(const_trait_impl)]
use std::marker::{Tuple, PhantomData};
use tupleops::{ConcatTuples, TupleConcat, concat_tuples, TupleLength, TupleUnprepend, Head, Tail};
use tuple_split::{TupleSplit, SplitInto};
#[const_trait]
pub trait Compose<F, XG, XF>: Sized
{
fn compose(self, with: F) -> Composition<Self, F, XG, XF>;
}
impl<G, F, XG, XF> const Compose<F, XG, XF> for G
where
XG: Tuple + TupleUnprepend<XG>,
XF: Tuple,
Self: FnOnce<XG>,
F: FnOnce<XF, Output = Head<XG>>,
(Tail<XG>, XF): TupleConcat<Tail<XG>, XF>,
ConcatTuples<Tail<XG>, XF>: Tuple,
Composition<Self, F, XG, XF>: FnOnce<ConcatTuples<Tail<XG>, XF>>
{
fn compose(self, with: F) -> Composition<Self, F, XG, XF>
{
Composition {
g: self,
f: with,
phantom: PhantomData
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Composition<G, F, XG, XF>
{
g: G,
f: F,
phantom: PhantomData<(XG, XF)>,
}
impl<G, F, XG, XF> FnOnce<ConcatTuples<Tail<XG>, XF>> for Composition<G, F, XG, XF>
where
XG: Tuple + TupleUnprepend<XG>,
XF: Tuple,
G: FnOnce<XG>,
F: FnOnce<XF, Output = Head<XG>>,
(Tail<XG>, XF): TupleConcat<Tail<XG>, XF>,
ConcatTuples<Tail<XG>, XF>: Tuple + SplitInto<Tail<XG>, XF>,
[(); <Tail<XG> as TupleLength>::LENGTH]:,
((F::Output,), Tail<XG>): TupleConcat<(F::Output,), Tail<XG>, Type = XG>
{
type Output = <G as FnOnce<XG>>::Output;
extern "rust-call" fn call_once(self, args: ConcatTuples<Tail<XG>, XF>) -> Self::Output
{
let (left, right): (Tail<XG>, XF) = args.split_tuple();
self.g.call_once(concat_tuples((self.f.call_once(right),), left))
}
}
impl<G, F, XG, XF> FnMut<ConcatTuples<Tail<XG>, XF>> for Composition<G, F, XG, XF>
where
XG: Tuple + TupleUnprepend<XG>,
XF: Tuple,
G: FnMut<XG>,
F: FnMut<XF, Output = Head<XG>>,
(Tail<XG>, XF): TupleConcat<Tail<XG>, XF>,
ConcatTuples<Tail<XG>, XF>: Tuple + SplitInto<Tail<XG>, XF>,
[(); <Tail<XG> as TupleLength>::LENGTH]:,
((F::Output,), Tail<XG>): TupleConcat<(F::Output,), Tail<XG>, Type = XG>
{
extern "rust-call" fn call_mut(&mut self, args: ConcatTuples<Tail<XG>, XF>) -> Self::Output
{
let (left, right) = args.split_tuple();
self.g.call_mut(concat_tuples((self.f.call_mut(right),), left))
}
}
impl<G, F, XG, XF> Fn<ConcatTuples<Tail<XG>, XF>> for Composition<G, F, XG, XF>
where
XG: Tuple + TupleUnprepend<XG>,
XF: Tuple,
G: Fn<XG>,
F: Fn<XF, Output = Head<XG>>,
(Tail<XG>, XF): TupleConcat<Tail<XG>, XF>,
ConcatTuples<Tail<XG>, XF>: Tuple + SplitInto<Tail<XG>, XF>,
[(); <Tail<XG> as TupleLength>::LENGTH]:,
((F::Output,), Tail<XG>): TupleConcat<(F::Output,), Tail<XG>, Type = XG>
{
extern "rust-call" fn call(&self, args: ConcatTuples<Tail<XG>, XF>) -> Self::Output
{
let (left, right) = args.split_tuple();
self.g.call(concat_tuples((self.f.call(right),), left))
}
}