use crate::{error::Error, fold::{self, dynamic_fold}};
use futures::{
future::{self, Either::{A, B}, Executor},
prelude::*,
sink,
sync::mpsc
};
use parking_lot::Mutex;
use std::{fmt, marker::PhantomData, sync::{atomic::{AtomicUsize, Ordering}, Arc}};
use void::Void;
pub trait Actor<T, E> where Self: Sized {
type Result: Future<Item = State<Self, T>, Error = E>;
fn process(self, ctx: &mut Context<T>, msg: Option<T>) -> Self::Result;
}
pub enum State<A, T> {
Ready(A),
Stream(A, Box<dyn Stream<Item = T, Error = Void> + Send>),
Close(A),
Done
}
impl<A, T> fmt::Debug for State<A, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
State::Ready(..) => f.write_str("State::Ready"),
State::Stream(..) => f.write_str("State::Stream"),
State::Close(..) => f.write_str("State::Close"),
State::Done => f.write_str("State::Done")
}
}
}
impl<A, T> Into<fold::State<A, T, ()>> for State<A, T> {
fn into(self) -> fold::State<A, T, ()> {
match self {
State::Ready(a) => fold::State::Ready(a),
State::Stream(a, s) => fold::State::Stream(a, s),
State::Close(a) => fold::State::Close(a),
State::Done => fold::State::Done(())
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Id(usize);
impl Id {
pub fn as_usize(self) -> usize {
self.0
}
}
impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
pub struct Addr<T, A = T> {
id: Id,
outgoing: mpsc::Sender<T>,
marker: PhantomData<A>
}
impl<T, A: Into<T>> Addr<T, A> {
pub fn id(&self) -> Id {
self.id
}
pub fn send(self, msg: A) -> impl Future<Item = Self, Error = Error> {
SendOne(self.id, self.outgoing.send(msg.into()), self.marker)
}
pub fn send_now(&mut self, msg: A) -> Result<(), Error> {
self.outgoing.try_send(msg.into()).map_err(|e| {
if e.is_full() {
return Error::MailboxFull
}
if e.is_disconnected() {
return Error::ActorGone
}
unreachable!("Impossible TrySendError")
})
}
pub fn cast<B: Into<T>>(&self) -> Addr<T, B> {
Addr {
id: self.id,
outgoing: self.outgoing.clone(),
marker: PhantomData
}
}
}
impl<T, A> Clone for Addr<T, A> {
fn clone(&self) -> Self {
Addr {
id: self.id,
outgoing: self.outgoing.clone(),
marker: self.marker
}
}
}
impl<T, A> fmt::Debug for Addr<T, A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Addr").field("id", &self.id).finish()
}
}
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct SendOne<T, A>(Id, sink::Send<mpsc::Sender<T>>, PhantomData<A>);
impl<T, A> Future for SendOne<T, A> {
type Item = Addr<T, A>;
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.1.poll() {
Ok(Async::Ready(s)) =>
Ok(Async::Ready(Addr {
id: self.0,
outgoing: s,
marker: self.2
})),
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(_) => Err(Error::ActorGone)
}
}
}
#[derive(Debug)]
pub struct Context<T> {
addr: Addr<T>,
exec: Scheduler
}
impl<T> Context<T> {
pub fn id(&self) -> Id {
self.addr.id()
}
pub fn address(&self) -> Addr<T> {
self.addr.clone()
}
pub fn scheduler(&self) -> &Scheduler {
&self.exec
}
}
#[derive(Debug)]
pub struct Fail<E> {
id: Id,
error: E
}
impl<E> Fail<E> {
pub fn id(&self) -> Id {
self.id
}
pub fn error(&self) -> &E {
&self.error
}
pub fn into_error(self) -> E {
self.error
}
}
#[derive(Debug)]
pub struct Options<F> {
backlog: u32,
supervisor: Option<Addr<F>>
}
impl<F> Default for Options<F> {
fn default() -> Self {
Self { backlog: 1000, supervisor: None }
}
}
impl<F> Options<F> {
pub fn backlog(self, n: u32) -> Self {
Self { backlog: n, .. self }
}
pub fn supervisor(self, p: Addr<F>) -> Self {
Self { supervisor: Some(p), .. self }
}
}
#[derive(Clone)]
pub struct Scheduler {
exec: Arc<dyn Executor<Box<dyn Future<Item = (), Error = ()> + Send>> + Send + Sync>,
counter: Arc<AtomicUsize>
}
impl Scheduler {
pub fn new<E>(e: E) -> Self
where
E: Executor<Box<dyn Future<Item = (), Error = ()> + Send>> + Send + Sync + 'static
{
Scheduler {
exec: Arc::new(e),
counter: Arc::new(AtomicUsize::new(0))
}
}
pub fn single_threaded<E>(e: E) -> Self
where
E: Executor<Box<dyn Future<Item = (), Error = ()> + Send>> + Send + 'static
{
struct SyncExec<E>(Mutex<E>);
impl<E, F> Executor<F> for SyncExec<E>
where
E: Executor<F>,
F: Future<Item = (), Error = ()>
{
fn execute(&self, future: F) -> Result<(), future::ExecuteError<F>> {
self.0.lock().execute(future)
}
}
Scheduler::new(SyncExec(Mutex::new(e)))
}
pub fn spawn<A, T, E>(&self, a: A) -> Result<Addr<T>, Error>
where
A: Actor<T, E> + Send + 'static,
T: Send + 'static,
E: Send + 'static,
<A as Actor<T, E>>::Result: Send + 'static
{
let opts: Options<Fail<E>> = Default::default();
self.spawn_ext(a, opts)
}
pub fn spawn_ext<A, T, E, F>(&self, a: A, opts: Options<F>) -> Result<Addr<T>, Error>
where
A: Actor<T, E> + Send + 'static,
T: Send + 'static,
E: Send + 'static,
F: From<Fail<E>> + Send + 'static,
<A as Actor<T, E>>::Result: Send + 'static
{
let id = Id(self.counter.fetch_add(1, Ordering::Relaxed));
let (tx_main, rx_main) = mpsc::channel(opts.backlog as usize);
let addr = Addr {
id,
outgoing: tx_main,
marker: PhantomData
};
let mut ctx = Context { addr: addr.clone(), exec: self.clone() };
let future = dynamic_fold(a, rx_main, move |actor, item| {
actor.process(&mut ctx, item).map(Into::into)
})
.map(|_| ())
.or_else(move |e| {
if let Some(p) = opts.supervisor {
let f = Fail { id, error: e };
A(p.send(f.into()).then(|_| Ok(())))
} else {
B(future::ok(()))
}
});
self.exec.execute(Box::new(future)).map_err(|_| Error::SpawnError)?;
Ok(addr)
}
pub fn execute<F>(&self, future: F) -> Result<(), Error>
where
F: Future<Item = (), Error = ()> + Send + 'static
{
self.exec.execute(Box::new(future)).map_err(|_| Error::SpawnError)
}
}
impl fmt::Debug for Scheduler {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("Scheduler")
}
}