use std::marker::PhantomData; pub trait Query: Copy { type Output; } pub trait QueryConvert: Query { fn convert(e: E) -> Self::Output; } pub trait QueryEnrich: Query { fn enrich(&self, output: Self::Output, a: A) -> Self::Output; } pub trait QueryChain: Query { type Original: Query; fn original(&self) -> &Self::Original; } pub struct StartQuery(Q, PhantomData); impl Clone for StartQuery { fn clone(&self) -> Self { Self(self.0.clone(), PhantomData) } } impl Copy for StartQuery {} impl Query for StartQuery { type Output = Q::Output; } impl QueryChain for StartQuery { type Original = Q; fn original(&self) -> &Self::Original { &self.0 } } struct BootQuery; struct IgnoreQuery; impl QueryEnrich for StartQuery where Q: QueryEnrich, { fn enrich(&self, output: Self::Output, a: A) -> Self::Output { self.0.enrich(output, a) } } impl QueryEnrich for StartQuery { fn enrich(&self, output: Self::Output, _a: A) -> Self::Output { output } } impl QueryConvert for StartQuery where Q: QueryConvert, { fn convert(e: E) -> Self::Output { Q::convert(e) } } pub struct ChainQuery(Q, PhantomData); impl Clone for ChainQuery { fn clone(&self) -> Self { Self(self.0.clone(), PhantomData) } } impl Copy for ChainQuery {} impl Query for ChainQuery { type Output = Q::Output; } impl QueryChain for ChainQuery { type Original = Q::Original; fn original(&self) -> &Self::Original { self.0.original() } } impl> QueryEnrich for ChainQuery where Q: QueryEnrich, Q::Original: QueryEnrich, { fn enrich(&self, output: Self::Output, a: Ax) -> Self::Output { self.0.enrich(a.enrich(output, self.original()), a) } } impl QueryConvert for ChainQuery where Q::Original: QueryConvert, { fn convert(e: E) -> Self::Output { >::convert(e) } } trait QueryExt: Query { fn start(self) -> StartQuery { StartQuery(self, PhantomData) } fn enriching(self) -> ChainQuery where Self: QueryChain, Self::Original: QueryEnrich, { ChainQuery(self, PhantomData) } } impl QueryExt for Q {} pub trait Enriches { fn enrich( &self, output: Output, query: &impl QueryEnrich, ) -> Output; } pub trait QueryJoin: QueryEnrich<::Output> {} impl::Output>> QueryJoin for Q {}