You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yuurei/src/state/local/host.rs

80 lines
1.6 KiB

//! Hosts `Imouto`'s `Kokoro`.
use super::*;
use std::{
pin::Pin,
task::{
Poll,
Context,
},
mem,
};
use pin_project::{
pin_project,
};
use futures::{
future::Future,
};
use tokio::{
task,
sync::{
oneshot,
mpsc,
},
};
#[derive(Debug)]
pub enum Worker
{
Attached(task::JoinHandle<Result<(), eyre::Report>>),
/// Worker has not been attached yet
Suspended(Kokoro),
/// Worker filed to spawn,
Crashed,
}
/// Host this `Kokoro`
async fn work(mut kokoro: Kokoro, mut recv: mpsc::Receiver<Vec<Delta>>) -> Result<(), eyre::Report>
{
while let Some(new) = recv.recv().await {
kokoro.apply(new).await?;
}
Ok(())
}
impl Worker
{
/// Host this suspended state worker with a channel to receive updates from.
///
/// # Panics
/// If we are not in the `Suspended` state.
pub fn host(&mut self, recv: mpsc::Receiver<Vec<Delta>>) -> WorkerHandle
{
match mem::replace(self, Self::Crashed) {
Self::Suspended(kokoro) => {
let (tx, rx) = oneshot::channel();
*self = Self::Attached(task::spawn(async move {
let vl = work(kokoro, recv).await;
tx.send(()).unwrap();
vl
}));
WorkerHandle(rx)
},
_ => panic!("Attempted to host non-suspended worker"),
}
}
}
/// A handle on a spawned worker
#[pin_project]
pub struct WorkerHandle(#[pin] oneshot::Receiver<()>);
impl Future for WorkerHandle
{
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
this.0.poll(cx).map(|x| x.unwrap())
}
}