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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! This module defines various traits and adapters for bridging command
//! execution with futures.
use futures::Future;

mod boxed_result;
mod invert;
mod fuse;
mod pinned;

pub use futures::{Async, Poll};
pub use self::boxed_result::BoxedResult;
pub use self::invert::InvertStatus;
pub use self::fuse::Fuse;
pub use self::pinned::Pinned;

/// A trait for objects that behave exactly like the `Future` trait from the
/// `futures` crate, however, each object must be polled in the context of some
/// environment.
///
/// > Note that `EnvFuture` differs from `Future` when it comes to dropping or
/// > cancelling: callers may need to ensure they call `cancel` on the `EnvFuture`
/// > before dropping it to ensure all environment state has been reset correctly.
/// > See documentation on `poll` and `cancel` for more details.
pub trait EnvFuture<E: ?Sized> {
    /// The type of value that this future will resolved with if it is
    /// successful.
    type Item;
    /// The type of error that this future will resolve with if it fails in a
    /// normal fashion.
    type Error;

    /// Behaves identical to `Future::poll` when polled with a provided environment.
    ///
    /// Caller should take care to always poll this future with the same environment.
    /// An implementation may panic or yield incorrect results if it is polled with
    /// different environments.
    ///
    /// # Panics
    ///
    /// Once a future has completed (returned `Ready` or `Err` from `poll`, or
    /// `cancel` invoked), then any future calls to `poll` may panic, block
    /// forever, or otherwise cause wrong behavior. The `EnvFuture` trait itself
    /// provides no guarantees about the behavior of `poll` after a future has completed.
    ///
    /// Callers who may call `poll` too many times may want to consider using
    /// the `fuse` adaptor which defines the behavior of `poll`, but comes with
    /// a little bit of extra cost.
    ///
    /// Additionally, calls to `poll` must always be made from within the
    /// context of a task. If a current task is not set then this method will
    /// likely panic.
    fn poll(&mut self, env: &mut E) -> Poll<Self::Item, Self::Error>;

    /// Cancel a future and consider it as completed, thus giving it a chance to
    /// run any clean up as if it had resolved on its own.
    ///
    /// Although dropping an `EnvFuture` will effectively cancel it by freeing
    /// all resources and not doing any further work, there is no guarantee
    /// that the future may not have made temporary changes to the environment
    /// it wishes to undo (e.g. temporarily overriding a file descriptor).
    ///
    /// Thus if a caller cares about returning the environment to a valid state,
    /// they must call `cancel` before dropping the future. Cancelling a future
    /// which has never been polled is considered a valid use case, and should
    /// be supported by the implementation.
    ///
    /// Caller should take care to cancel this future with the same environment
    /// that was provided to `poll`. An implementation may panic or yield
    /// incorrect results if it is polled with a different environment.
    ///
    /// # Panics
    ///
    /// If a future has completed (returned `Ready` or `Err` from `poll`, or
    /// `cancel` invoked) then any future calls to `cancel` may panic, block
    /// forever, or otherwise cause wrong behavior. The `EnvFuture` trait itself
    /// provides no guarantees about the behavior of `cancel` after a future has
    /// completed.
    ///
    /// Callers who may call `cancel` too many times may want to consider using
    /// the `fuse` adaptor which defines the behavior of `cancel`, but comes
    /// with a little bit of extra cost.
    fn cancel(&mut self, env: &mut E);

    /// Pin an environment to this future, allowing the resulting future to be
    /// polled from anywhere without needing the caller to specify an environment.
    fn pin_env(self, env: E) -> Pinned<E, Self> where E: Sized, Self: Sized {
        pinned::new(self, env)
    }

    /// Fuse a future such that `poll` and `cancel` will never again be called
    /// once it has completed.
    ///
    /// Currently once a future has returned `Ready` or `Err` from
    /// `poll` or if `cancel` was invoked, any further calls to either method
    /// could exhibit bad behavior such as blocking forever, panicking, never
    /// returning, etc. If it is known that `poll` or `cancel` may be called too
    /// often then this method can be used to ensure that it has defined semantics.
    ///
    /// Once a future has been `fuse`d and it returns a completion from `poll`
    /// or cancelled via `cancel, then it will forever return `NotReady` from
    /// `poll` (never resolve) and will ignore future calls to `cancel`. This,
    /// unlike the trait's `poll` and `cancel` methods, is guaranteed.
    fn fuse(self) -> Fuse<Self> where Self: Sized {
        fuse::new(self)
    }

    /// Converts the resulting future into a boxed trait object.
    ///
    /// In other words, instead of returning a concrete type, this
    /// adapter will return `Box<Future>` which is useful when type
    /// erasure is desired.
    fn boxed_result<'a>(self) -> BoxedResult<'a, Self>
        where Self: Sized,
              Self::Item: 'a + Future,
    {
        boxed_result::new(self)
    }
}

impl<'a, T: ?Sized, E: ?Sized> EnvFuture<E> for &'a mut T where T: EnvFuture<E> {
    type Item = T::Item;
    type Error = T::Error;

    fn poll(&mut self, env: &mut E) -> Poll<Self::Item, Self::Error> {
        (**self).poll(env)
    }

    fn cancel(&mut self, env: &mut E) {
        (**self).cancel(env)
    }
}

impl<T: ?Sized, E: ?Sized> EnvFuture<E> for Box<T> where T: EnvFuture<E> {
    type Item = T::Item;
    type Error = T::Error;

    fn poll(&mut self, env: &mut E) -> Poll<Self::Item, Self::Error> {
        (**self).poll(env)
    }

    fn cancel(&mut self, env: &mut E) {
        (**self).cancel(env)
    }
}