-
Notifications
You must be signed in to change notification settings - Fork 24
Description
Right now the path down a Choose
style decision tree is formed by signaling with booleans over the channel, which is not (space) efficient. Further, you must use macros to avoid having to do a bunch of annoying compositions to select the branches you want.
Here's an alternative API which unfortunately requires Rust nightly, but (somehow) works:
#![feature(optin_builtin_traits)]
use std::marker::PhantomData;
trait ChooseFrom { }
impl<Q> ChooseFrom for Finally<Q> {}
impl<P, Q: ChooseFrom> ChooseFrom for Choose<P, Q> {}
struct Finally<Q>(PhantomData<Q>);
struct Choose<P, Q: ChooseFrom>(PhantomData<(P, Q)>);
struct Compound<A, B>(PhantomData<(A, B)>);
trait NotSame { }
impl NotSame for .. { }
impl<A> !NotSame for Compound<A, A> { }
trait Chooser<T> {
fn num() -> usize;
}
impl<P, Q: ChooseFrom> Chooser<P> for Choose<P, Q> {
fn num() -> usize { 0 }
}
impl<P> Chooser<P> for Finally<P> {
fn num() -> usize { 0 }
}
impl<P, S, Q: ChooseFrom + Chooser<S>> Chooser<S> for Choose<P, Q>
where Compound<S, P>: NotSame {
fn num() -> usize { 1 + Q::num() }
}
impl<P, Q: ChooseFrom> Choose<P, Q> {
fn choose<S>(&self) -> usize where Self: Chooser<S> {
Self::num()
}
}
fn main() {
let a: Choose<usize, Choose<isize, Choose<String, Finally<()>>>> = Choose(PhantomData);
println!("{:?}", a.choose::<String>());
}
Basically, in theory you can just call chan.choose::<Protocol>()
and it will signal over the channel that you're switching to that protocol using a single number. Perhaps if there's a monomorphization recursion limit anyway, we could use u8 or u16 instead of usize to make the discriminant as small as possible. (Safety note: if the number wraps around it will cause memory safety violations. Perhaps we can use peano numbers to encode a maximum limit here.)
Also, I believe with inlining LLVM will completely optimize this away.