finchers_core/
task.rs

1//! Components for constructing asynchronous computations which will be returned from `Endpoint`s.
2//!
3//! The main trait in this module is `Task`.
4//! This trait is an abstraction of asynchronous computations which will be returned from endpoints.
5//! The role of this trait is very close to `futures` and hence its design intentionally resembles
6//! `Future`. However, some differences are exist for specializing to the purpose of HTTP handling.
7//!
8//! This trait does not provide any combinators for composing complicate computations.
9//! Such combinations are usually performed indirectly by the endpoints or by wrapping the value of
10//! `Future`.
11
12use either::Either;
13use futures::{Async, Future, IntoFuture};
14
15use error::Error;
16use input::{Input, RequestBody};
17use never::Never;
18use poll::{Poll, PollResult};
19
20/// The contextual information during polling an task.
21#[derive(Debug)]
22pub struct Context<'a> {
23    input: &'a Input,
24    body: &'a mut Option<RequestBody>,
25    // FIXME: add `futures::task::Context`
26}
27
28impl<'a> Context<'a> {
29    /// Create an instance of `Context` from components.
30    #[inline]
31    pub fn new(input: &'a Input, body: &'a mut Option<RequestBody>) -> Context<'a> {
32        Context { input, body }
33    }
34
35    /// Return the reference to `Input` at the current request.
36    #[inline]
37    pub fn input(&self) -> &Input {
38        self.input
39    }
40
41    /// Take the instance of `RequestBody` at the current request if available.
42    #[inline]
43    pub fn body(&mut self) -> Option<RequestBody> {
44        self.body.take()
45    }
46}
47
48/// Trait representing the asynchronous computation after applying the endpoints.
49///
50/// See the module level documentation for details.
51pub trait Task: Send {
52    /// The *inner* type of an output which will be returned from this task.
53    type Output;
54
55    /// Perform polling this task and get its result.
56    fn poll_task(&mut self, cx: &mut Context) -> PollResult<Self::Output, Error>;
57}
58
59impl<L, R> Task for Either<L, R>
60where
61    L: Task,
62    R: Task<Output = L::Output>,
63{
64    type Output = L::Output;
65
66    #[inline(always)]
67    fn poll_task(&mut self, cx: &mut Context) -> PollResult<Self::Output, Error> {
68        match *self {
69            Either::Left(ref mut t) => t.poll_task(cx),
70            Either::Right(ref mut t) => t.poll_task(cx),
71        }
72    }
73}
74
75/// Trait representing the conversion to a `Task`.
76pub trait IntoTask {
77    /// The type of *output* value.
78    type Output;
79
80    /// The type of value to be converted.
81    type Task: Task<Output = Self::Output>;
82
83    /// Perform conversion itself into a `Task`.
84    fn into_task(self) -> Self::Task;
85}
86
87// FIXME: replace the trait bound with `core::ops::Async`
88impl<F> IntoTask for F
89where
90    F: IntoFuture,
91    F::Future: Send,
92{
93    type Output = Result<F::Item, F::Error>;
94    type Task = TaskFuture<F::Future>;
95
96    #[inline(always)]
97    fn into_task(self) -> Self::Task {
98        future(self)
99    }
100}
101
102/// A helper struct which wraps a `Future` and provides the implementation of `Task`.
103#[derive(Debug)]
104pub struct TaskFuture<F>(F);
105
106impl<F> From<F> for TaskFuture<F>
107where
108    F: Future + Send,
109{
110    fn from(fut: F) -> Self {
111        TaskFuture(fut)
112    }
113}
114
115impl<F> Task for TaskFuture<F>
116where
117    F: Future + Send,
118{
119    type Output = Result<F::Item, F::Error>;
120
121    #[inline(always)]
122    fn poll_task(&mut self, _: &mut Context) -> PollResult<Self::Output, Error> {
123        match Future::poll(&mut self.0) {
124            Ok(Async::Ready(ready)) => Poll::Ready(Ok(Ok(ready))),
125            Ok(Async::NotReady) => Poll::Pending,
126            Err(err) => Poll::Ready(Ok(Err(err))),
127        }
128    }
129}
130
131/// Create a task from a `Future`.
132pub fn future<F>(future: F) -> TaskFuture<F::Future>
133where
134    F: IntoFuture,
135    F::Future: Send,
136{
137    TaskFuture::from(IntoFuture::into_future(future))
138}
139
140/// A `Task` which will immediately return a value of `T`.
141#[derive(Debug)]
142pub struct Ready<T>(Option<T>);
143
144impl<T: Send> From<T> for Ready<T> {
145    fn from(val: T) -> Self {
146        Ready(Some(val))
147    }
148}
149
150impl<T: Send> Task for Ready<T> {
151    type Output = T;
152
153    #[inline(always)]
154    fn poll_task(&mut self, _: &mut Context) -> PollResult<Self::Output, Error> {
155        let val = self.0.take().expect("The task cannot resolve twice");
156        Poll::Ready(Ok(val))
157    }
158}
159
160/// Create a task which will immediately return a value of `T`.
161pub fn ready<T: Send>(val: T) -> Ready<T> {
162    Ready::from(val)
163}
164
165/// A `Task` which will immediately abort with an error value of `E`.
166#[derive(Debug)]
167pub struct Abort<E> {
168    cause: Option<E>,
169}
170
171impl<E> From<E> for Abort<E>
172where
173    E: Into<Error> + Send,
174{
175    fn from(cause: E) -> Self {
176        Abort { cause: Some(cause) }
177    }
178}
179
180impl<E> Task for Abort<E>
181where
182    E: Into<Error> + Send,
183{
184    type Output = Never;
185
186    #[inline(always)]
187    fn poll_task(&mut self, _: &mut Context) -> PollResult<Self::Output, Error> {
188        let cause = self.cause.take().expect("The task cannot reject twice");
189        Poll::Ready(Err(Into::into(cause)))
190    }
191}
192
193/// Create a task which will immediately abort the computation with an error value of `E`.
194pub fn abort<E>(cause: E) -> Abort<E>
195where
196    E: Into<Error> + Send,
197{
198    Abort::from(cause)
199}