use std::fmt::Debug;
use futures::future::BoxFuture;
use smol::{
channel::{
self,
Sender,
Receiver,
},
};
struct Message<S> {
func: Box<dyn for<'a> FnOnce(&'a mut S) -> BoxFuture<'a, ()> + Send>,
}
#[derive(Clone)]
pub struct Actor<S>
where
S: Send + 'static
{
tx: Sender<Message<S>>,
}
impl<S> Actor<S>
where
S: Default + Send + 'static
{
pub fn new() -> Self {
Self::from_state(S::default())
}
}
impl<S> Actor<S>
where
S: Send + 'static
{
pub fn from_state(state: S) -> Self {
let (tx, rx) = channel::unbounded();
smol::spawn(async move {
Self::run(state, rx).await
}).detach();
Self { tx }
}
async fn run(mut state: S, rx: Receiver<Message<S>>) {
while let Ok(msg) = rx.recv().await {
(msg.func)(&mut state).await;
}
}
pub async fn cast<F>(&self, f: F)
where
F: for<'a> FnOnce(&'a mut S) -> BoxFuture<'a, ()>,
F: 'static + Send,
{
let msg = Message {
func: Box::new(move |state| Box::pin(async move {
f(state).await;
}))
};
let _ = self.tx.send(msg).await;
}
pub async fn call<F, R>(&self, f: F) -> R
where
F: for<'a> FnOnce(&'a mut S) -> BoxFuture<'a, R>,
F: 'static + Send,
R: 'static + Send + Debug,
{
let (tx, rx) = channel::bounded(1);
let msg = Message {
func: Box::new(move |state| Box::pin(async move {
let res = f(state).await;
let _ = tx.send(res).await;
}))
};
let _ = self.tx.send(msg).await;
rx.recv().await
.expect("Actor is gone")
}
pub async fn flush(&self) {
self.call(|_| Box::pin(async move {})).await
}
}