puppet/
lib.rs

1use futures::channel::oneshot;
2use std::borrow::Cow;
3use std::future::Future;
4
5pub use puppet_derive::puppet_actor;
6
7// Not public API. Used by generated code.
8#[doc(hidden)]
9pub mod __private {
10    pub use flume;
11    pub use futures;
12
13    #[cfg(feature = "helper-methods")]
14    pub use tokio;
15}
16
17/// A derived actor handler.
18pub trait Actor {
19    /// The derive actor messages.
20    type Messages;
21}
22
23/// An actor message.
24pub trait Message {
25    /// The response type of the message.
26    type Output;
27}
28
29/// A custom executor to spawn actors into.
30pub trait Executor {
31    fn spawn(&self, fut: impl Future<Output = ()> + Send + 'static);
32}
33
34// Not public API. Used by generated code.
35#[doc(hidden)]
36pub trait MessageHandler<T: Message> {
37    fn create(msg: T) -> (Self, oneshot::Receiver<T::Output>)
38    where
39        Self: Sized;
40}
41
42/// A actor mailbox.
43///
44/// This is a cheap to clone way of contacting the actor and sending messages.
45pub struct ActorMailbox<A: Actor> {
46    tx: flume::Sender<A::Messages>,
47    name: Cow<'static, str>,
48}
49
50impl<A: Actor> Clone for ActorMailbox<A> {
51    fn clone(&self) -> Self {
52        Self {
53            tx: self.tx.clone(),
54            name: self.name.clone(),
55        }
56    }
57}
58
59impl<A: Actor> ActorMailbox<A> {
60    // Not public API. Used by generated code.
61    #[doc(hidden)]
62    /// Creates a new actor mailbox.
63    ///
64    /// This should only really be made by the derive system.
65    pub fn new(tx: flume::Sender<A::Messages>, name: Cow<'static, str>) -> Self {
66        Self { tx, name }
67    }
68
69    #[inline]
70    /// The name of the actor.
71    ///
72    /// This can be set by calling `actor.spawn_actor_with_name` or `actor.spawn_actor_with_name_and_size`
73    pub fn name(&self) -> &str {
74        self.name.as_ref()
75    }
76
77    /// Sends a message to the actor and waits for a response back.
78    pub async fn send<T>(&self, msg: T) -> T::Output
79    where
80        T: Message,
81        A::Messages: MessageHandler<T>,
82    {
83        let (msg, rx) = A::Messages::create(msg);
84        self.tx.send_async(msg).await.expect("Contact actor");
85        rx.await.expect("Actor response")
86    }
87
88    /// Sends a message to the actor and returns a deferred response.
89    ///
90    /// This does not wait for the returned message.
91    pub async fn deferred_send<T>(&self, msg: T) -> DeferredResponse<T::Output>
92    where
93        T: Message,
94        A::Messages: MessageHandler<T>,
95    {
96        let (msg, rx) = A::Messages::create(msg);
97        self.tx.send_async(msg).await.expect("Contact actor");
98        DeferredResponse { rx }
99    }
100
101    /// Sends a message to the actor and waits for a response back.
102    ///
103    /// This a sync variant which will block the thread until the message is returned.
104    pub fn send_sync<T>(&self, msg: T) -> T::Output
105    where
106        T: Message,
107        A::Messages: MessageHandler<T>,
108    {
109        let (msg, rx) = A::Messages::create(msg);
110        self.tx.send(msg).expect("Contact actor");
111        futures::executor::block_on(rx).expect("Actor response")
112    }
113}
114
115/// A deferred response from the actor.
116///
117/// This can be used to schedule a message while not waiting for the result.
118pub struct DeferredResponse<T> {
119    rx: oneshot::Receiver<T>,
120}
121
122impl<T> DeferredResponse<T> {
123    /// Attempts to get the result of the response immediately.
124    pub fn try_recv(&mut self) -> Option<T> {
125        self.rx.try_recv().expect("Get actor response")
126    }
127
128    /// Waits for the response by the actor.
129    pub async fn recv(self) -> T {
130        self.rx.await.expect("Get actor response")
131    }
132}
133
134/// A reply handle.
135///
136/// Because it cannot be guaranteed that the reply will be called,
137/// we require that response `T` implements default to act as a safe reply
138/// method if `reply()` is not called directly.
139pub struct Reply<T: Default> {
140    tx: Option<oneshot::Sender<T>>,
141}
142
143impl<T: Default> From<oneshot::Sender<T>> for Reply<T> {
144    fn from(tx: oneshot::Sender<T>) -> Self {
145        Self { tx: Some(tx) }
146    }
147}
148
149impl<T: Default> Reply<T> {
150    /// Responds to the actor message.
151    pub fn reply(mut self, msg: T) {
152        if let Some(tx) = self.tx.take() {
153            let _ = tx.send(msg);
154        }
155    }
156}
157
158impl<T: Default> Drop for Reply<T> {
159    fn drop(&mut self) {
160        if let Some(tx) = self.tx.take() {
161            let _ = tx.send(T::default());
162        }
163    }
164}
165
166#[macro_export]
167/// A helper macro for deriving the [Message] trait.
168macro_rules! derive_message {
169    ($msg:ident, $output:ty) => {
170        impl $crate::Message for $msg {
171            type Output = $output;
172        }
173    };
174}