1 | use core::pin::Pin; |
2 | use futures_core::future::{FusedFuture, Future}; |
3 | use futures_core::task::{Context, Poll}; |
4 | use pin_project_lite::pin_project; |
5 | |
6 | pin_project! { |
7 | /// Future for the [`fuse`](super::FutureExt::fuse) method. |
8 | #[derive(Debug)] |
9 | #[must_use = "futures do nothing unless you `.await` or poll them" ] |
10 | pub struct Fuse<Fut> { |
11 | #[pin] |
12 | inner: Option<Fut>, |
13 | } |
14 | } |
15 | |
16 | impl<Fut> Fuse<Fut> { |
17 | pub(super) fn new(f: Fut) -> Self { |
18 | Self { inner: Some(f) } |
19 | } |
20 | } |
21 | |
22 | impl<Fut: Future> Fuse<Fut> { |
23 | /// Creates a new `Fuse`-wrapped future which is already terminated. |
24 | /// |
25 | /// This can be useful in combination with looping and the `select!` |
26 | /// macro, which bypasses terminated futures. |
27 | /// |
28 | /// # Examples |
29 | /// |
30 | /// ``` |
31 | /// # futures::executor::block_on(async { |
32 | /// use futures::channel::mpsc; |
33 | /// use futures::future::{Fuse, FusedFuture, FutureExt}; |
34 | /// use futures::select; |
35 | /// use futures::stream::StreamExt; |
36 | /// use futures::pin_mut; |
37 | /// |
38 | /// let (sender, mut stream) = mpsc::unbounded(); |
39 | /// |
40 | /// // Send a few messages into the stream |
41 | /// sender.unbounded_send(()).unwrap(); |
42 | /// sender.unbounded_send(()).unwrap(); |
43 | /// drop(sender); |
44 | /// |
45 | /// // Use `Fuse::terminated()` to create an already-terminated future |
46 | /// // which may be instantiated later. |
47 | /// let foo_printer = Fuse::terminated(); |
48 | /// pin_mut!(foo_printer); |
49 | /// |
50 | /// loop { |
51 | /// select! { |
52 | /// _ = foo_printer => {}, |
53 | /// () = stream.select_next_some() => { |
54 | /// if !foo_printer.is_terminated() { |
55 | /// println!("Foo is already being printed!" ); |
56 | /// } else { |
57 | /// foo_printer.set(async { |
58 | /// // do some other async operations |
59 | /// println!("Printing foo from `foo_printer` future" ); |
60 | /// }.fuse()); |
61 | /// } |
62 | /// }, |
63 | /// complete => break, // `foo_printer` is terminated and the stream is done |
64 | /// } |
65 | /// } |
66 | /// # }); |
67 | /// ``` |
68 | pub fn terminated() -> Self { |
69 | Self { inner: None } |
70 | } |
71 | } |
72 | |
73 | impl<Fut: Future> FusedFuture for Fuse<Fut> { |
74 | fn is_terminated(&self) -> bool { |
75 | self.inner.is_none() |
76 | } |
77 | } |
78 | |
79 | impl<Fut: Future> Future for Fuse<Fut> { |
80 | type Output = Fut::Output; |
81 | |
82 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Fut::Output> { |
83 | match self.as_mut().project().inner.as_pin_mut() { |
84 | Some(fut) => fut.poll(cx).map(|output| { |
85 | self.project().inner.set(None); |
86 | output |
87 | }), |
88 | None => Poll::Pending, |
89 | } |
90 | } |
91 | } |
92 | |