How to implement a factory trait that returns common values ​​with a parameter of the appropriate type?

Consider the following code (simplified but compiled):

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 achieve something similar with a different signature?

Idea

The code in the question is simplified to reduce it to the main parts that I could not solve.

In general, Actor should have a mutable state that changes with processing messages (in this example, there is no process method). You can create an Actor and can communicate with it using ActorRef (there is no submit method in this example).

I want to allow different ways of "spawning" Actor . For instance. message processing can occur in one thread for each actor. Or, processing may be performed in a thread pool that is shared by other participants.

Other code may depend on the creation of other members. The underlying mechanism used should be abstracted. Since the trait is ActorSpawner .

My attempts to solve it

Suppose 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 this feature 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) } } 

leads to 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 other:

 struct DeadActorSpawner; impl ActorSpawner for DeadActorSpawner { fn spawn<Message,A,R>(actor: A) -> Arc<DeadRef> { Arc::new(DeadRef) } } 

leads to 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 tried many other things to no avail, including using related types for Message in Actor and ActorRef .

+5
source share
1 answer

Is it possible to implement ActorSpawner::spawn

Yes , but there is no useful implementation, as I see it

or to achieve something similar with a different signature

I believe you were expecting Arc<ActorRef<Message>> return. Thus, you can use DeadActorSpawner as an ActorSpawner , unaware of the Dead * types.

In fact, you tried to specialize the spawn function to return Arc<DeadRef> . I modified your ActorSpawner to return an object 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

+4
source

All Articles