use std::pin::Pin;
pub struct Guard<T: Send + 'static> {
future: Option<Pin<Box<dyn Future<Output = T> + Send>>>,
}
impl<T: Send + 'static> Future for Guard<T> {
type Output = T;
fn poll(
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
if let Some(future) = self.future.as_mut() {
match future.as_mut().poll(cx) {
std::task::Poll::Ready(value) => {
self.future = None;
std::task::Poll::Ready(value)
}
std::task::Poll::Pending => std::task::Poll::Pending,
}
} else {
panic!("Guard polled after completion");
}
}
}
impl<T: Send + 'static> Drop for Guard<T> {
fn drop(&mut self) {
if let Some(future) = self.future.take() {
tokio::spawn(future);
}
}
}
pub trait GuardExt: Future
where
Self::Output: Send + 'static,
{
fn guarded(self) -> Guard<Self::Output>;
}
impl<F: Future + Send + 'static> GuardExt for F
where
F::Output: Send + 'static,
{
fn guarded(self) -> Guard<F::Output> {
Guard { future: Some(Box::pin(self)) }
}
}