ractor/actor/actor_cell.rs
1// Copyright (c) Sean Lawlor
2//
3// This source code is licensed under both the MIT license found in the
4// LICENSE-MIT file in the root directory of this source tree.
5
6//! [ActorCell] is reference counted actor which can be passed around as needed
7//!
8//! This module contains all the functionality around the [ActorCell], including
9//! the internal properties, ports, states, etc. [ActorCell] is the basic primitive
10//! for references to a given actor and its communication channels
11
12use std::any::TypeId;
13use std::sync::Arc;
14
15#[cfg(feature = "async-std")]
16use futures::FutureExt;
17
18use super::actor_properties::MuxedMessage;
19use super::messages::Signal;
20use super::messages::StopMessage;
21use super::SupervisionEvent;
22use crate::actor::actor_properties::ActorProperties;
23use crate::concurrency::JoinHandle;
24use crate::concurrency::MpscUnboundedReceiver as InputPortReceiver;
25use crate::concurrency::OneshotReceiver;
26use crate::errors::MessagingErr;
27#[cfg(feature = "cluster")]
28use crate::message::SerializedMessage;
29use crate::Actor;
30use crate::ActorId;
31use crate::ActorName;
32use crate::ActorRef;
33use crate::Message;
34use crate::RactorErr;
35use crate::SpawnErr;
36
37/// [ActorStatus] represents the status of an actor's lifecycle
38#[derive(Debug, Clone, Eq, PartialEq, Copy, PartialOrd, Ord)]
39#[repr(u8)]
40pub enum ActorStatus {
41 /// Created, but not yet started
42 Unstarted = 0u8,
43 /// Starting
44 Starting = 1u8,
45 /// Executing (or waiting on messages)
46 Running = 2u8,
47 /// Upgrading
48 Upgrading = 3u8,
49 /// Draining
50 Draining = 4u8,
51 /// Stopping
52 Stopping = 5u8,
53 /// Dead
54 Stopped = 6u8,
55}
56
57/// Actor states where operations can continue to interact with an agent
58pub const ACTIVE_STATES: [ActorStatus; 3] = [
59 ActorStatus::Starting,
60 ActorStatus::Running,
61 ActorStatus::Upgrading,
62];
63
64/// The collection of ports an actor needs to listen to
65pub(crate) struct ActorPortSet {
66 /// The inner signal port
67 pub(crate) signal_rx: OneshotReceiver<Signal>,
68 /// The inner stop port
69 pub(crate) stop_rx: OneshotReceiver<StopMessage>,
70 /// The inner supervisor port
71 pub(crate) supervisor_rx: InputPortReceiver<SupervisionEvent>,
72 /// The inner message port
73 pub(crate) message_rx: InputPortReceiver<MuxedMessage>,
74}
75
76impl Drop for ActorPortSet {
77 fn drop(&mut self) {
78 // Close all the message ports and flush all the message queue backlogs.
79 // See: https://docs.rs/tokio/0.1.22/tokio/sync/mpsc/index.html#clean-shutdown
80 self.signal_rx.close();
81 self.stop_rx.close();
82 self.supervisor_rx.close();
83 self.message_rx.close();
84
85 while self.signal_rx.try_recv().is_ok() {}
86 while self.stop_rx.try_recv().is_ok() {}
87 while self.supervisor_rx.try_recv().is_ok() {}
88 while self.message_rx.try_recv().is_ok() {}
89 }
90}
91
92/// Messages that come in off an actor's port, with associated priority
93pub(crate) enum ActorPortMessage {
94 /// A signal message
95 Signal(Signal),
96 /// A stop message
97 Stop(StopMessage),
98 /// A supervision message
99 Supervision(SupervisionEvent),
100 /// A regular message
101 Message(MuxedMessage),
102}
103
104impl ActorPortSet {
105 /// Run a future beside the signal port, so that
106 /// the signal port can terminate the async work
107 ///
108 /// * `future` - The future to execute
109 ///
110 /// Returns [Ok(`TState`)] when the future completes without
111 /// signal interruption, [Err(Signal)] in the event the
112 /// signal interrupts the async work.
113 pub(crate) async fn run_with_signal<TState>(
114 &mut self,
115 future: impl std::future::Future<Output = TState>,
116 ) -> Result<TState, Signal>
117 where
118 TState: crate::State,
119 {
120 #[cfg(feature = "async-std")]
121 {
122 crate::concurrency::select! {
123 // supervision or message processing work
124 // can be interrupted by the signal port receiving
125 // a kill signal
126 signal = (&mut self.signal_rx).fuse() => {
127 Err(signal.unwrap_or(Signal::Kill))
128 }
129 new_state = future.fuse() => {
130 Ok(new_state)
131 }
132 }
133 }
134 #[cfg(not(feature = "async-std"))]
135 {
136 crate::concurrency::select! {
137 // supervision or message processing work
138 // can be interrupted by the signal port receiving
139 // a kill signal
140 signal = &mut self.signal_rx => {
141 Err(signal.unwrap_or(Signal::Kill))
142 }
143 new_state = future => {
144 Ok(new_state)
145 }
146 }
147 }
148 }
149
150 /// List to the input ports in priority. The priority of listening for messages is
151 /// 1. Signal port
152 /// 2. Stop port
153 /// 3. Supervision message port
154 /// 4. General message port
155 ///
156 /// Returns [Ok(ActorPortMessage)] on a successful message reception, [MessagingErr]
157 /// in the event any of the channels is closed.
158 pub(crate) async fn listen_in_priority(
159 &mut self,
160 ) -> Result<ActorPortMessage, MessagingErr<()>> {
161 #[cfg(feature = "async-std")]
162 {
163 crate::concurrency::select! {
164 signal = (&mut self.signal_rx).fuse() => {
165 signal.map(ActorPortMessage::Signal).map_err(|_| MessagingErr::ChannelClosed)
166 }
167 stop = (&mut self.stop_rx).fuse() => {
168 stop.map(ActorPortMessage::Stop).map_err(|_| MessagingErr::ChannelClosed)
169 }
170 supervision = self.supervisor_rx.recv().fuse() => {
171 supervision.map(ActorPortMessage::Supervision).ok_or(MessagingErr::ChannelClosed)
172 }
173 message = self.message_rx.recv().fuse() => {
174 message.map(ActorPortMessage::Message).ok_or(MessagingErr::ChannelClosed)
175 }
176 }
177 }
178 #[cfg(not(feature = "async-std"))]
179 {
180 crate::concurrency::select! {
181 signal = &mut self.signal_rx => {
182 signal.map(ActorPortMessage::Signal).map_err(|_| MessagingErr::ChannelClosed)
183 }
184 stop = &mut self.stop_rx => {
185 stop.map(ActorPortMessage::Stop).map_err(|_| MessagingErr::ChannelClosed)
186 }
187 supervision = self.supervisor_rx.recv() => {
188 supervision.map(ActorPortMessage::Supervision).ok_or(MessagingErr::ChannelClosed)
189 }
190 message = self.message_rx.recv() => {
191 message.map(ActorPortMessage::Message).ok_or(MessagingErr::ChannelClosed)
192 }
193 }
194 }
195 }
196}
197
198/// An [ActorCell] is a reference to an [Actor]'s communication channels
199/// and provides external access to send messages, stop, kill, and generally
200/// interactor with the underlying [Actor] process.
201///
202/// The input ports contained in the cell will return an error should the
203/// underlying actor have terminated and no longer exist.
204#[derive(Clone)]
205pub struct ActorCell {
206 pub(crate) inner: Arc<ActorProperties>,
207}
208
209impl std::fmt::Debug for ActorCell {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 f.debug_struct("Actor")
212 .field("name", &self.get_name())
213 .field("id", &self.get_id())
214 .finish()
215 }
216}
217
218impl PartialEq for ActorCell {
219 fn eq(&self, other: &Self) -> bool {
220 other.get_id() == self.get_id()
221 }
222}
223
224impl Eq for ActorCell {}
225
226impl std::hash::Hash for ActorCell {
227 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
228 self.get_id().hash(state)
229 }
230}
231
232impl ActorCell {
233 /// Construct a new [ActorCell] pointing to an [super::Actor] and return the message reception channels as a [ActorPortSet]
234 ///
235 /// * `name` - Optional name for the actor
236 ///
237 /// Returns a tuple [(ActorCell, ActorPortSet)] to bootstrap the [crate::Actor]
238 pub(crate) fn new<TActor>(name: Option<ActorName>) -> Result<(Self, ActorPortSet), SpawnErr>
239 where
240 TActor: Actor,
241 {
242 let (props, rx1, rx2, rx3, rx4) = ActorProperties::new::<TActor>(name.clone());
243 let cell = Self {
244 inner: Arc::new(props),
245 };
246
247 #[cfg(feature = "cluster")]
248 {
249 // registry to the PID registry
250 crate::registry::pid_registry::register_pid(cell.get_id(), cell.clone())?;
251 }
252
253 if let Some(r_name) = name {
254 crate::registry::register(r_name, cell.clone())?;
255 }
256
257 Ok((
258 cell,
259 ActorPortSet {
260 signal_rx: rx1,
261 stop_rx: rx2,
262 supervisor_rx: rx3,
263 message_rx: rx4,
264 },
265 ))
266 }
267
268 /// Create a new remote actor, to be called from the `ractor_cluster` crate
269 #[cfg(feature = "cluster")]
270 pub(crate) fn new_remote<TActor>(
271 name: Option<ActorName>,
272 id: ActorId,
273 ) -> Result<(Self, ActorPortSet), SpawnErr>
274 where
275 TActor: Actor,
276 {
277 if id.is_local() {
278 return Err(SpawnErr::StartupFailed(From::from("Cannot create a new remote actor handler without the actor id being marked as a remote actor!")));
279 }
280
281 let (props, rx1, rx2, rx3, rx4) = ActorProperties::new_remote::<TActor>(name, id);
282 let cell = Self {
283 inner: Arc::new(props),
284 };
285 // NOTE: remote actors don't appear in the name registry
286 // if let Some(r_name) = name {
287 // crate::registry::register(r_name, cell.clone())?;
288 // }
289 Ok((
290 cell,
291 ActorPortSet {
292 signal_rx: rx1,
293 stop_rx: rx2,
294 supervisor_rx: rx3,
295 message_rx: rx4,
296 },
297 ))
298 }
299
300 /// Retrieve the [super::Actor]'s unique identifier [ActorId]
301 pub fn get_id(&self) -> ActorId {
302 self.inner.id
303 }
304
305 /// Retrieve the [super::Actor]'s name
306 pub fn get_name(&self) -> Option<ActorName> {
307 self.inner.name.clone()
308 }
309
310 /// Retrieve the current status of an [super::Actor]
311 ///
312 /// Returns the [super::Actor]'s current [ActorStatus]
313 pub fn get_status(&self) -> ActorStatus {
314 self.inner.get_status()
315 }
316
317 /// Identifies if this actor supports remote (dist) communication
318 ///
319 /// Returns [true] if the actor's messaging protocols support remote calls, [false] otherwise
320 #[cfg(feature = "cluster")]
321 pub fn supports_remoting(&self) -> bool {
322 self.inner.supports_remoting
323 }
324
325 /// Advance the status of the [super::Actor]. Requests to move backward in
326 /// the lifecycle are ignored. If the status advances to
327 /// [ActorStatus::Stopping] or [ActorStatus::Stopped] the actor
328 /// will also be unenrolled from both the named registry ([crate::registry])
329 /// and the PG groups ([crate::pg]) if it's enrolled in any
330 ///
331 /// * `status` - The [ActorStatus] to set
332 ///
333 /// Returns the status observed immediately before the update.
334 pub(crate) fn set_status(&self, status: ActorStatus) -> ActorStatus {
335 let previous_status = self.inner.set_status(status);
336
337 // The actor is shut down — only run cleanup once, on the first transition
338 // to Stopping. Publish the new status before cleanup so concurrent PG
339 // registrations cannot be added after the reverse indexes are drained.
340 if status >= ActorStatus::Stopping && previous_status < ActorStatus::Stopping {
341 #[cfg(feature = "cluster")]
342 {
343 // stop monitoring for updates
344 crate::registry::pid_registry::demonitor(self.get_id());
345 // unregistry from the PID registry
346 crate::registry::pid_registry::unregister_pid(self.get_id());
347 }
348 // If it's enrolled in the registry, remove it
349 if let Some(name) = self.get_name() {
350 crate::registry::unregister(name);
351 }
352 // Leave all + stop monitoring pg groups (if any)
353 crate::pg::demonitor_all(self.get_id());
354 crate::pg::leave_all(self.get_id());
355 }
356
357 // Fix for #254. We should only notify the stop listener AFTER post_stop
358 // has executed, which is when the state gets set to `Stopped`.
359 if status == ActorStatus::Stopped && previous_status < ActorStatus::Stopped {
360 // notify whoever might be waiting on the stop signal
361 self.inner.notify_stop_listener();
362 }
363
364 previous_status
365 }
366
367 /// Terminate this [super::Actor] and all it's children
368 pub(crate) fn terminate(&self) {
369 // we don't need to notify of exit if we're already stopping or stopped
370 if self.get_status() as u8 <= ActorStatus::Upgrading as u8 {
371 // kill myself immediately. Ignores failures, as a failure means either
372 // 1. we're already dead or
373 // 2. the channel is full of "signals"
374 self.kill();
375 }
376
377 // notify children they should die. They will unlink themselves from the supervisor
378 self.inner.tree.terminate_all_children();
379 }
380
381 /// Link this [super::Actor] to the provided supervisor
382 ///
383 /// * `supervisor` - The supervisor [super::Actor] of this actor
384 pub fn link(&self, supervisor: ActorCell) {
385 supervisor.inner.tree.insert_child(self.clone());
386 self.inner.tree.set_supervisor(supervisor);
387 }
388
389 /// Unlink this [super::Actor] from the supervisor if it's
390 /// currently linked (if self's supervisor is `supervisor`)
391 ///
392 /// * `supervisor` - The supervisor to unlink this [super::Actor] from
393 pub fn unlink(&self, supervisor: ActorCell) {
394 if self.inner.tree.is_child_of(supervisor.get_id()) {
395 supervisor.inner.tree.remove_child(self.get_id());
396 self.inner.tree.clear_supervisor();
397 }
398 }
399
400 /// Clear the supervisor field
401 pub(crate) fn clear_supervisor(&self) {
402 self.inner.tree.clear_supervisor();
403 }
404
405 /// Monitor the provided [super::Actor] for supervision events. An actor in `ractor` can
406 /// only have a single supervisor, denoted by the `link` function, however they
407 /// may have multiple `monitors`. Monitor's receive copies of the [SupervisionEvent]s,
408 /// with non-cloneable information removed.
409 ///
410 /// * `who`: The actor to monitor
411 #[cfg(feature = "monitors")]
412 pub fn monitor(&self, who: ActorCell) {
413 who.inner.tree.set_monitor(self.clone());
414 }
415
416 /// Stop monitoring the provided [super::Actor] for supervision events.
417 ///
418 /// * `who`: The actor to stop monitoring
419 #[cfg(feature = "monitors")]
420 pub fn unmonitor(&self, who: ActorCell) {
421 who.inner.tree.remove_monitor(self.get_id());
422 }
423
424 /// Kill this [super::Actor] forcefully (terminates async work)
425 pub fn kill(&self) {
426 let _ = self.inner.send_signal(Signal::Kill);
427 }
428
429 /// Kill this [super::Actor] forcefully (terminates async work)
430 /// and wait for the actor shutdown to complete
431 ///
432 /// * `timeout` - An optional timeout duration to wait for shutdown to occur
433 ///
434 /// Returns [Ok(())] upon the actor being stopped/shutdown. [Err(RactorErr::Messaging(_))] if the channel is closed
435 /// or dropped (which may indicate some other process is trying to shutdown this actor) or [Err(RactorErr::Timeout)]
436 /// if timeout was hit before the actor was successfully shut down (when set)
437 pub async fn kill_and_wait(
438 &self,
439 timeout: Option<crate::concurrency::Duration>,
440 ) -> Result<(), RactorErr<()>> {
441 if let Some(to) = timeout {
442 match crate::concurrency::timeout(to, self.inner.send_signal_and_wait(Signal::Kill))
443 .await
444 {
445 Err(_) => Err(RactorErr::Timeout),
446 Ok(Err(e)) => Err(e.into()),
447 Ok(_) => Ok(()),
448 }
449 } else {
450 Ok(self.inner.send_signal_and_wait(Signal::Kill).await?)
451 }
452 }
453
454 /// Stop this [super::Actor] gracefully (stopping message processing)
455 ///
456 /// * `reason` - An optional string reason why the stop is occurring
457 pub fn stop(&self, reason: Option<String>) {
458 // ignore failures, since that means the actor is dead already
459 let _ = self.inner.send_stop(reason);
460 }
461
462 /// Stop the [super::Actor] gracefully (stopping messaging processing)
463 /// and wait for the actor shutdown to complete
464 ///
465 /// * `reason` - An optional string reason why the stop is occurring
466 /// * `timeout` - An optional timeout duration to wait for shutdown to occur
467 ///
468 /// Returns [Ok(())] upon the actor being stopped/shutdown. [Err(RactorErr::Messaging(_))] if the channel is closed
469 /// or dropped (which may indicate some other process is trying to shutdown this actor) or [Err(RactorErr::Timeout)]
470 /// if timeout was hit before the actor was successfully shut down (when set)
471 pub async fn stop_and_wait(
472 &self,
473 reason: Option<String>,
474 timeout: Option<crate::concurrency::Duration>,
475 ) -> Result<(), RactorErr<StopMessage>> {
476 if let Some(to) = timeout {
477 match crate::concurrency::timeout(to, self.inner.send_stop_and_wait(reason)).await {
478 Err(_) => Err(RactorErr::Timeout),
479 Ok(Err(e)) => Err(e.into()),
480 Ok(_) => Ok(()),
481 }
482 } else {
483 Ok(self.inner.send_stop_and_wait(reason).await?)
484 }
485 }
486
487 /// Wait for the actor to exit, optionally within a timeout
488 ///
489 /// * `timeout`: If supplied, the amount of time to wait before
490 /// returning an error and cancelling the wait future.
491 ///
492 /// IMPORTANT: If the timeout is hit, the actor is still running.
493 /// You should wait again for its exit.
494 pub async fn wait(
495 &self,
496 timeout: Option<crate::concurrency::Duration>,
497 ) -> Result<(), crate::concurrency::Timeout> {
498 if let Some(to) = timeout {
499 crate::concurrency::timeout(to, self.inner.wait()).await
500 } else {
501 self.inner.wait().await;
502 Ok(())
503 }
504 }
505
506 /// Send a supervisor event to the supervisory port
507 ///
508 /// * `message` - The [SupervisionEvent] to send to the supervisory port
509 ///
510 /// Returns [Ok(())] on successful message send, [Err(MessagingErr)] otherwise
511 pub(crate) fn send_supervisor_evt(
512 &self,
513 message: SupervisionEvent,
514 ) -> Result<(), MessagingErr<SupervisionEvent>> {
515 self.inner.send_supervisor_evt(message)
516 }
517
518 /// Send a strongly-typed message, constructing the boxed message on the fly
519 ///
520 /// Note: The type requirement of `TActor` assures that `TMsg` is the supported
521 /// message type for `TActor` such that we can't send boxed messages of an unsupported
522 /// type to the specified actor.
523 ///
524 /// * `message` - The message to send
525 ///
526 /// Returns [Ok(())] on successful message send, [Err(MessagingErr)] otherwise
527 pub fn send_message<TMessage>(&self, message: TMessage) -> Result<(), MessagingErr<TMessage>>
528 where
529 TMessage: Message,
530 {
531 self.inner.send_message::<TMessage>(message)
532 }
533
534 /// Drain the actor's message queue and when finished processing, terminate the actor.
535 ///
536 /// Any messages received after the drain marker but prior to shutdown will be rejected
537 pub fn drain(&self) -> Result<(), MessagingErr<()>> {
538 self.inner.drain()
539 }
540
541 /// Drain the actor's message queue and when finished processing, terminate the actor,
542 /// notifying on this handler that the actor has drained and exited (stopped).
543 ///
544 /// * `timeout`: The optional amount of time to wait for the drain to complete.
545 ///
546 /// Any messages received after the drain marker but prior to shutdown will be rejected
547 pub async fn drain_and_wait(
548 &self,
549 timeout: Option<crate::concurrency::Duration>,
550 ) -> Result<(), RactorErr<()>> {
551 if let Some(to) = timeout {
552 match crate::concurrency::timeout(to, self.inner.drain_and_wait()).await {
553 Err(_) => Err(RactorErr::Timeout),
554 Ok(Err(e)) => Err(e.into()),
555 Ok(_) => Ok(()),
556 }
557 } else {
558 Ok(self.inner.drain_and_wait().await?)
559 }
560 }
561
562 /// Send a serialized binary message to the actor.
563 ///
564 /// * `message` - The message to send
565 ///
566 /// Returns [Ok(())] on successful message send, [Err(MessagingErr)] otherwise
567 #[cfg(feature = "cluster")]
568 pub fn send_serialized(
569 &self,
570 message: SerializedMessage,
571 ) -> Result<(), Box<MessagingErr<SerializedMessage>>> {
572 self.inner.send_serialized(message)
573 }
574
575 /// Notify the supervisor and all monitors that a supervision event occurred.
576 /// Monitors receive a reduced copy of the supervision event which won't contain
577 /// the [crate::actor::BoxedState] and collapses the [crate::ActorProcessingErr]
578 /// exception to a [String]
579 ///
580 /// * `evt` - The event to send to this [super::Actor]'s supervisors
581 pub fn notify_supervisor(&self, evt: SupervisionEvent) {
582 self.inner.tree.notify_supervisor(evt)
583 }
584
585 /// Stop any children of this actor, not waiting for their exit, and threading
586 /// the optional reason to all children
587 ///
588 /// * `reason`: The stop reason to send to all the children
589 ///
590 /// This swallows and communication errors because if you can't send a message
591 /// to the child, it's dropped the message channel, and is dead/stopped already.
592 pub fn stop_children(&self, reason: Option<String>) {
593 self.inner.tree.stop_all_children(reason);
594 }
595
596 /// Tries to retrieve this actor's supervisor.
597 ///
598 /// Returns [None] if this actor has no supervisor at the given instance or
599 /// [Some(ActorCell)] supervisor if one is configured.
600 pub fn try_get_supervisor(&self) -> Option<ActorCell> {
601 self.inner.tree.try_get_supervisor()
602 }
603
604 /// Stop any children of this actor, and wait for their collective exit, optionally
605 /// threading the optional reason to all children
606 ///
607 /// * `reason`: The stop reason to send to all the children
608 /// * `timeout`: An optional timeout which is the maximum time to wait for the actor stop
609 /// operation to complete
610 ///
611 /// This swallows and communication errors because if you can't send a message
612 /// to the child, it's dropped the message channel, and is dead/stopped already.
613 pub async fn stop_children_and_wait(
614 &self,
615 reason: Option<String>,
616 timeout: Option<crate::concurrency::Duration>,
617 ) {
618 self.inner
619 .tree
620 .stop_all_children_and_wait(reason, timeout)
621 .await
622 }
623
624 /// Drain any children of this actor, not waiting for their exit
625 ///
626 /// This swallows and communication errors because if you can't send a message
627 /// to the child, it's dropped the message channel, and is dead/stopped already.
628 pub fn drain_children(&self) {
629 self.inner.tree.drain_all_children();
630 }
631
632 /// Drain any children of this actor, and wait for their collective exit
633 ///
634 /// * `timeout`: An optional timeout which is the maximum time to wait for the actor stop
635 /// operation to complete
636 pub async fn drain_children_and_wait(&self, timeout: Option<crate::concurrency::Duration>) {
637 self.inner.tree.drain_all_children_and_wait(timeout).await
638 }
639
640 /// Retrieve the supervised children of this actor (if any)
641 ///
642 /// Returns a [Vec] of [ActorCell]s which are the children that are
643 /// presently linked to this actor.
644 pub fn get_children(&self) -> Vec<ActorCell> {
645 self.inner.tree.get_children()
646 }
647
648 /// Retrieve the [TypeId] of this [ActorCell] which can be helpful
649 /// for quick type-checking.
650 ///
651 /// HOWEVER: Note this is an unstable identifier, and changes between
652 /// Rust releases and may not be stable over a network call.
653 pub fn get_type_id(&self) -> TypeId {
654 self.inner.type_id
655 }
656
657 /// Runtime check the message type of this actor, which only works for
658 /// local actors, as remote actors send serializable messages, and can't
659 /// have their message type runtime checked.
660 ///
661 /// Returns [None] if the actor is a remote actor, and we cannot perform a
662 /// runtime message type check. Otherwise [Some(true)] for the correct message
663 /// type or [Some(false)] for an incorrect type will returned.
664 pub fn is_message_type_of<TMessage: Message>(&self) -> Option<bool> {
665 if self.get_id().is_local() {
666 Some(self.get_type_id() == std::any::TypeId::of::<TMessage>())
667 } else {
668 None
669 }
670 }
671
672 /// Spawn an actor of the given type as a child of this actor, automatically starting the actor.
673 /// This [ActorCell] becomes the supervisor of the child actor.
674 ///
675 /// * `name`: A name to give the actor. Useful for global referencing or debug printing
676 /// * `handler` The implementation of Self
677 /// * `startup_args`: Arguments passed to the `pre_start` call of the [Actor] to facilitate startup and
678 /// initial state creation
679 ///
680 /// Returns a [Ok((ActorRef, JoinHandle<()>))] upon successful start, denoting the actor reference
681 /// along with the join handle which will complete when the actor terminates. Returns [Err(SpawnErr)] if
682 /// the actor failed to start
683 pub async fn spawn_linked<T: Actor>(
684 &self,
685 name: Option<String>,
686 handler: T,
687 startup_args: T::Arguments,
688 ) -> Result<(ActorRef<T::Msg>, JoinHandle<()>), SpawnErr> {
689 crate::actor::ActorRuntime::spawn_linked(name, handler, startup_args, self.clone()).await
690 }
691
692 // ================== Test Utilities ================== //
693
694 #[cfg(test)]
695 pub(crate) fn get_num_children(&self) -> usize {
696 self.inner.tree.get_num_children()
697 }
698
699 #[cfg(test)]
700 pub(crate) fn get_num_parents(&self) -> usize {
701 self.inner.tree.get_num_parents()
702 }
703}