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}