use std::cell::RefCell; use std::marker::PhantomData; use std::rc::Rc; use actix_http::{Error, Extensions, Payload, Response}; use actix_service::{NewService, Service, Void}; use futures::future::{ok, FutureResult}; use futures::{try_ready, Async, Future, IntoFuture, Poll}; use crate::extract::FromRequest; use crate::request::HttpRequest; use crate::responder::Responder; use crate::service::{ServiceRequest, ServiceResponse}; /// Handler converter factory pub trait Factory: Clone where R: Responder, { fn call(&self, param: T) -> R; } impl Factory<(), R> for F where F: Fn() -> R + Clone, R: Responder, { fn call(&self, _: ()) -> R { (self)() } } #[doc(hidden)] pub struct Handler where F: Factory, R: Responder, { hnd: F, _t: PhantomData<(T, R)>, } impl Handler where F: Factory, R: Responder, { pub fn new(hnd: F) -> Self { Handler { hnd, _t: PhantomData, } } } impl Clone for Handler where F: Factory, R: Responder, { fn clone(&self) -> Self { Self { hnd: self.hnd.clone(), _t: PhantomData, } } } impl Service for Handler where F: Factory, R: Responder, { type Request = (T, HttpRequest); type Response = ServiceResponse; type Error = Void; type Future = HandlerServiceResponse<::Future>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, (param, req): (T, HttpRequest)) -> Self::Future { let fut = self.hnd.call(param).respond_to(&req).into_future(); HandlerServiceResponse { fut, req: Some(req), } } } pub struct HandlerServiceResponse { fut: T, req: Option, } impl Future for HandlerServiceResponse where T: Future, T::Error: Into, { type Item = ServiceResponse; type Error = Void; fn poll(&mut self) -> Poll { match self.fut.poll() { Ok(Async::Ready(res)) => Ok(Async::Ready(ServiceResponse::new( self.req.take().unwrap(), res, ))), Ok(Async::NotReady) => Ok(Async::NotReady), Err(e) => { let res: Response = e.into().into(); Ok(Async::Ready(ServiceResponse::new( self.req.take().unwrap(), res, ))) } } } } /// Async handler converter factory pub trait AsyncFactory: Clone + 'static where R: IntoFuture, R::Item: Into, R::Error: Into, { fn call(&self, param: T) -> R; } impl AsyncFactory<(), R> for F where F: Fn() -> R + Clone + 'static, R: IntoFuture, R::Item: Into, R::Error: Into, { fn call(&self, _: ()) -> R { (self)() } } #[doc(hidden)] pub struct AsyncHandler where F: AsyncFactory, R: IntoFuture, R::Item: Into, R::Error: Into, { hnd: F, _t: PhantomData<(T, R)>, } impl AsyncHandler where F: AsyncFactory, R: IntoFuture, R::Item: Into, R::Error: Into, { pub fn new(hnd: F) -> Self { AsyncHandler { hnd, _t: PhantomData, } } } impl Clone for AsyncHandler where F: AsyncFactory, R: IntoFuture, R::Item: Into, R::Error: Into, { fn clone(&self) -> Self { AsyncHandler { hnd: self.hnd.clone(), _t: PhantomData, } } } impl Service for AsyncHandler where F: AsyncFactory, R: IntoFuture, R::Item: Into, R::Error: Into, { type Request = (T, HttpRequest); type Response = ServiceResponse; type Error = Void; type Future = AsyncHandlerServiceResponse; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, (param, req): (T, HttpRequest)) -> Self::Future { AsyncHandlerServiceResponse { fut: self.hnd.call(param).into_future(), req: Some(req), } } } #[doc(hidden)] pub struct AsyncHandlerServiceResponse { fut: T, req: Option, } impl Future for AsyncHandlerServiceResponse where T: Future, T::Item: Into, T::Error: Into, { type Item = ServiceResponse; type Error = Void; fn poll(&mut self) -> Poll { match self.fut.poll() { Ok(Async::Ready(res)) => Ok(Async::Ready(ServiceResponse::new( self.req.take().unwrap(), res.into(), ))), Ok(Async::NotReady) => Ok(Async::NotReady), Err(e) => { let res: Response = e.into().into(); Ok(Async::Ready(ServiceResponse::new( self.req.take().unwrap(), res, ))) } } } } /// Extract arguments from request pub struct Extract, S> { config: Rc>>>, service: S, _t: PhantomData<(P, T)>, } impl, S> Extract { pub fn new(config: Rc>>>, service: S) -> Self { Extract { config, service, _t: PhantomData, } } } impl, S> NewService for Extract where S: Service + Clone, { type Request = ServiceRequest

; type Response = ServiceResponse; type Error = (Error, ServiceRequest

); type InitError = (); type Service = ExtractService; type Future = FutureResult; fn new_service(&self, _: &()) -> Self::Future { ok(ExtractService { _t: PhantomData, config: self.config.borrow().clone(), service: self.service.clone(), }) } } pub struct ExtractService, S> { config: Option>, service: S, _t: PhantomData<(P, T)>, } impl, S> Service for ExtractService where S: Service + Clone, { type Request = ServiceRequest

; type Response = ServiceResponse; type Error = (Error, ServiceRequest

); type Future = ExtractResponse; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, req: ServiceRequest

) -> Self::Future { let (mut req, mut payload) = req.into_parts(); req.set_route_data(self.config.clone()); let fut = T::from_request(&req, &mut payload).into_future(); ExtractResponse { fut, fut_s: None, req: Some((req, payload)), service: self.service.clone(), } } } pub struct ExtractResponse, S: Service> { req: Option<(HttpRequest, Payload

)>, service: S, fut: ::Future, fut_s: Option, } impl, S> Future for ExtractResponse where S: Service, { type Item = ServiceResponse; type Error = (Error, ServiceRequest

); fn poll(&mut self) -> Poll { if let Some(ref mut fut) = self.fut_s { return fut.poll().map_err(|_| panic!()); } let item = try_ready!(self.fut.poll().map_err(|e| { let (req, payload) = self.req.take().unwrap(); let req = ServiceRequest::from_parts(req, payload); (e.into(), req) })); self.fut_s = Some(self.service.call((item, self.req.take().unwrap().0))); self.poll() } } /// FromRequest trait impl for tuples macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => { impl Factory<($($T,)+), Res> for Func where Func: Fn($($T,)+) -> Res + Clone, Res: Responder, { fn call(&self, param: ($($T,)+)) -> Res { (self)($(param.$n,)+) } } impl AsyncFactory<($($T,)+), Res> for Func where Func: Fn($($T,)+) -> Res + Clone + 'static, Res: IntoFuture, Res::Item: Into, Res::Error: Into, { fn call(&self, param: ($($T,)+)) -> Res { (self)($(param.$n,)+) } } }); #[rustfmt::skip] mod m { use super::*; factory_tuple!((0, A)); factory_tuple!((0, A), (1, B)); factory_tuple!((0, A), (1, B), (2, C)); factory_tuple!((0, A), (1, B), (2, C), (3, D)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J)); }