Skip to main content

atomr_core/actor/
props.rs

1//! `Props` — a recipe for constructing an actor.
2
3use std::fmt;
4use std::sync::Arc;
5
6use super::deploy::Deploy;
7use super::metadata::MessageInterceptor;
8use super::traits::Actor;
9use crate::supervision::SupervisorStrategy;
10
11pub type Factory<A> = Arc<dyn Fn() -> A + Send + Sync>;
12
13/// Typed props. The factory produces fresh `A` instances on initial start
14/// and on restart.
15pub struct Props<A: Actor> {
16    factory: Factory<A>,
17    pub dispatcher: Option<String>,
18    pub mailbox: Option<String>,
19    pub deploy: Deploy,
20    pub supervisor_strategy: Option<SupervisorStrategy>,
21    /// Optional message interceptor (FR-10) invoked around each `handle` and on
22    /// outgoing sends — e.g. a tracing-context propagator.
23    pub interceptor: Option<Arc<dyn MessageInterceptor>>,
24}
25
26impl<A: Actor> Clone for Props<A> {
27    fn clone(&self) -> Self {
28        Self {
29            factory: self.factory.clone(),
30            dispatcher: self.dispatcher.clone(),
31            mailbox: self.mailbox.clone(),
32            deploy: self.deploy.clone(),
33            supervisor_strategy: self.supervisor_strategy.clone(),
34            interceptor: self.interceptor.clone(),
35        }
36    }
37}
38
39impl<A: Actor> fmt::Debug for Props<A> {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        f.debug_struct("Props")
42            .field("dispatcher", &self.dispatcher)
43            .field("mailbox", &self.mailbox)
44            .field("deploy", &self.deploy)
45            .finish_non_exhaustive()
46    }
47}
48
49impl<A: Actor> Props<A> {
50    /// Create props from a zero-argument factory. Mirrors `Props.Create<T>(() => new T())`.
51    pub fn create<F>(factory: F) -> Self
52    where
53        F: Fn() -> A + Send + Sync + 'static,
54    {
55        Self {
56            factory: Arc::new(factory),
57            dispatcher: None,
58            mailbox: None,
59            deploy: Deploy::local(),
60            supervisor_strategy: None,
61            interceptor: None,
62        }
63    }
64
65    /// Install a [`MessageInterceptor`] (FR-10). It fires before/after each
66    /// `handle` and can inject child trace context on outgoing sends.
67    pub fn with_interceptor(mut self, interceptor: Arc<dyn MessageInterceptor>) -> Self {
68        self.interceptor = Some(interceptor);
69        self
70    }
71
72    pub fn with_dispatcher(mut self, d: impl Into<String>) -> Self {
73        self.dispatcher = Some(d.into());
74        self
75    }
76
77    pub fn with_mailbox(mut self, m: impl Into<String>) -> Self {
78        self.mailbox = Some(m.into());
79        self
80    }
81
82    pub fn with_supervisor_strategy(mut self, s: SupervisorStrategy) -> Self {
83        self.supervisor_strategy = Some(s);
84        self
85    }
86
87    pub fn with_deploy(mut self, d: Deploy) -> Self {
88        self.deploy = d;
89        self
90    }
91
92    pub fn new_actor(&self) -> A {
93        (self.factory)()
94    }
95}
96
97/// Type-erased props — used when an actor needs to hold props of an
98/// unknown `A` (e.g. remote deployment, routers).
99#[derive(Clone)]
100pub struct BoxedProps {
101    pub spawn: Arc<dyn Fn() -> Arc<dyn std::any::Any + Send + Sync> + Send + Sync>,
102    pub dispatcher: Option<String>,
103    pub mailbox: Option<String>,
104    pub deploy: Deploy,
105}
106
107impl fmt::Debug for BoxedProps {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        f.debug_struct("BoxedProps").finish_non_exhaustive()
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116    use crate::actor::context::Context;
117
118    #[derive(Default)]
119    struct A(u32);
120
121    #[async_trait::async_trait]
122    impl Actor for A {
123        type Msg = ();
124        async fn handle(&mut self, _: &mut Context<Self>, _: ()) {}
125    }
126
127    #[test]
128    fn create_and_instantiate() {
129        let p = Props::create(|| A(5));
130        let a = p.new_actor();
131        assert_eq!(a.0, 5);
132    }
133}