use lunatic::{
channel::{self, Receiver, Sender},
Process,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
pub trait Actor: Sized {
type Input: Serialize + DeserializeOwned;
type Output: Serialize + DeserializeOwned;
fn create() -> Self;
fn handle(&mut self, msg: Self::Input, link: &Link<Self>);
}
pub fn spawn<A: Actor>() -> Bridge<A> {
let (in_sender, in_receiver) = channel::unbounded::<A::Input>();
let (out_sender, out_receiver) = channel::unbounded::<A::Output>();
Process::spawn_with((in_receiver, out_sender), |(receiver, sender)| {
Context {
link: Link { sender, receiver },
actor: A::create(),
}
.run()
})
.detach();
Bridge {
sender: in_sender,
receiver: out_receiver,
}
}
#[derive(Serialize, Deserialize)]
pub struct Bridge<A: Actor> {
sender: Sender<A::Input>,
receiver: Receiver<A::Output>,
}
impl<A: Actor> Bridge<A> {
pub fn send(&self, msg: A::Input) -> Result<(), ()> {
self.sender.send(msg)
}
pub fn receive(&self) -> Result<A::Output, ()> {
self.receiver.receive()
}
}
impl<A: Actor> Clone for Bridge<A> {
fn clone(&self) -> Self {
Self {
sender: self.sender.clone(),
receiver: self.receiver.clone(),
}
}
}
pub struct Link<A: Actor> {
sender: Sender<A::Output>,
receiver: Receiver<A::Input>,
}
impl<A: Actor> Link<A> {
pub fn respond(&self, msg: A::Output) -> Result<(), ()> {
self.sender.send(msg)
}
fn receive(&self) -> Result<A::Input, ()> {
self.receiver.receive()
}
}
struct Context<A: Actor> {
link: Link<A>,
actor: A,
}
impl<A: Actor> Context<A> {
fn run(mut self) {
while let Ok(msg) = self.link.receive() {
self.actor.handle(msg, &self.link);
}
}
}