vigil/
dropped.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use futures::future::{FusedFuture, Shared};
6use futures::{Future, FutureExt};
7use std::task::{Context, Poll};
8
9use crate::DropWatch;
10
11/// A future that can be constructed from any impl DropWatch, that completes when the item is dropped.
12#[derive(Clone)]
13#[must_use = "futures do nothing unless you await or poll them"]
14pub struct Dropped(Shared<futures::channel::oneshot::Receiver<()>>);
15
16impl Dropped {
17    pub fn new<DW: DropWatch<U> + ?Sized, U: ?Sized>(watchable: &DW) -> Self {
18        let (sender, receiver) = futures::channel::oneshot::channel();
19        DropWatch::watch(watchable, move |_| {
20            let _ = sender.send(());
21        });
22        Self(receiver.shared())
23    }
24}
25
26impl Future for Dropped {
27    type Output = ();
28
29    fn poll(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
30        self.0.poll_unpin(cx).map(|_| ())
31    }
32}
33
34impl FusedFuture for Dropped {
35    fn is_terminated(&self) -> bool {
36        self.0.is_terminated()
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use async_utils::PollExt;
43    use futures_test::task::new_count_waker;
44
45    use super::*;
46    use crate::Vigil;
47
48    #[test]
49    fn obits() {
50        let v = Vigil::new(());
51
52        let mut obit = Vigil::dropped(&v);
53        let mut obit2 = Vigil::dropped(&v);
54        let mut obit_never_polled = Vigil::dropped(&v);
55
56        let (waker, count) = new_count_waker();
57
58        let mut cx = Context::from_waker(&waker);
59
60        obit.poll_unpin(&mut cx).expect_pending("shouldn't be done");
61        obit2.poll_unpin(&mut cx).expect_pending("shouldn't be done");
62
63        // when dropped, both should be woken.
64        drop(v);
65        // The data should have been dropped.
66        assert_eq!(2, count.get());
67
68        // polling them should be ready.
69        obit.poll_unpin(&mut cx).expect("should be done");
70        obit2.poll_unpin(&mut cx).expect("should also be done");
71
72        // polling the one that hasn't been polled yet should also be ready
73        obit_never_polled.poll_unpin(&mut cx).expect("be done");
74    }
75}