use crate::Result;
use tokio::sync::watch;
#[cfg(test)]
mod tests;
pub struct Handle {
join_blocks: tokio::task::JoinHandle<Result<()>>,
close: Close,
}
struct Close {
close_blocks: watch::Sender<()>,
}
impl Handle {
pub fn new(
join_blocks: tokio::task::JoinHandle<Result<()>>,
close_blocks: watch::Sender<()>,
) -> Self {
Self {
join_blocks,
close: Close { close_blocks },
}
}
pub async fn close(self) -> Result<()> {
let Self { join_blocks, close } = self;
close.close();
let br = join_blocks.await;
flatten_result(br)
}
pub async fn join(self) -> Result<()> {
let Self { join_blocks, close } = self;
let r = join_blocks.await;
close.close();
flatten_result(r)
}
}
impl Close {
fn close(&self) {
let _ = self.close_blocks.send(());
}
}
fn flatten_result(result: std::result::Result<Result<()>, tokio::task::JoinError>) -> Result<()> {
match result {
Ok(r) => r,
Err(e) => {
if e.is_panic() {
std::panic::resume_unwind(e.into_panic())
} else {
Ok(())
}
}
}
}
impl Drop for Close {
fn drop(&mut self) {
self.close();
}
}