futures_util/future/
lazy.rs

1//! Definition of the Lazy combinator, deferring execution of a function until
2//! the future is polled.
3
4use core::mem;
5
6use futures_core::{Future, IntoFuture, Poll};
7use futures_core::task;
8
9/// A future which defers creation of the actual future until the future
10/// is `poll`ed.
11///
12/// This is created by the `lazy` function.
13#[derive(Debug)]
14#[must_use = "futures do nothing unless polled"]
15pub struct Lazy<R: IntoFuture, F> {
16    inner: _Lazy<R::Future, F>,
17}
18
19#[derive(Debug)]
20enum _Lazy<R, F> {
21    First(F),
22    Second(R),
23    Moved,
24}
25
26/// Creates a new future which will eventually be the same as the one created
27/// by the closure provided.
28///
29/// The provided closure is only run once the future is polled.
30/// Once run, however, this future is the same as the one the closure creates.
31///
32/// # Examples
33///
34/// ```
35/// # extern crate futures;
36/// use futures::prelude::*;
37/// use futures::future::{self, FutureResult};
38///
39/// # fn main() {
40/// let a = future::lazy(|_| future::ok::<u32, u32>(1));
41///
42/// let b = future::lazy(|_| -> FutureResult<u32, u32> {
43///     panic!("oh no!")
44/// });
45/// drop(b); // closure is never run
46/// # }
47/// ```
48pub fn lazy<R, F>(f: F) -> Lazy<R, F>
49    where F: FnOnce(&mut task::Context) -> R,
50          R: IntoFuture
51{
52    Lazy {
53        inner: _Lazy::First(f),
54    }
55}
56
57impl<R, F> Lazy<R, F>
58    where F: FnOnce(&mut task::Context) -> R,
59          R: IntoFuture,
60{
61    fn get(&mut self, cx: &mut task::Context) -> &mut R::Future {
62        match self.inner {
63            _Lazy::First(_) => {}
64            _Lazy::Second(ref mut f) => return f,
65            _Lazy::Moved => panic!(), // can only happen if `f()` panics
66        }
67        match mem::replace(&mut self.inner, _Lazy::Moved) {
68            _Lazy::First(f) => self.inner = _Lazy::Second(f(cx).into_future()),
69            _ => panic!(), // we already found First
70        }
71        match self.inner {
72            _Lazy::Second(ref mut f) => f,
73            _ => panic!(), // we just stored Second
74        }
75    }
76}
77
78impl<R, F> Future for Lazy<R, F>
79    where F: FnOnce(&mut task::Context) -> R,
80          R: IntoFuture,
81{
82    type Item = R::Item;
83    type Error = R::Error;
84
85    fn poll(&mut self, cx: &mut task::Context) -> Poll<R::Item, R::Error> {
86        self.get(cx).poll(cx)
87    }
88}