use std::error::Error;
use std::future::Future;
use std::mem;
use std::pin::Pin;
use std::task::{Context, Poll};
use async_trait::async_trait;
use futures::channel::oneshot;
use futures::future::FutureExt;
use log::error;
use crate::Addr;
pub type ActorError = Box<dyn Error + Send + Sync>;
pub type ActorResult<T> = Result<Produces<T>, ActorError>;
#[derive(Debug)]
#[non_exhaustive]
pub enum Produces<T> {
None,
Value(T),
Deferred(oneshot::Receiver<Produces<T>>),
}
impl<T> Unpin for Produces<T> {}
impl<T> Produces<T> {
pub fn ok(value: T) -> ActorResult<T> {
Ok(Produces::Value(value))
}
}
impl<T> Future for Produces<T> {
type Output = Result<T, oneshot::Canceled>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
break match mem::replace(&mut *self, Produces::None) {
Produces::None => Poll::Ready(Err(oneshot::Canceled)),
Produces::Value(value) => Poll::Ready(Ok(value)),
Produces::Deferred(mut recv) => match recv.poll_unpin(cx) {
Poll::Ready(Ok(producer)) => {
*self = producer;
continue;
}
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Pending => {
*self = Produces::Deferred(recv);
Poll::Pending
}
},
};
}
}
}
#[async_trait]
pub trait Actor: Send + 'static {
async fn started(&mut self, _addr: Addr<Self>) -> ActorResult<()>
where
Self: Sized,
{
Produces::ok(())
}
async fn error(&mut self, error: ActorError) -> bool {
error!("{}", error);
true
}
}
pub trait IntoActorResult {
type Output;
fn into_actor_result(self) -> ActorResult<Self::Output>;
}
impl<T> IntoActorResult for ActorResult<T> {
type Output = T;
fn into_actor_result(self) -> ActorResult<T> {
self
}
}
impl IntoActorResult for () {
type Output = ();
fn into_actor_result(self) -> ActorResult<()> {
Produces::ok(())
}
}