Skip to main content

maiko/
actor_builder.rs

1use std::sync::Arc;
2
3use tokio::sync::mpsc::Receiver;
4
5use crate::{
6    Actor, ActorConfig, ActorId, Context, Envelope, Event, Result, Subscribe, Supervisor, Topic,
7    internal::Subscription,
8};
9
10/// Builder for registering an actor with custom configuration.
11///
12/// Returned by [`Supervisor::build_actor`]. Use this when you need to override
13/// per-actor settings such as channel capacity or when you want to separate
14/// actor construction from topic subscription.
15///
16/// Defaults to no topic subscriptions and channel capacity inherited from the
17/// global [`SupervisorConfig`](crate::SupervisorConfig).
18///
19/// # Examples
20///
21/// ```rust,ignore
22/// // Custom channel capacity for a slow consumer
23/// sup.build_actor("writer", |ctx| Writer::new(ctx))
24///     .topics(&[Topic::Data])
25///     .channel_capacity(512)
26///     .build()?;
27///
28/// // Replace the entire actor config
29/// sup.build_actor("fast", |ctx| Fast::new(ctx))
30///     .topics(Subscribe::all())
31///     .config(my_config)
32///     .build()?;
33/// ```
34///
35/// [`Supervisor::build_actor`]: crate::Supervisor::build_actor
36#[must_use = "actor is not registered until .build() is called"]
37pub struct ActorBuilder<'a, E: Event, T: Topic<E>, A: Actor<Event = E>> {
38    supervisor: &'a mut Supervisor<E, T>,
39    actor: A,
40    ctx: Context<A::Event>,
41    config: ActorConfig,
42    topics: Subscription<T>,
43    receiver: Receiver<Arc<Envelope<E>>>,
44}
45
46impl<'a, E: Event, T: Topic<E>, A: Actor<Event = E>> ActorBuilder<'a, E, T, A> {
47    pub(crate) fn new(
48        supervisor: &'a mut Supervisor<E, T>,
49        actor: A,
50        ctx: Context<A::Event>,
51        receiver: Receiver<Arc<Envelope<E>>>,
52    ) -> Self {
53        let config = ActorConfig::new(supervisor.config());
54        Self {
55            supervisor,
56            ctx,
57            actor,
58            config,
59            topics: Subscription::None,
60            receiver,
61        }
62    }
63
64    /// Set the topics this actor subscribes to.
65    ///
66    /// Accepts anything that converts to [`Subscribe`]: a topic slice,
67    /// [`Subscribe::all()`], or [`Subscribe::none()`].
68    pub fn topics<S>(mut self, topics: S) -> Self
69    where
70        S: Into<Subscribe<E, T>>,
71    {
72        self.topics = topics.into().0;
73        self
74    }
75
76    /// Replace the entire [`ActorConfig`] for this actor.
77    pub fn config<C>(mut self, config: C) -> Self
78    where
79        C: Into<ActorConfig>,
80    {
81        self.config = config.into();
82        self
83    }
84
85    /// Transform the current [`ActorConfig`] with a closure.
86    ///
87    /// Unlike [`config()`](Self::config) which replaces the entire config,
88    /// this preserves inherited defaults and lets you tweak individual fields.
89    ///
90    /// ```rust,ignore
91    /// sup.build_actor("consumer", |ctx| Consumer::new(ctx))
92    ///     .topics(&[Topic::Data])
93    ///     .channel_capacity(256)
94    ///     .with_config(|c| c.with_max_events_per_tick(64))
95    ///     .build()?;
96    /// ```
97    pub fn with_config<F>(mut self, f: F) -> Self
98    where
99        F: FnOnce(ActorConfig) -> ActorConfig,
100    {
101        self.config = f(self.config);
102        self
103    }
104
105    /// Set the actor's mailbox channel capacity.
106    ///
107    /// Shorthand for modifying the channel capacity without replacing the
108    /// full config. See [`ActorConfig::with_channel_capacity`].
109    pub fn channel_capacity(mut self, capacity: usize) -> Self {
110        self.config = self.config.with_channel_capacity(capacity);
111        self
112    }
113
114    /// Register the actor with the supervisor and return its [`ActorId`].
115    ///
116    /// # Errors
117    ///
118    /// Returns [`Error::DuplicateActorName`](crate::Error::DuplicateActorName)
119    /// if an actor with the same name is already registered.
120    pub fn build(self) -> Result<ActorId> {
121        self.supervisor.register_actor(
122            self.ctx,
123            self.actor,
124            self.topics,
125            self.config,
126            self.receiver,
127        )
128    }
129}