1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-10-11 04:32:28 +00:00
actix-web/src/with.rs

420 lines
13 KiB
Rust
Raw Normal View History

2018-03-27 06:10:31 +00:00
use std::rc::Rc;
use std::cell::UnsafeCell;
use std::marker::PhantomData;
use futures::{Async, Future, Poll};
use error::Error;
use handler::{Handler, Reply, ReplyItem, Responder};
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use extractor::HttpRequestExtractor;
/// Trait defines object that could be registered as route handler
#[allow(unused_variables)]
2018-03-28 21:24:32 +00:00
pub trait WithHandler<T, S>: 'static
where T: HttpRequestExtractor<S>, S: 'static
2018-03-27 06:10:31 +00:00
{
/// The type of value that handler will return.
type Result: Responder;
/// Handle request
2018-03-28 21:24:32 +00:00
fn handle(&mut self, data: T) -> Self::Result;
2018-03-27 06:10:31 +00:00
}
/// WithHandler<D, T, S> for Fn()
2018-03-28 21:24:32 +00:00
impl<T, S, F, R> WithHandler<T, S> for F
where F: Fn(T) -> R + 'static,
2018-03-27 06:10:31 +00:00
R: Responder + 'static,
2018-03-28 21:24:32 +00:00
T: HttpRequestExtractor<S>,
2018-03-28 03:33:24 +00:00
S: 'static,
2018-03-27 06:10:31 +00:00
{
type Result = R;
2018-03-28 21:24:32 +00:00
fn handle(&mut self, item: T) -> R {
2018-03-28 03:33:24 +00:00
(self)(item)
2018-03-27 06:10:31 +00:00
}
}
2018-03-28 21:24:32 +00:00
pub(crate)
fn with<T, S, H>(h: H) -> With<T, S, H>
where H: WithHandler<T, S>,
T: HttpRequestExtractor<S>,
2018-03-27 06:10:31 +00:00
{
2018-03-28 21:24:32 +00:00
With{hnd: Rc::new(UnsafeCell::new(h)), _t: PhantomData, _s: PhantomData}
2018-03-27 06:10:31 +00:00
}
2018-03-28 21:24:32 +00:00
pub struct With<T, S, H>
where H: WithHandler<T, S> + 'static,
2018-03-28 21:24:32 +00:00
T: HttpRequestExtractor<S>,
2018-03-28 03:33:24 +00:00
S: 'static,
2018-03-27 06:10:31 +00:00
{
hnd: Rc<UnsafeCell<H>>,
_t: PhantomData<T>,
_s: PhantomData<S>,
}
2018-03-28 21:24:32 +00:00
impl<T, S, H> Handler<S> for With<T, S, H>
where H: WithHandler<T, S>,
T: HttpRequestExtractor<S> + 'static,
S: 'static, H: 'static
2018-03-27 06:10:31 +00:00
{
type Result = Reply;
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
let mut fut = T::extract(&req);
match fut.poll() {
Ok(Async::Ready(item)) => {
let hnd: &mut H = unsafe{&mut *self.hnd.get()};
match hnd.handle(item).respond_to(req.without_state()) {
Ok(item) => match item.into().into() {
ReplyItem::Message(resp) => Reply::response(resp),
ReplyItem::Future(fut) => Reply::async(
WithHandlerFut{
req,
hnd: Rc::clone(&self.hnd),
fut1: None,
fut2: Some(fut),
})
},
Err(e) => Reply::response(e.into()),
}
}
Ok(Async::NotReady) => Reply::async(
WithHandlerFut{
req,
hnd: Rc::clone(&self.hnd),
fut1: Some(Box::new(fut)),
fut2: None,
}),
Err(e) => Reply::response(e),
}
2018-03-27 06:10:31 +00:00
}
}
2018-03-28 21:24:32 +00:00
struct WithHandlerFut<T, S, H>
where H: WithHandler<T, S>,
T: HttpRequestExtractor<S>,
T: 'static, S: 'static
2018-03-27 06:10:31 +00:00
{
hnd: Rc<UnsafeCell<H>>,
req: HttpRequest<S>,
2018-03-28 21:24:32 +00:00
fut1: Option<Box<Future<Item=T, Error=Error>>>,
2018-03-27 06:10:31 +00:00
fut2: Option<Box<Future<Item=HttpResponse, Error=Error>>>,
}
2018-03-28 21:24:32 +00:00
impl<T, S, H> Future for WithHandlerFut<T, S, H>
where H: WithHandler<T, S>,
T: HttpRequestExtractor<S> + 'static,
S: 'static
2018-03-27 06:10:31 +00:00
{
type Item = HttpResponse;
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if let Some(ref mut fut) = self.fut2 {
return fut.poll()
}
let item = match self.fut1.as_mut().unwrap().poll()? {
Async::Ready(item) => item,
Async::NotReady => return Ok(Async::NotReady),
};
let hnd: &mut H = unsafe{&mut *self.hnd.get()};
2018-03-28 03:33:24 +00:00
let item = match hnd.handle(item)
2018-03-27 06:34:31 +00:00
.respond_to(self.req.without_state())
2018-03-27 06:10:31 +00:00
{
Ok(item) => item.into(),
Err(err) => return Err(err.into()),
};
match item.into() {
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => self.fut2 = Some(fut),
}
self.poll()
}
}
2018-03-28 21:24:32 +00:00
pub(crate)
fn with2<T1, T2, S, F, R>(h: F) -> With2<T1, T2, S, F, R>
where F: Fn(T1, T2) -> R,
R: Responder,
T1: HttpRequestExtractor<S>,
T2: HttpRequestExtractor<S>,
{
With2{hnd: Rc::new(UnsafeCell::new(h)),
_t1: PhantomData, _t2: PhantomData, _s: PhantomData}
}
pub struct With2<T1, T2, S, F, R>
where F: Fn(T1, T2) -> R,
R: Responder,
T1: HttpRequestExtractor<S>,
T2: HttpRequestExtractor<S>,
S: 'static,
{
hnd: Rc<UnsafeCell<F>>,
_t1: PhantomData<T1>,
_t2: PhantomData<T2>,
_s: PhantomData<S>,
}
impl<T1, T2, S, F, R> Handler<S> for With2<T1, T2, S, F, R>
where F: Fn(T1, T2) -> R + 'static,
R: Responder + 'static,
T1: HttpRequestExtractor<S> + 'static,
T2: HttpRequestExtractor<S> + 'static,
S: 'static
{
type Result = Reply;
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
let mut fut = T1::extract(&req);
match fut.poll() {
Ok(Async::Ready(item1)) => {
let mut fut = T2::extract(&req);
match fut.poll() {
Ok(Async::Ready(item2)) => {
let hnd: &mut F = unsafe{&mut *self.hnd.get()};
match (*hnd)(item1, item2).respond_to(req.without_state()) {
Ok(item) => match item.into().into() {
ReplyItem::Message(resp) => Reply::response(resp),
ReplyItem::Future(fut) => Reply::async(
WithHandlerFut2{
req,
item: None,
hnd: Rc::clone(&self.hnd),
fut1: None,
fut2: None,
fut3: Some(fut),
})
},
Err(e) => Reply::response(e.into()),
}
},
Ok(Async::NotReady) => Reply::async(
WithHandlerFut2{
req,
hnd: Rc::clone(&self.hnd),
item: Some(item1),
fut1: None,
fut2: Some(Box::new(fut)),
fut3: None,
}),
Err(e) => Reply::response(e),
}
},
Ok(Async::NotReady) => Reply::async(
WithHandlerFut2{
req,
hnd: Rc::clone(&self.hnd),
item: None,
fut1: Some(Box::new(fut)),
fut2: None,
fut3: None,
}),
Err(e) => Reply::response(e),
}
2018-03-28 21:24:32 +00:00
}
}
struct WithHandlerFut2<T1, T2, S, F, R>
where F: Fn(T1, T2) -> R + 'static,
R: Responder + 'static,
T1: HttpRequestExtractor<S> + 'static,
T2: HttpRequestExtractor<S> + 'static,
S: 'static
{
hnd: Rc<UnsafeCell<F>>,
req: HttpRequest<S>,
item: Option<T1>,
fut1: Option<Box<Future<Item=T1, Error=Error>>>,
fut2: Option<Box<Future<Item=T2, Error=Error>>>,
fut3: Option<Box<Future<Item=HttpResponse, Error=Error>>>,
}
impl<T1, T2, S, F, R> Future for WithHandlerFut2<T1, T2, S, F, R>
where F: Fn(T1, T2) -> R + 'static,
R: Responder + 'static,
T1: HttpRequestExtractor<S> + 'static,
T2: HttpRequestExtractor<S> + 'static,
S: 'static
{
type Item = HttpResponse;
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if let Some(ref mut fut) = self.fut3 {
return fut.poll()
}
if self.fut1.is_some() {
match self.fut1.as_mut().unwrap().poll()? {
Async::Ready(item) => {
self.item = Some(item);
self.fut1.take();
self.fut2 = Some(Box::new(T2::extract(&self.req)));
},
Async::NotReady => return Ok(Async::NotReady),
}
}
let item = match self.fut2.as_mut().unwrap().poll()? {
Async::Ready(item) => item,
Async::NotReady => return Ok(Async::NotReady),
};
let hnd: &mut F = unsafe{&mut *self.hnd.get()};
let item = match (*hnd)(self.item.take().unwrap(), item)
.respond_to(self.req.without_state())
{
Ok(item) => item.into(),
Err(err) => return Err(err.into()),
};
match item.into() {
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => self.fut3 = Some(fut),
}
self.poll()
}
}
pub(crate)
fn with3<T1, T2, T3, S, F, R>(h: F) -> With3<T1, T2, T3, S, F, R>
where F: Fn(T1, T2, T3) -> R + 'static,
R: Responder,
T1: HttpRequestExtractor<S>,
T2: HttpRequestExtractor<S>,
T3: HttpRequestExtractor<S>,
{
With3{hnd: Rc::new(UnsafeCell::new(h)),
_s: PhantomData, _t1: PhantomData, _t2: PhantomData, _t3: PhantomData}
}
pub struct With3<T1, T2, T3, S, F, R>
where F: Fn(T1, T2, T3) -> R + 'static,
R: Responder + 'static,
T1: HttpRequestExtractor<S>,
T2: HttpRequestExtractor<S>,
T3: HttpRequestExtractor<S>,
S: 'static,
{
hnd: Rc<UnsafeCell<F>>,
_t1: PhantomData<T1>,
_t2: PhantomData<T2>,
_t3: PhantomData<T3>,
_s: PhantomData<S>,
}
impl<T1, T2, T3, S, F, R> Handler<S> for With3<T1, T2, T3, S, F, R>
where F: Fn(T1, T2, T3) -> R + 'static,
R: Responder + 'static,
T1: HttpRequestExtractor<S>,
T2: HttpRequestExtractor<S>,
T3: HttpRequestExtractor<S>,
T1: 'static, T2: 'static, T3: 'static, S: 'static
{
type Result = Reply;
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
let fut = Box::new(T1::extract(&req));
Reply::async(
WithHandlerFut3{
req,
hnd: Rc::clone(&self.hnd),
item1: None,
item2: None,
fut1: Some(fut),
fut2: None,
fut3: None,
fut4: None,
})
}
}
struct WithHandlerFut3<T1, T2, T3, S, F, R>
where F: Fn(T1, T2, T3) -> R + 'static,
R: Responder + 'static,
T1: HttpRequestExtractor<S> + 'static,
T2: HttpRequestExtractor<S> + 'static,
T3: HttpRequestExtractor<S> + 'static,
S: 'static
{
hnd: Rc<UnsafeCell<F>>,
req: HttpRequest<S>,
item1: Option<T1>,
item2: Option<T2>,
fut1: Option<Box<Future<Item=T1, Error=Error>>>,
fut2: Option<Box<Future<Item=T2, Error=Error>>>,
fut3: Option<Box<Future<Item=T3, Error=Error>>>,
fut4: Option<Box<Future<Item=HttpResponse, Error=Error>>>,
}
impl<T1, T2, T3, S, F, R> Future for WithHandlerFut3<T1, T2, T3, S, F, R>
where F: Fn(T1, T2, T3) -> R + 'static,
R: Responder + 'static,
T1: HttpRequestExtractor<S> + 'static,
T2: HttpRequestExtractor<S> + 'static,
T3: HttpRequestExtractor<S> + 'static,
S: 'static
{
type Item = HttpResponse;
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if let Some(ref mut fut) = self.fut4 {
return fut.poll()
}
if self.fut1.is_some() {
match self.fut1.as_mut().unwrap().poll()? {
Async::Ready(item) => {
self.item1 = Some(item);
self.fut1.take();
self.fut2 = Some(Box::new(T2::extract(&self.req)));
},
Async::NotReady => return Ok(Async::NotReady),
}
}
if self.fut2.is_some() {
match self.fut2.as_mut().unwrap().poll()? {
Async::Ready(item) => {
self.item2 = Some(item);
self.fut2.take();
self.fut3 = Some(Box::new(T3::extract(&self.req)));
},
Async::NotReady => return Ok(Async::NotReady),
}
}
let item = match self.fut3.as_mut().unwrap().poll()? {
Async::Ready(item) => item,
Async::NotReady => return Ok(Async::NotReady),
};
let hnd: &mut F = unsafe{&mut *self.hnd.get()};
let item = match (*hnd)(self.item1.take().unwrap(),
self.item2.take().unwrap(),
item)
.respond_to(self.req.without_state())
{
Ok(item) => item.into(),
Err(err) => return Err(err.into()),
};
match item.into() {
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => self.fut4 = Some(fut),
}
self.poll()
}
}