futures_util/future/future/fuse.rs
1use core::pin::Pin;
2use futures_core::future::{FusedFuture, Future};
3use futures_core::task::{Context, Poll};
4use pin_project_lite::pin_project;
5
6pin_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
16impl<Fut> Fuse<Fut> {
17 pub(super) fn new(f: Fut) -> Self {
18 Self { inner: Some(f) }
19 }
20}
21
22impl<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 core::pin::pin;
33 ///
34 /// use futures::channel::mpsc;
35 /// use futures::future::{Fuse, FusedFuture, FutureExt};
36 /// use futures::select;
37 /// use futures::stream::StreamExt;
38 ///
39 /// let (sender, mut stream) = mpsc::unbounded();
40 ///
41 /// // Send a few messages into the stream
42 /// sender.unbounded_send(()).unwrap();
43 /// sender.unbounded_send(()).unwrap();
44 /// drop(sender);
45 ///
46 /// // Use `Fuse::terminated()` to create an already-terminated future
47 /// // which may be instantiated later.
48 /// let foo_printer = Fuse::terminated();
49 /// let mut foo_printer = pin!(foo_printer);
50 ///
51 /// loop {
52 /// select! {
53 /// _ = foo_printer => {},
54 /// () = stream.select_next_some() => {
55 /// if !foo_printer.is_terminated() {
56 /// println!("Foo is already being printed!");
57 /// } else {
58 /// foo_printer.set(async {
59 /// // do some other async operations
60 /// println!("Printing foo from `foo_printer` future");
61 /// }.fuse());
62 /// }
63 /// },
64 /// complete => break, // `foo_printer` is terminated and the stream is done
65 /// }
66 /// }
67 /// # });
68 /// ```
69 pub fn terminated() -> Self {
70 Self { inner: None }
71 }
72}
73
74impl<Fut: Future> FusedFuture for Fuse<Fut> {
75 fn is_terminated(&self) -> bool {
76 self.inner.is_none()
77 }
78}
79
80impl<Fut: Future> Future for Fuse<Fut> {
81 type Output = Fut::Output;
82
83 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Fut::Output> {
84 match self.as_mut().project().inner.as_pin_mut() {
85 Some(fut) => fut.poll(cx).map(|output| {
86 self.project().inner.set(None);
87 output
88 }),
89 None => Poll::Pending,
90 }
91 }
92}