use std::future::Future;
use std::sync::Arc;
use futures::future::abortable;
use futures::future::AbortHandle;
pub fn spawn_controlled<T>(t: T) -> ControlledHandle
where
T: Future + Send + 'static,
T::Output: Send + 'static,
{
let (abortable_future, abort_handle) = abortable(t);
tokio::task::spawn(abortable_future);
ControlledHandle::new(abort_handle)
}
#[derive(Clone, Debug)]
pub struct ControlledHandle(Arc<Inner>);
impl ControlledHandle {
fn new(abort_handle: AbortHandle) -> Self {
Self(Arc::new(Inner(abort_handle)))
}
}
#[derive(Debug)]
struct Inner(AbortHandle);
impl Drop for Inner {
fn drop(&mut self) {
self.0.abort();
}
}
#[cfg(test)]
mod tests {
use tokio::sync::mpsc;
use super::*;
fn handle_and_counting_receiver() -> (ControlledHandle, mpsc::Receiver<u64>) {
let (tx, rx) = mpsc::channel(1);
let handle = spawn_controlled(async move {
let mut x: u64 = 0;
loop {
tx.send(x).await.unwrap();
x += 1;
}
});
(handle, rx)
}
#[tokio::test]
async fn test_no_handles_abort() {
let (handle, mut rx) = handle_and_counting_receiver();
assert_eq!(rx.recv().await, Some(0));
{
let _ = handle.clone();
}
assert_eq!(rx.recv().await, Some(1));
drop(handle);
assert_eq!(rx.recv().await, None);
}
}