must_done/
lib.rs

1use std::{future::Future, task::Poll};
2
3pin_project_lite::pin_project! {
4    pub struct MustDoneFuture<F> {
5        #[pin]
6        inner: F,
7        guard: Option<Guard>,
8    }
9}
10
11pub trait MustDone {
12    fn must_done(self) -> MustDoneFuture<Self>
13    where
14        Self: Sized;
15}
16
17impl<F: Future> Future for MustDoneFuture<F> {
18    type Output = F::Output;
19
20    #[inline]
21    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
22        let this = self.project();
23        match this.inner.poll(cx) {
24            Poll::Ready(r) => {
25                std::mem::forget(this.guard.take());
26                Poll::Ready(r)
27            }
28            Poll::Pending => Poll::Pending,
29        }
30    }
31}
32
33impl<F> MustDoneFuture<F> {
34    #[inline]
35    pub fn new(inner: F) -> Self {
36        Self {
37            inner,
38            guard: Some(Guard),
39        }
40    }
41}
42
43impl<F> From<F> for MustDoneFuture<F> {
44    #[inline]
45    fn from(value: F) -> Self {
46        Self::new(value)
47    }
48}
49
50impl<T: Future + Sized> MustDone for T {
51    #[inline]
52    fn must_done(self) -> MustDoneFuture<Self>
53    where
54        Self: Sized,
55    {
56        MustDoneFuture::new(self)
57    }
58}
59
60struct Guard;
61
62impl Drop for Guard {
63    fn drop(&mut self) {
64        extern "C" {
65            #[link_name = "oops"]
66            fn trigger() -> !;
67        }
68
69        unsafe { trigger() };
70    }
71}