From 4358da9926355381859c36bd55d4114572a30dca Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Tue, 27 Mar 2018 20:33:24 -0700 Subject: [PATCH] refactor WithHandler trait --- examples/json/src/main.rs | 2 +- src/extractor.rs | 93 ++++++++++++++++++++++++++++++--------- src/httpmessage.rs | 8 ++-- src/httprequest.rs | 8 ++-- src/json.rs | 7 +-- src/resource.rs | 2 +- src/route.rs | 4 +- src/with.rs | 28 ++++++------ 8 files changed, 103 insertions(+), 49 deletions(-) diff --git a/examples/json/src/main.rs b/examples/json/src/main.rs index 6d85a35e..7078c586 100644 --- a/examples/json/src/main.rs +++ b/examples/json/src/main.rs @@ -31,7 +31,7 @@ fn index(req: HttpRequest) -> Box> { } /// This handler uses `With` helper for loading serde json object. -fn extract_item(_: HttpRequest, item: Json) -> Result { +fn extract_item(item: Json) -> Result { println!("model: {:?}", &item); httpcodes::HTTPOk.build().json(item.0) // <- send response } diff --git a/src/extractor.rs b/src/extractor.rs index a6373ab3..a5255e12 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -8,11 +8,11 @@ use error::Error; use httprequest::HttpRequest; -pub trait HttpRequestExtractor: Sized where T: DeserializeOwned +pub trait HttpRequestExtractor: Sized where T: DeserializeOwned, S: 'static { type Result: Future; - fn extract(req: &HttpRequest) -> Self::Result; + fn extract(req: &HttpRequest) -> Self::Result; } /// Extract typed information from the request's path. @@ -33,7 +33,7 @@ pub trait HttpRequestExtractor: Sized where T: DeserializeOwned /// } /// /// /// extract path info using serde -/// fn index(req: HttpRequest, info: Path) -> Result { +/// fn index(info: Path) -> Result { /// Ok(format!("Welcome {}!", info.username)) /// } /// @@ -43,31 +43,57 @@ pub trait HttpRequestExtractor: Sized where T: DeserializeOwned /// |r| r.method(Method::GET).with(index)); // <- use `with` extractor /// } /// ``` -pub struct Path(pub T); +pub struct Path{ + item: T, + req: HttpRequest, +} -impl Deref for Path { +impl Deref for Path { type Target = T; fn deref(&self) -> &T { - &self.0 + &self.item } } -impl DerefMut for Path { +impl DerefMut for Path { fn deref_mut(&mut self) -> &mut T { - &mut self.0 + &mut self.item } } -impl HttpRequestExtractor for Path where T: DeserializeOwned +impl Path { + + /// Shared application state + #[inline] + pub fn state(&self) -> &S { + self.req.state() + } + + /// Incoming request + #[inline] + pub fn request(&self) -> &HttpRequest { + &self.req + } + + /// Deconstruct instance into a parts + pub fn into(self) -> (T, HttpRequest) { + (self.item, self.req) + } + +} + +impl HttpRequestExtractor for Path + where T: DeserializeOwned, S: 'static { type Result = FutureResult; #[inline] - fn extract(req: &HttpRequest) -> Self::Result { - result(de::Deserialize::deserialize(PathExtractor{req}) + fn extract(req: &HttpRequest) -> Self::Result { + let req = req.clone(); + result(de::Deserialize::deserialize(PathExtractor{req: &req}) .map_err(|e| e.into()) - .map(Path)) + .map(|item| Path{item, req})) } } @@ -90,7 +116,7 @@ impl HttpRequestExtractor for Path where T: DeserializeOwned /// /// // use `with` extractor for query info /// // this handler get called only if request's query contains `username` field -/// fn index(req: HttpRequest, info: Query) -> Result { +/// fn index(info: Query) -> Result { /// Ok(format!("Welcome {}!", info.username)) /// } /// @@ -100,31 +126,56 @@ impl HttpRequestExtractor for Path where T: DeserializeOwned /// |r| r.method(Method::GET).with(index)); // <- use `with` extractor /// } /// ``` -pub struct Query(pub T); +pub struct Query{ + item: T, + req: HttpRequest, +} -impl Deref for Query { +impl Deref for Query { type Target = T; fn deref(&self) -> &T { - &self.0 + &self.item } } -impl DerefMut for Query { +impl DerefMut for Query { fn deref_mut(&mut self) -> &mut T { - &mut self.0 + &mut self.item } } -impl HttpRequestExtractor for Query where T: de::DeserializeOwned +impl Query { + + /// Shared application state + #[inline] + pub fn state(&self) -> &S { + self.req.state() + } + + /// Incoming request + #[inline] + pub fn request(&self) -> &HttpRequest { + &self.req + } + + /// Deconstruct instance into a parts + pub fn into(self) -> (T, HttpRequest) { + (self.item, self.req) + } +} + +impl HttpRequestExtractor for Query + where T: de::DeserializeOwned, S: 'static { type Result = FutureResult; #[inline] - fn extract(req: &HttpRequest) -> Self::Result { + fn extract(req: &HttpRequest) -> Self::Result { + let req = req.clone(); result(serde_urlencoded::from_str::(req.query_string()) .map_err(|e| e.into()) - .map(Query)) + .map(|item| Query{ item, req})) } } diff --git a/src/httpmessage.rs b/src/httpmessage.rs index 69065c49..33b7d046 100644 --- a/src/httpmessage.rs +++ b/src/httpmessage.rs @@ -136,7 +136,7 @@ pub trait HttpMessage { MessageBody::new(self) } - /// Parse `application/x-www-form-urlencoded` encoded body. + /// Parse `application/x-www-form-urlencoded` encoded request's body. /// Return `UrlEncoded` future. It resolves to a `HashMap` which /// contains decoded parameters. /// @@ -151,15 +151,15 @@ pub trait HttpMessage { /// ```rust /// # extern crate actix_web; /// # extern crate futures; + /// # use futures::Future; /// use actix_web::*; - /// use futures::future::{Future, ok}; /// - /// fn index(mut req: HttpRequest) -> Box> { + /// fn index(mut req: HttpRequest) -> FutureResponse { /// req.urlencoded() // <- get UrlEncoded future /// .from_err() /// .and_then(|params| { // <- url encoded parameters /// println!("==== BODY ==== {:?}", params); - /// ok(httpcodes::HttpOk.into()) + /// Ok(httpcodes::HttpOk.into()) /// }) /// .responder() /// } diff --git a/src/httprequest.rs b/src/httprequest.rs index 539f752f..20fef5a2 100644 --- a/src/httprequest.rs +++ b/src/httprequest.rs @@ -430,8 +430,8 @@ impl HttpRequest { where S: 'static, T: de::DeserializeOwned, { - match Path::::extract(self).poll()? { - Async::Ready(val) => Ok(val.0), + match Path::::extract(self).poll()? { + Async::Ready(val) => Ok(val.into().0), _ => unreachable!() } } @@ -482,8 +482,8 @@ impl HttpRequest { where S: 'static, T: de::DeserializeOwned, { - match Query::::extract(self).poll()? { - Async::Ready(val) => Ok(val.0), + match Query::::extract(self).poll()? { + Async::Ready(val) => Ok(val.into().0), _ => unreachable!() } } diff --git a/src/json.rs b/src/json.rs index 94a3f368..b97f6f75 100644 --- a/src/json.rs +++ b/src/json.rs @@ -63,12 +63,13 @@ impl Responder for Json { } } -impl HttpRequestExtractor for Json where T: DeserializeOwned + 'static +impl HttpRequestExtractor for Json + where T: DeserializeOwned + 'static, S: 'static { type Result = Box>; #[inline] - fn extract(req: &HttpRequest) -> Self::Result { + fn extract(req: &HttpRequest) -> Self::Result { Box::new( JsonBody::new(req.clone()) .from_err() @@ -251,7 +252,7 @@ mod tests { #[test] fn test_with_json() { - let mut handler = with(|_: _, data: Json| data); + let mut handler = with(|data: Json| data); let req = HttpRequest::default(); let mut json = handler.handle(req).into_future(); diff --git a/src/resource.rs b/src/resource.rs index 732d788c..5a202115 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -144,7 +144,7 @@ impl Resource { /// ``` pub fn with(&mut self, handler: H) where H: WithHandler, - D: HttpRequestExtractor + 'static, + D: HttpRequestExtractor + 'static, T: DeserializeOwned + 'static, { self.routes.push(Route::default()); diff --git a/src/route.rs b/src/route.rs index 9f18cce5..37bb1357 100644 --- a/src/route.rs +++ b/src/route.rs @@ -127,7 +127,7 @@ impl Route { /// } /// /// /// extract path info using serde - /// fn index(req: HttpRequest, info: Path) -> Result { + /// fn index(info: Path) -> Result { /// Ok(format!("Welcome {}!", info.username)) /// } /// @@ -139,7 +139,7 @@ impl Route { /// ``` pub fn with(&mut self, handler: H) where H: WithHandler, - D: HttpRequestExtractor + 'static, + D: HttpRequestExtractor + 'static, T: DeserializeOwned + 'static, { self.h(with(handler)) diff --git a/src/with.rs b/src/with.rs index a7b338a7..0bdcd7ac 100644 --- a/src/with.rs +++ b/src/with.rs @@ -14,32 +14,33 @@ use extractor::HttpRequestExtractor; /// Trait defines object that could be registered as route handler #[allow(unused_variables)] pub trait WithHandler: 'static - where D: HttpRequestExtractor, T: DeserializeOwned + where D: HttpRequestExtractor, T: DeserializeOwned, S: 'static { /// The type of value that handler will return. type Result: Responder; /// Handle request - fn handle(&mut self, req: HttpRequest, data: D) -> Self::Result; + fn handle(&mut self, data: D) -> Self::Result; } /// WithHandler for Fn() impl WithHandler for F - where F: Fn(HttpRequest, D) -> R + 'static, + where F: Fn(D) -> R + 'static, R: Responder + 'static, - D: HttpRequestExtractor, + D: HttpRequestExtractor, T: DeserializeOwned, + S: 'static, { type Result = R; - fn handle(&mut self, req: HttpRequest, item: D) -> R { - (self)(req, item) + fn handle(&mut self, item: D) -> R { + (self)(item) } } pub(crate) fn with(h: H) -> With where H: WithHandler, - D: HttpRequestExtractor, + D: HttpRequestExtractor, T: DeserializeOwned, { With{hnd: Rc::new(UnsafeCell::new(h)), @@ -48,8 +49,9 @@ pub(crate) fn with(h: H) -> With pub struct With where H: WithHandler, - D: HttpRequestExtractor, + D: HttpRequestExtractor, T: DeserializeOwned, + S: 'static, { hnd: Rc>, _t: PhantomData, @@ -59,9 +61,9 @@ pub struct With impl Handler for With where H: WithHandler, - D: HttpRequestExtractor, + D: HttpRequestExtractor, T: DeserializeOwned, - T: 'static, D: 'static, S: 'static + T: 'static, D: 'static, S: 'static, H: 'static { type Result = Reply; @@ -82,7 +84,7 @@ impl Handler for With struct WithHandlerFut where H: WithHandler, - D: HttpRequestExtractor, + D: HttpRequestExtractor, T: DeserializeOwned, T: 'static, D: 'static, S: 'static { @@ -96,7 +98,7 @@ struct WithHandlerFut impl Future for WithHandlerFut where H: WithHandler, - D: HttpRequestExtractor, + D: HttpRequestExtractor, T: DeserializeOwned, T: 'static, D: 'static, S: 'static { @@ -114,7 +116,7 @@ impl Future for WithHandlerFut }; let hnd: &mut H = unsafe{&mut *self.hnd.get()}; - let item = match hnd.handle(self.req.clone(), item) + let item = match hnd.handle(item) .respond_to(self.req.without_state()) { Ok(item) => item.into(),