I'm building an event-driven abstraction which can be minimized like this
use std::marker::PhantomData;
trait OnEvent<M> {}
trait SendEvent<M> {}
impl<E: SendEvent<M> + ?Sized, M> SendEvent<M> for Box<E> {}
struct Sender<S>(PhantomData<S>);
// type inference is somehow broken if I don't include this into the example
struct Session<S>(PhantomData<S>);
impl<S> Session<S> {
fn sender(&self) -> Sender<S> {
Sender(Default::default())
}
fn run(&self, state: S) {}
}
impl<S: OnEvent<M>, M> SendEvent<M> for Sender<S> {}
struct State<E> {
sender: E
}
struct Event;
impl<E: SendEvent<Event>> OnEvent<Event> for State<E> {}
I would like the state type S
instead of event type M
to show up in the sender so I can perform type erasure on the event type (which is not the type erasure I'm discussing in this post). The state holds a sender, which may or may not send to itself, and it may send Event
through this sender while handling an incoming Event
. In this post we focus on the case when it is actually sending to itself. In practice there are also cases where states send to each other in a circle, which leads to similar situation.
Obviously if I naively put these pieces together, cyclic type will fail the compilation (although the confusing compilation error starts with error[E0308]: mismatched types
fn main() {
let session = Session(Default::default());
let state = State { sender: session.sender() };
session.run(state) // cyclic type of infinite size
}
The go to solution would be breaking the circle with trait object
fn main() {
let session = Session(Default::default());
let state = State {
sender: Box::new(session.sender()) as Box<dyn SendEvent<Event>>
};
session.run(state)
}
(And add the corresponded blanket implementation of SendEvent
for Box<_>
.) In this case state
will be State<Box<dyn SendEvent<event>>>
. This has been what I am doing.
Just now I came up with the idea of use impl _
to replace Box<dyn _>
so I can save some nonsense runtime overhead. Sadly it does not work
fn main() {
let session = Session(Default::default());
// cannot write `State<impl SendEvent<Event>>` for now so use this to workaround
fn into_impl(sender: impl SendEvent<Event>) -> impl SendEvent<Event> {
sender
}
let state = State { sender: into_impl(session.sender()) }; // cyclic type of infinite size
session.run(state)
}
Interestingly the error is reported earlier, though I don't know why.
I don't see a reason why impl type theoretically not works here. As long as I can erase the concrete type into its behavior compiler should be happy, since all it cares for resolving trait implementation is the behavior. However, this error seems to indicate that impl type is only hiding the concrete type to me, not to compiler.
Should I expect impl type to work for type erasure soon or later?