use futures::{Async, Future, Poll}; use std::cell::UnsafeCell; use std::marker::PhantomData; use std::rc::Rc; use error::Error; use handler::{AsyncResult, AsyncResultItem, FromRequest, Handler, Responder}; use httprequest::HttpRequest; use httpresponse::HttpResponse; pub(crate) struct With where F: Fn(T) -> R, T: FromRequest, S: 'static, { hnd: Rc>, cfg: Rc, } pub struct WithHnd where F: Fn(T) -> R, T: FromRequest, S: 'static, { hnd: Rc>, _t: PhantomData, _s: PhantomData, } impl With where F: Fn(T) -> R, T: FromRequest, S: 'static, { pub fn new(f: F, cfg: T::Config) -> Self { With { cfg: Rc::new(cfg), hnd: Rc::new(WithHnd { hnd: Rc::new(UnsafeCell::new(f)), _t: PhantomData, _s: PhantomData, }), } } } impl Handler for With where F: Fn(T) -> R + 'static, R: Responder + 'static, T: FromRequest + 'static, S: 'static, { type Result = AsyncResult; fn handle(&self, req: HttpRequest) -> Self::Result { let mut fut = WithHandlerFut { req, started: false, hnd: Rc::clone(&self.hnd), cfg: self.cfg.clone(), fut1: None, fut2: None, }; match fut.poll() { Ok(Async::Ready(resp)) => AsyncResult::ok(resp), Ok(Async::NotReady) => AsyncResult::async(Box::new(fut)), Err(e) => AsyncResult::err(e), } } } struct WithHandlerFut where F: Fn(T) -> R, R: Responder, T: FromRequest + 'static, S: 'static, { started: bool, hnd: Rc>, cfg: Rc, req: HttpRequest, fut1: Option>>, fut2: Option>>, } impl Future for WithHandlerFut where F: Fn(T) -> R, R: Responder + 'static, T: FromRequest + '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 = if !self.started { self.started = true; let reply = T::from_request(&self.req, self.cfg.as_ref()).into(); match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.fut1 = Some(fut); return self.poll(); } } } else { match self.fut1.as_mut().unwrap().poll()? { Async::Ready(item) => item, Async::NotReady => return Ok(Async::NotReady), } }; let fut = { // clone handler, inicrease ref counter let h = self.hnd.as_ref().hnd.clone(); // Enforce invariants before entering unsafe code. // Only two references could exists With struct owns one, and line above if Rc::weak_count(&h) != 0 || Rc::strong_count(&h) != 2 { panic!("Multiple copies of handler are in use") } let hnd: &mut F = unsafe { &mut *h.as_ref().get() }; let item = match (*hnd)(item).respond_to(&self.req) { Ok(item) => item.into(), Err(e) => return Err(e.into()), }; match item.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => fut, } }; self.fut2 = Some(fut); self.poll() } } pub(crate) struct WithAsync where F: Fn(T) -> R, R: Future, I: Responder, E: Into, T: FromRequest, S: 'static, { hnd: Rc>, cfg: Rc, } impl WithAsync where F: Fn(T) -> R, R: Future, I: Responder, E: Into, T: FromRequest, S: 'static, { pub fn new(f: F, cfg: T::Config) -> Self { WithAsync { cfg: Rc::new(cfg), hnd: Rc::new(WithHnd { hnd: Rc::new(UnsafeCell::new(f)), _s: PhantomData, _t: PhantomData, }), } } } impl Handler for WithAsync where F: Fn(T) -> R + 'static, R: Future + 'static, I: Responder + 'static, E: Into + 'static, T: FromRequest + 'static, S: 'static, { type Result = AsyncResult; fn handle(&self, req: HttpRequest) -> Self::Result { let mut fut = WithAsyncHandlerFut { req, started: false, hnd: Rc::clone(&self.hnd), cfg: Rc::clone(&self.cfg), fut1: None, fut2: None, fut3: None, }; match fut.poll() { Ok(Async::Ready(resp)) => AsyncResult::ok(resp), Ok(Async::NotReady) => AsyncResult::async(Box::new(fut)), Err(e) => AsyncResult::err(e), } } } struct WithAsyncHandlerFut where F: Fn(T) -> R, R: Future + 'static, I: Responder + 'static, E: Into + 'static, T: FromRequest + 'static, S: 'static, { started: bool, hnd: Rc>, cfg: Rc, req: HttpRequest, fut1: Option>>, fut2: Option, fut3: Option>>, } impl Future for WithAsyncHandlerFut where F: Fn(T) -> R, R: Future + 'static, I: Responder + 'static, E: Into + 'static, T: FromRequest + '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.fut2.is_some() { return match self.fut2.as_mut().unwrap().poll() { Ok(Async::NotReady) => Ok(Async::NotReady), Ok(Async::Ready(r)) => match r.respond_to(&self.req) { Ok(r) => match r.into().into() { AsyncResultItem::Err(err) => Err(err), AsyncResultItem::Ok(resp) => Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => { self.fut3 = Some(fut); self.poll() } }, Err(e) => Err(e.into()), }, Err(e) => Err(e.into()), }; } let item = if !self.started { self.started = true; let reply = T::from_request(&self.req, self.cfg.as_ref()).into(); match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.fut1 = Some(fut); return self.poll(); } } } else { match self.fut1.as_mut().unwrap().poll()? { Async::Ready(item) => item, Async::NotReady => return Ok(Async::NotReady), } }; self.fut2 = { // clone handler, inicrease ref counter let h = self.hnd.as_ref().hnd.clone(); // Enforce invariants before entering unsafe code. // Only two references could exists With struct owns one, and line above if Rc::weak_count(&h) != 0 || Rc::strong_count(&h) != 2 { panic!("Multiple copies of handler are in use") } let hnd: &mut F = unsafe { &mut *h.as_ref().get() }; Some((*hnd)(item)) }; self.poll() } }