Skip to main content

actor_kit/
handle.rs

1//! Actor handle for sending messages and querying state.
2//!
3//! Provides a reference to an actor for interaction.
4
5use std::sync::Arc;
6
7use crate::{ActorId, ActorScheduler, ActorState, Message, MessagePayload, Priority};
8
9/// Handle to an actor for sending messages and querying state.
10#[derive(Clone)]
11pub struct ActorHandle {
12    /// Actor ID
13    id: ActorId,
14    /// Scheduler reference
15    scheduler: Arc<ActorScheduler>,
16}
17
18impl ActorHandle {
19    /// Create a new actor handle.
20    pub(crate) fn new(id: ActorId, scheduler: Arc<ActorScheduler>) -> Self {
21        Self { id, scheduler }
22    }
23
24    /// Get the actor ID.
25    pub fn id(&self) -> ActorId {
26        self.id
27    }
28
29    /// Send a message to this actor.
30    pub async fn send(&self, payload: MessagePayload) -> crate::Result<()> {
31        self.scheduler
32            .send(
33                self.id,
34                Message {
35                    sender: None,
36                    payload,
37                    priority: Priority::Normal,
38                },
39            )
40            .await
41    }
42
43    /// Send a message with a specific priority.
44    pub async fn send_with_priority(
45        &self,
46        payload: MessagePayload,
47        priority: Priority,
48    ) -> crate::Result<()> {
49        self.scheduler
50            .send(
51                self.id,
52                Message {
53                    sender: None,
54                    payload,
55                    priority,
56                },
57            )
58            .await
59    }
60
61    /// Send a message from another actor.
62    pub async fn send_from(&self, sender: ActorId, payload: MessagePayload) -> crate::Result<()> {
63        self.scheduler
64            .send(
65                self.id,
66                Message {
67                    sender: Some(sender),
68                    payload,
69                    priority: Priority::Normal,
70                },
71            )
72            .await
73    }
74
75    /// Send a start signal to the actor.
76    pub async fn start(&self) -> crate::Result<()> {
77        self.send(MessagePayload::Start).await
78    }
79
80    /// Send a stop signal to the actor.
81    pub async fn stop(&self) -> crate::Result<()> {
82        self.send(MessagePayload::Stop).await
83    }
84
85    /// Send a pause signal to the actor.
86    pub async fn pause(&self) -> crate::Result<()> {
87        self.send(MessagePayload::Signal(crate::Signal::Pause))
88            .await
89    }
90
91    /// Send a resume signal to the actor.
92    pub async fn resume(&self) -> crate::Result<()> {
93        self.send(MessagePayload::Signal(crate::Signal::Resume))
94            .await
95    }
96
97    /// Send a restart signal to the actor.
98    pub async fn restart(&self) -> crate::Result<()> {
99        self.send(MessagePayload::Signal(crate::Signal::Restart))
100            .await
101    }
102
103    /// Query the actor's state.
104    pub fn state(&self) -> Option<ActorState> {
105        self.scheduler.registry().get_state(&self.id)
106    }
107
108    /// Check if the actor is running.
109    pub fn is_running(&self) -> bool {
110        self.state() == Some(ActorState::Running)
111    }
112
113    /// Check if the actor is stopped.
114    pub fn is_stopped(&self) -> bool {
115        self.state() == Some(ActorState::Stopped)
116    }
117
118    /// Check if the actor is suspended.
119    pub fn is_suspended(&self) -> bool {
120        self.state() == Some(ActorState::Suspended)
121    }
122
123    /// Check if the actor is in backpressure.
124    pub fn is_backpressured(&self) -> bool {
125        self.scheduler
126            .registry()
127            .get_mailbox(&self.id)
128            .map(|m| m.is_backpressured())
129            .unwrap_or(false)
130    }
131
132    /// Get the mailbox size.
133    pub fn mailbox_size(&self) -> usize {
134        self.scheduler
135            .registry()
136            .get_mailbox(&self.id)
137            .map(|m| m.len())
138            .unwrap_or(0)
139    }
140
141    /// Get the number of messages processed by this actor.
142    pub fn processed_count(&self) -> u64 {
143        self.scheduler.registry().get_processed_count(&self.id)
144    }
145}
146
147impl std::fmt::Debug for ActorHandle {
148    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149        f.debug_struct("ActorHandle")
150            .field("id", &self.id)
151            .field("state", &self.state())
152            .finish()
153    }
154}
155
156impl std::hash::Hash for ActorHandle {
157    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
158        self.id.hash(state);
159    }
160}
161
162impl PartialEq for ActorHandle {
163    fn eq(&self, other: &Self) -> bool {
164        self.id == other.id
165    }
166}
167
168impl Eq for ActorHandle {}
169
170/// Builder for creating actors.
171pub struct ActorBuilder {
172    name: Option<String>,
173    priority: Priority,
174}
175
176impl ActorBuilder {
177    /// Create a new actor builder.
178    pub fn new() -> Self {
179        Self {
180            name: None,
181            priority: Priority::Normal,
182        }
183    }
184
185    /// Set the actor name.
186    pub fn name(mut self, name: impl Into<String>) -> Self {
187        self.name = Some(name.into());
188        self
189    }
190
191    /// Set the default priority for this actor's messages.
192    pub fn priority(mut self, priority: Priority) -> Self {
193        self.priority = priority;
194        self
195    }
196
197    /// Spawn the actor with the given scheduler.
198    pub fn spawn(self, scheduler: &Arc<ActorScheduler>) -> crate::Result<ActorHandle> {
199        let id = scheduler.spawn_named(self.name)?;
200        Ok(ActorHandle::new(id, scheduler.clone()))
201    }
202}
203
204impl Default for ActorBuilder {
205    fn default() -> Self {
206        Self::new()
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213
214    #[tokio::test]
215    async fn test_actor_handle_send() {
216        let scheduler = Arc::new(ActorScheduler::new(Default::default()));
217        scheduler.start().unwrap();
218
219        let handle = ActorBuilder::new()
220            .name("test-actor")
221            .spawn(&scheduler)
222            .unwrap();
223
224        assert_eq!(handle.state(), Some(ActorState::Creating));
225
226        handle.start().await.unwrap();
227    }
228}