Consider the following code (simplified but compilable):
use std::sync::Arc;
pub trait ActorRef<Message> { /* ... */ }
pub trait Actor<Message> { /* ... */ }
pub trait ActorSpawner {
/// Spawns a new actor returning an actor ref
/// for passing messages to it.
fn spawn<Message,A,R>(actor: A) -> Arc<R>
where R: ActorRef<Message>, A: Actor<Message>;
}
Is it possible to implement ActorSpawner::spawn
or to achieve something similar with another signature?
The code in the question is simplified to reduce it to the core parts that I couldn't solve.
In general, an Actor
should have mutable state which is changed by the processing messages (a process method is missing from the example). You can spawn an Actor
and can communicate with it via an ActorRef
(the send method is missing from the example).
I want to allow different ways of "spawning" an Actor
. E.g. the message processing might happen on one thread per actor. Or the processing might be done on a thread pool which is shared by other actors.
Other code might depend on creating further actors. The underlying mechanism used should be abstracted. Since the trait ActorSpawner
.
Let's assume that we have some dummy implementations for Actor
and ActorRef
:
struct NoopActor;
impl<Message> Actor<Message> for NoopActor {}
struct DeadRef;
impl<Message> ActorRef<Message> for DeadRef {}
It should now be possible to implement the trait somehow using these dummy implementations.
This is my first attempt:
struct DeadActorSpawner;
impl ActorSpawner for DeadActorSpawner {
fn spawn<Message,A,R>(actor: A) -> Arc<R>
where R: ActorRef<Message>, A: Actor<Message>
{
Arc::new(DeadRef)
}
}
resulting in this error:
error[E0308]: mismatched types
--> src/main.rs:29:18
|
29 | Arc::new(DeadRef)
| ^^^^^^^ expected type parameter, found struct `DeadRef`
|
= note: expected type `R`
found type `DeadRef`
Or another one:
struct DeadActorSpawner;
impl ActorSpawner for DeadActorSpawner {
fn spawn<Message,A,R>(actor: A) -> Arc<DeadRef>
{
Arc::new(DeadRef)
}
}
resulting in this error:
error[E0053]: method `spawn` has an incompatible type for trait
--> src/main.rs:25:42
|
12 | fn spawn<Message, A, R>(actor: A) -> Arc<R>
| ------ type in trait
...
25 | fn spawn<Message, A, R>(actor: A) -> Arc<DeadRef> {
| ^^^^^^^^^^^^ expected type parameter, found struct `DeadRef`
|
= note: expected type `fn(A) -> std::sync::Arc<R>`
found type `fn(A) -> std::sync::Arc<DeadRef>`
I have tried numerous other things to no avail including using associated types for the Message
in Actor
and ActorRef
.
Is it possible to implement
ActorSpawner::spawn
Yes, but there's no useful implementation as I see it
or to achieve something similar with another signature
I believe you were expecting an Arc<ActorRef<Message>>
to be returned. So you could use the DeadActorSpawner
through the ActorSpawner
trait without knowing about the Dead
* types.
What you actually did was to attempt to specialize the spawn
function to return an Arc<DeadRef>
. I modified your ActorSpawner
to return a trait-object:
pub trait ActorSpawner {
fn spawn<Message, A>(actor: A) -> Arc<ActorRef<Message>> where A: Actor<Message>;
}
struct DeadActorSpawner;
impl ActorSpawner for DeadActorSpawner {
fn spawn<Message, A>(actor: A) -> Arc<ActorRef<Message>>
where A: Actor<Message>
{
Arc::new(DeadRef)
}
}
Playground example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With