futures_util/future/future/
map.rs

1use core::pin::Pin;
2use futures_core::future::{FusedFuture, Future};
3use futures_core::ready;
4use futures_core::task::{Context, Poll};
5use pin_project_lite::pin_project;
6
7use crate::fns::FnOnce1;
8
9pin_project! {
10    /// Internal Map future
11    #[project = MapProj]
12    #[project_replace = MapProjReplace]
13    #[derive(Debug)]
14    #[must_use = "futures do nothing unless you `.await` or poll them"]
15    pub enum Map<Fut, F> {
16        Incomplete {
17            #[pin]
18            future: Fut,
19            f: F,
20        },
21        Complete,
22    }
23}
24
25impl<Fut, F> Map<Fut, F> {
26    /// Creates a new Map.
27    pub(crate) fn new(future: Fut, f: F) -> Self {
28        Self::Incomplete { future, f }
29    }
30}
31
32impl<Fut, F, T> FusedFuture for Map<Fut, F>
33where
34    Fut: Future,
35    F: FnOnce1<Fut::Output, Output = T>,
36{
37    fn is_terminated(&self) -> bool {
38        match self {
39            Self::Incomplete { .. } => false,
40            Self::Complete => true,
41        }
42    }
43}
44
45impl<Fut, F, T> Future for Map<Fut, F>
46where
47    Fut: Future,
48    F: FnOnce1<Fut::Output, Output = T>,
49{
50    type Output = T;
51
52    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
53        match self.as_mut().project() {
54            MapProj::Incomplete { future, .. } => {
55                let output = ready!(future.poll(cx));
56                match self.project_replace(Self::Complete) {
57                    MapProjReplace::Incomplete { f, .. } => Poll::Ready(f.call_once(output)),
58                    MapProjReplace::Complete => unreachable!(),
59                }
60            }
61            MapProj::Complete => {
62                panic!("Map must not be polled after it returned `Poll::Ready`")
63            }
64        }
65    }
66}