black_box/actors/
mod.rs

1use std::future::Future;
2
3use async_channel::Sender;
4
5use crate::{
6    executor::Context,
7    message::{Envelope, Message},
8};
9
10/// Abstraction for message handleing
11///
12/// Actors are spawned in an [`Executor`](crate::Executor), and run in the executor's event loop.
13/// When new messages are received by the executor, the appropriate handler [`Handler`] is invoked,
14/// allowing the actor to take any necessary action, including mutating it's internal state.
15pub trait Actor: Sized {
16    fn starting(&mut self, _ctx: &Context<Self>) -> impl Future<Output = ()> + Send {
17        std::future::ready(())
18    }
19
20    fn stopping(&mut self, _ctx: &Context<Self>) -> impl Future<Output = ()> + Send {
21        std::future::ready(())
22    }
23}
24
25/// The implementation for how an actor handles a particular message
26///
27/// An [`Actor`], can implement the Handler trait any number of time, with a unique message type for
28/// each implementation.
29pub trait Handler<M>
30where
31    Self: Actor,
32    M: Message,
33{
34    /// Asynchronously act on the message, with mutable access to self
35    fn handle(&mut self, msg: M, ctx: &Context<Self>) -> impl Future<Output = ()> + Send;
36}
37
38/// A cloneable address which can be used to send messages to the associated [`Actor`]
39///
40/// This is a cheaply cloneable type and can be used to send an actor address to other actors, other
41/// runtimes, etc.
42pub struct Address<A> {
43    sender: Sender<Envelope<A>>,
44}
45
46// SAFETY: The address is a queue abstraction for *messages* sent to the actor. Even if the actor
47// itself is not Send/Sync the address should be. The Message trait itself already requires that
48// the implementer be Send
49unsafe impl<A> std::marker::Send for Address<A> {}
50// SAFETY: As above but for Sync
51unsafe impl<A> std::marker::Sync for Address<A> {}
52impl<A> std::marker::Unpin for Address<A> {}
53
54impl<A> Clone for Address<A> {
55    fn clone(&self) -> Self {
56        Self {
57            sender: self.sender.clone(),
58        }
59    }
60}
61
62impl<A> Address<A> {
63    pub(crate) fn new(sender: Sender<Envelope<A>>) -> Self {
64        Self { sender }
65    }
66}
67
68impl<A> Address<A>
69where
70    A: 'static + Actor + Send,
71{
72    /// Send the given message to the actor's receiver.
73    ///
74    /// If the receiver is currently full, it will await capacity to enqueue the message
75    pub async fn send<M>(&self, message: M)
76    where
77        A: Handler<M>,
78        M: Message,
79    {
80        let env = Envelope::pack(message);
81
82        // TODO: Decide what to do here
83        let _ = self.sender.send(env).await;
84    }
85
86    pub fn try_send<M>(&self, message: M)
87    where
88        A: Handler<M>,
89        M: Message,
90    {
91        let env = Envelope::pack(message);
92
93        // TODO: Decide what to do here
94        let _ = self.sender.try_send(env);
95    }
96}