Skip to content

Better choose API #28

@ebfull

Description

@ebfull

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions