use crate::{Quote,HNil,HCons};
pub fn calc<Expr,Quotes>(q:Quotes)->Expr::Result
where Expr:Calc<Quotes> {
<Expr as Calc<Quotes>>::calc(q)
}
pub trait Eval {
type Result;
}
pub trait Calc<Quotes> {
type Result;
fn calc(q:Quotes)->Self::Result;
}
impl<T> Eval for Quote<T> {
type Result = T;
}
impl<T:Eval> Eval for std::marker::PhantomData<T> {
type Result = T::Result;
}
impl<T,U> Calc<U> for std::marker::PhantomData<T> {
type Result = Self;
#[inline(always)]
fn calc(_:U)->Self { std::marker::PhantomData }
}
impl<Src: Into<Dest>, Dest> Calc<Src> for Quote<Dest> {
type Result = Dest;
#[inline(always)]
fn calc(t:Src)->Dest { t.into() }
}
pub trait EvalList {
type Result;
}
macro_rules! eval_list { ($exprs:ty) => { <$exprs as EvalList>::Result }}
pub trait CalcList<Quotes> {
type Result;
fn calc_list(q:Quotes)->Self::Result;
}
impl EvalList for HNil {
type Result = HNil;
}
impl CalcList<HNil> for HNil {
type Result = HNil;
#[inline(always)]
fn calc_list(_:HNil)->HNil { HNil }
}
impl<H:Eval, T:EvalList> EvalList for HCons<H,T> {
type Result = HCons<H::Result, eval_list!{T}>;
}
impl<QH, QT, H, T> CalcList<HCons<QH,QT>> for HCons<H,T>
where H: Calc<QH>,
T: CalcList< QT > {
type Result = HCons<H::Result, T::Result>;
#[inline(always)]
fn calc_list(q: HCons<QH,QT>) -> HCons<H::Result, T::Result> {
HCons { head: H::calc(q.head),
tail: T::calc_list(q.tail)
}
}
}
impl<H:Eval, T> Eval for HCons<H,T>
where H::Result: Call,
<H::Result as Call>::Conv: CallImpl<H::Result, T> {
type Result = <<H::Result as Call>::Conv as CallImpl<H::Result, T>>::Result;
}
impl<H:Calc<QH>, T, QH, QT> Calc<HCons<QH,QT>> for HCons<H,T>
where H::Result: Call,
<H::Result as Call>::Conv: CalcImpl<H::Result, T, QT>,
{
type Result = <<H::Result as Call>::Conv as CalcImpl<H::Result, T, QT>>::Result;
#[inline(always)]
fn calc(q:HCons<QH, QT>)->Self::Result {
let func = H::calc(q.head);
<H::Result as Call>::Conv::calc_impl(func, q.tail)
}
}
pub mod cc {
pub struct Func;
pub struct Syntax;
}
pub trait Call {
type Conv;
}
pub trait FunCall< Args >: Call<Conv=cc::Func> {
type Result;
}
pub trait FunCalc< Args >: Sized {
type Result;
fn calc(self, args:Args)->Self::Result;
}
pub trait SynCall< Args >: Call<Conv=cc::Syntax> {
type Result;
}
pub trait CallImpl<F, Args> {
type Result;
}
pub trait CalcImpl<F, Args, Q> {
type Result;
fn calc_impl(func:F, q:Q)->Self::Result;
}
impl<F, Args:EvalList> CallImpl<F, Args> for cc::Func
where F:FunCall< eval_list!{Args} > {
type Result = <F as FunCall< eval_list!{Args}>>::Result;
}
impl<F, Args:CalcList<Q>, Q> CalcImpl<F, Args, Q> for cc::Func
where F: FunCalc< Args::Result > {
type Result = <F as FunCalc< Args::Result >>::Result;
#[inline(always)]
fn calc_impl(func:F, q:Q)->Self::Result {
let args = Args::calc_list(q);
func.calc(args)
}
}
impl<F, Args> CallImpl<F, Args> for cc::Syntax
where F:SynCall< Args > {
type Result = <F as SynCall< Args>>::Result;
}
impl<F, Args, Q> CalcImpl<F, Args, Q> for cc::Syntax
where F:SynCalc< Args, Q > {
type Result = <F as SynCalc<Args, Q>>::Result;
#[inline(always)]
fn calc_impl(func:F, quotes:Q)->Self::Result {
func.syn_calc(quotes)
}
}
pub trait SynCalc< Args, Q > {
type Result;
fn syn_calc(self, quotes:Q) -> Self::Result;
}