act_zero/actor.rs
1use std::error::Error;
2use std::future::Future;
3use std::mem;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6
7use async_trait::async_trait;
8use futures::channel::oneshot;
9use futures::future::FutureExt;
10use log::error;
11
12use crate::Addr;
13
14/// The type of error returned by an actor method.
15pub type ActorError = Box<dyn Error + Send + Sync>;
16/// Short alias for a `Result<Produces<T>, ActorError>`.
17pub type ActorResult<T> = Result<Produces<T>, ActorError>;
18
19/// A concrete type similar to a `BoxFuture<'static, Result<T, oneshot::Canceled>>`, but
20/// without requiring an allocation if the value is immediately ready.
21/// This type implements the `Future` trait and can be directly `await`ed.
22#[derive(Debug)]
23#[non_exhaustive]
24pub enum Produces<T> {
25 /// No value was produced.
26 None,
27 /// A value is ready.
28 Value(T),
29 /// A value may be sent in the future.
30 Deferred(oneshot::Receiver<Produces<T>>),
31}
32
33impl<T> Unpin for Produces<T> {}
34
35impl<T> Produces<T> {
36 /// Returns `Ok(Produces::Value(value))`
37 pub fn ok(value: T) -> ActorResult<T> {
38 Ok(Produces::Value(value))
39 }
40}
41
42impl<T> Future for Produces<T> {
43 type Output = Result<T, oneshot::Canceled>;
44
45 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
46 loop {
47 break match mem::replace(&mut *self, Produces::None) {
48 Produces::None => Poll::Ready(Err(oneshot::Canceled)),
49 Produces::Value(value) => Poll::Ready(Ok(value)),
50 Produces::Deferred(mut recv) => match recv.poll_unpin(cx) {
51 Poll::Ready(Ok(producer)) => {
52 *self = producer;
53 continue;
54 }
55 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
56 Poll::Pending => {
57 *self = Produces::Deferred(recv);
58 Poll::Pending
59 }
60 },
61 };
62 }
63 }
64}
65
66/// Trait implemented by all actors.
67/// This trait is defined using the `#[async_trait]` attribute:
68/// ```ignore
69/// #[async_trait]
70/// pub trait Actor: Send + 'static {
71/// /// Called automatically when an actor is started. Actors can use this
72/// /// to store their own address for future use.
73/// async fn started(&mut self, _addr: Addr<Self>) -> ActorResult<()>
74/// where
75/// Self: Sized,
76/// {
77/// Ok(())
78/// }
79///
80/// /// Called when any actor method returns an error. If this method
81/// /// returns `true`, the actor will stop.
82/// /// The default implementation logs the error using the `log` crate
83/// /// and then stops the actor.
84/// async fn error(&mut self, error: ActorError) -> bool {
85/// error!("{}", error);
86/// true
87/// }
88/// }
89/// ```
90///
91/// In order to use a trait object with the actor system, such as with `Addr<dyn Trait>`,
92/// the trait must extend this `Actor` trait.
93#[async_trait]
94pub trait Actor: Send + 'static {
95 /// Called automatically when an actor is started. Actors can use this
96 /// to store their own address for future use.
97 async fn started(&mut self, _addr: Addr<Self>) -> ActorResult<()>
98 where
99 Self: Sized,
100 {
101 Produces::ok(())
102 }
103
104 /// Called when any actor method returns an error. If this method
105 /// returns `true`, the actor will stop.
106 /// The default implementation logs the error using the `log` crate
107 /// and then stops the actor.
108 async fn error(&mut self, error: ActorError) -> bool {
109 error!("{}", error);
110 true
111 }
112}
113
114/// Actor methods may return any type implementing this trait.
115pub trait IntoActorResult {
116 /// The type to be sent back to the caller.
117 type Output;
118 /// Perform the conversion to an ActorResult.
119 fn into_actor_result(self) -> ActorResult<Self::Output>;
120}
121
122impl<T> IntoActorResult for ActorResult<T> {
123 type Output = T;
124 fn into_actor_result(self) -> ActorResult<T> {
125 self
126 }
127}
128
129impl IntoActorResult for () {
130 type Output = ();
131 fn into_actor_result(self) -> ActorResult<()> {
132 Produces::ok(())
133 }
134}