     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99

    //! Definition of the `LoopFn` combinator, implementing `Future` loops.

    use {Async, Future, IntoFuture, Poll};

    /// The status of a `loop_fn` loop.
    #[derive(Debug)]
    pub enum Loop<T, S> {
        /// Indicates that the loop has completed with output `T`.
        Break(T),

        /// Indicates that the loop function should be called again with input
        /// state `S`.
        Continue(S),
    }

    /// A future implementing a tail-recursive loop.
    ///
    /// Created by the `loop_fn` function.
    #[derive(Debug)]
    pub struct LoopFn<A, F> where A: IntoFuture {
        future: A::Future,
        func: F,
    }

    /// Creates a new future implementing a tail-recursive loop.
    ///
    /// The loop function is immediately called with `initial_state` and should
    /// return a value that can be converted to a future. On successful completion,
    /// this future should output a `Loop<T, S>` to indicate the status of the
    /// loop.
    ///
    /// `Loop::Break(T)` halts the loop and completes the future with output `T`.
    ///
    /// `Loop::Continue(S)` reinvokes the loop function with state `S`. The returned
    /// future will be subsequently polled for a new `Loop<T, S>` value.
    ///
    /// # Examples
    ///
    /// ```
    /// use futures::future::{ok, loop_fn, Future, FutureResult, Loop};
    /// use std::io::Error;
    ///
    /// struct Client {
    ///     ping_count: u8,
    /// }
    ///
    /// impl Client {
    ///     fn new() -> Self {
    ///         Client { ping_count: 0 }
    ///     }
    ///
    ///     fn send_ping(self) -> FutureResult<Self, Error> {
    ///         ok(Client { ping_count: self.ping_count + 1 })
    ///     }
    ///
    ///     fn receive_pong(self) -> FutureResult<(Self, bool), Error> {
    ///         let done = self.ping_count >= 5;
    ///         ok((self, done))
    ///     }
    /// }
    ///
    /// let ping_til_done = loop_fn(Client::new(), |client| {
    ///     client.send_ping()
    ///         .and_then(|client| client.receive_pong())
    ///         .and_then(|(client, done)| {
    ///             if done {
    ///                 Ok(Loop::Break(client))
    ///             } else {
    ///                 Ok(Loop::Continue(client))
    ///             }
    ///         })
    /// });
    /// ```
    pub fn loop_fn<S, T, A, F>(initial_state: S, mut func: F) -> LoopFn<A, F>
        where F: FnMut(S) -> A,
              A: IntoFuture<Item = Loop<T, S>>,
    {
        LoopFn {
            future: func(initial_state).into_future(),
            func: func,
        }
    }

    impl<S, T, A, F> Future for LoopFn<A, F>
        where F: FnMut(S) -> A,
              A: IntoFuture<Item = Loop<T, S>>,
    {
        type Item = T;
        type Error = A::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            loop {
                match try_ready!(self.future.poll()) {
                    Loop::Break(x) => return Ok(Async::Ready(x)),
                    Loop::Continue(s) => self.future = (self.func)(s).into_future(),
                }
            }
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)