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}