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> {}
52
53impl<A> Clone for Address<A> {
54    fn clone(&self) -> Self {
55        Self {
56            sender: self.sender.clone(),
57        }
58    }
59}
60
61impl<A> Address<A> {
62    pub(crate) fn new(sender: Sender<Envelope<A>>) -> Self {
63        Self { sender }
64    }
65}
66
67impl<A> Address<A>
68where
69    A: 'static + Actor + Send,
70{
71    /// Send the given message to the actor's receiver.
72    ///
73    /// If the receiver is currently full, it will await capacity to enqueue the message
74    pub async fn send<M>(&self, message: M)
75    where
76        A: Handler<M>,
77        M: Message,
78    {
79        let env = Envelope::pack(message);
80
81        // TODO: Decide what to do here
82        let _ = self.sender.send(env).await;
83    }
84
85    pub fn try_send<M>(&self, message: M)
86    where
87        A: Handler<M>,
88        M: Message,
89    {
90        let env = Envelope::pack(message);
91
92        // TODO: Decide what to do here
93        let _ = self.sender.try_send(env);
94    }
95}