Skip to main content

acktor_ipc/remote_actor/
factory.rs

1use std::marker::PhantomData;
2
3use acktor::{Actor, Address, BoxError, JoinHandle, Recipient};
4
5use super::RemoteActor;
6use crate::remote_message::RemoteMessage;
7
8/// Extends [`RemoteActor`] with the ability to be spawned on demand by peers.
9///
10/// Implementing this trait opts an actor into peer-initiated creation. [`TYPE_NAME`]
11/// is the type identifier the peer sends in the `CreateActor` messsage.
12///
13/// [`TYPE_NAME`]: RemoteActorFactory::TYPE_NAME
14pub trait RemoteActorFactory: RemoteActor {
15    /// The type name of this actor.
16    ///
17    /// [`std::any::type_name`] is not guaranteed to be stable across Rust versions so we require users to provide their own stable type name.
18    const TYPE_NAME: &'static str;
19
20    /// Creates an instance of this actor with the given label and configuration string.
21    ///
22    /// Implementations typically call [`Actor::create`] or [`Actor::run`] internally and return
23    /// the actor address and the join handle.
24    fn create_remote(
25        label: String,
26        config: String,
27    ) -> Result<(Address<Self>, JoinHandle<()>), <Self as Actor>::Error>;
28}
29
30/// Dyn-compatible shim stored inside a [`Node`][crate::Node]'s factory map.
31///
32/// [`RemoteActorFactory`] itself is not dyn-compatible because of the `Actor` supertrait.
33/// This trait returns a recipient so the node can store factories as trait objects.
34pub(crate) trait DynRemoteActorFactory: Send + Sync + 'static {
35    fn create_remote(
36        &self,
37        label: String,
38        config: String,
39    ) -> Result<(Recipient<RemoteMessage>, JoinHandle<()>), BoxError>;
40}
41
42/// Zero-sized generic adapter that bridges a [`RemoteActorFactory`] impl into the
43/// dyn-compatible [`DynRemoteActorFactory`] trait object.
44pub(crate) struct RemoteActorShim<A>(pub(crate) PhantomData<fn() -> A>);
45
46impl<A> DynRemoteActorFactory for RemoteActorShim<A>
47where
48    A: RemoteActorFactory,
49{
50    fn create_remote(
51        &self,
52        label: String,
53        config: String,
54    ) -> Result<(Recipient<RemoteMessage>, JoinHandle<()>), BoxError> {
55        let (address, join_handle) = A::create_remote(label, config).map_err(Into::into)?;
56        Ok((address.into(), join_handle))
57    }
58}