Skip to main content

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}