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)] pub trait WithHandler: 'static where T: HttpRequestExtractor, S: 'static { /// The type of value that handler will return. type Result: Responder; /// Handle request fn handle(&mut self, data: T) -> Self::Result; } /// WithHandler for Fn() impl WithHandler for F where F: Fn(T) -> R + 'static, R: Responder + 'static, T: HttpRequestExtractor, S: 'static, { type Result = R; fn handle(&mut self, item: T) -> R { (self)(item) } } pub(crate) fn with(h: H) -> With where H: WithHandler, T: HttpRequestExtractor, { With{hnd: Rc::new(UnsafeCell::new(h)), _t: PhantomData, _s: PhantomData} } pub struct With where H: WithHandler + 'static, T: HttpRequestExtractor, S: 'static, { hnd: Rc>, _t: PhantomData, _s: PhantomData, } impl Handler for With where H: WithHandler, T: HttpRequestExtractor + 'static, S: 'static, H: 'static { type Result = Reply; fn handle(&mut self, req: HttpRequest) -> 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), } } } struct WithHandlerFut where H: WithHandler, T: HttpRequestExtractor, T: 'static, S: 'static { hnd: Rc>, req: HttpRequest, fut1: Option>>, fut2: Option>>, } impl Future for WithHandlerFut where H: WithHandler, T: HttpRequestExtractor + 'static, S: 'static { type Item = HttpResponse; type Error = Error; fn poll(&mut self) -> Poll { 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()}; let item = match hnd.handle(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.fut2 = Some(fut), } self.poll() } } pub(crate) fn with2(h: F) -> With2 where F: Fn(T1, T2) -> R, R: Responder, T1: HttpRequestExtractor, T2: HttpRequestExtractor, { With2{hnd: Rc::new(UnsafeCell::new(h)), _t1: PhantomData, _t2: PhantomData, _s: PhantomData} } pub struct With2 where F: Fn(T1, T2) -> R, R: Responder, T1: HttpRequestExtractor, T2: HttpRequestExtractor, S: 'static, { hnd: Rc>, _t1: PhantomData, _t2: PhantomData, _s: PhantomData, } impl Handler for With2 where F: Fn(T1, T2) -> R + 'static, R: Responder + 'static, T1: HttpRequestExtractor + 'static, T2: HttpRequestExtractor + 'static, S: 'static { type Result = Reply; fn handle(&mut self, req: HttpRequest) -> 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), } } } struct WithHandlerFut2 where F: Fn(T1, T2) -> R + 'static, R: Responder + 'static, T1: HttpRequestExtractor + 'static, T2: HttpRequestExtractor + 'static, S: 'static { hnd: Rc>, req: HttpRequest, item: Option, fut1: Option>>, fut2: Option>>, fut3: Option>>, } impl Future for WithHandlerFut2 where F: Fn(T1, T2) -> R + 'static, R: Responder + 'static, T1: HttpRequestExtractor + 'static, T2: HttpRequestExtractor + 'static, S: 'static { type Item = HttpResponse; type Error = Error; fn poll(&mut self) -> Poll { 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(h: F) -> With3 where F: Fn(T1, T2, T3) -> R + 'static, R: Responder, T1: HttpRequestExtractor, T2: HttpRequestExtractor, T3: HttpRequestExtractor, { With3{hnd: Rc::new(UnsafeCell::new(h)), _s: PhantomData, _t1: PhantomData, _t2: PhantomData, _t3: PhantomData} } pub struct With3 where F: Fn(T1, T2, T3) -> R + 'static, R: Responder + 'static, T1: HttpRequestExtractor, T2: HttpRequestExtractor, T3: HttpRequestExtractor, S: 'static, { hnd: Rc>, _t1: PhantomData, _t2: PhantomData, _t3: PhantomData, _s: PhantomData, } impl Handler for With3 where F: Fn(T1, T2, T3) -> R + 'static, R: Responder + 'static, T1: HttpRequestExtractor, T2: HttpRequestExtractor, T3: HttpRequestExtractor, T1: 'static, T2: 'static, T3: 'static, S: 'static { type Result = Reply; fn handle(&mut self, req: HttpRequest) -> 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 where F: Fn(T1, T2, T3) -> R + 'static, R: Responder + 'static, T1: HttpRequestExtractor + 'static, T2: HttpRequestExtractor + 'static, T3: HttpRequestExtractor + 'static, S: 'static { hnd: Rc>, req: HttpRequest, item1: Option, item2: Option, fut1: Option>>, fut2: Option>>, fut3: Option>>, fut4: Option>>, } impl Future for WithHandlerFut3 where F: Fn(T1, T2, T3) -> R + 'static, R: Responder + 'static, T1: HttpRequestExtractor + 'static, T2: HttpRequestExtractor + 'static, T3: HttpRequestExtractor + 'static, S: 'static { type Item = HttpResponse; type Error = Error; fn poll(&mut self) -> Poll { 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() } }