From aa5af796baa32a4ce306f6ffbb6c5a86e3537a9e Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Sat, 1 Feb 2020 02:58:06 +0900 Subject: [PATCH 1/3] Make Endpoint::call generic over lifetime --- src/endpoint.rs | 11 +++-------- src/middleware/mod.rs | 2 +- src/redirect.rs | 26 ++++---------------------- src/router.rs | 4 ++-- src/server/mod.rs | 21 +++++++++++++++------ src/server/route.rs | 7 +++---- 6 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/endpoint.rs b/src/endpoint.rs index 795fd2884..292c4b424 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -46,15 +46,11 @@ use crate::{response::IntoResponse, Request, Response}; /// /// Tide routes will also accept endpoints with `Fn` signatures of this form, but using the `async` keyword has better ergonomics. pub trait Endpoint: Send + Sync + 'static { - /// The async result of `call`. - type Fut: Future + Send + 'static; - /// Invoke the endpoint within the given context - fn call(&self, req: Request) -> Self::Fut; + fn call<'a>(&'a self, req: Request) -> BoxFuture<'a, Response>; } -pub(crate) type DynEndpoint = - dyn (Fn(Request) -> BoxFuture<'static, Response>) + 'static + Send + Sync; +pub(crate) type DynEndpoint = dyn Endpoint; impl Endpoint for F where @@ -62,8 +58,7 @@ where Fut: Future + Send + 'static, Fut::Output: IntoResponse, { - type Fut = BoxFuture<'static, Response>; - fn call(&self, req: Request) -> Self::Fut { + fn call<'a>(&'a self, req: Request) -> BoxFuture<'a, Response> { let fut = (self)(req); Box::pin(async move { fut.await.into_response() }) } diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index 04f43d1e2..621a87eb9 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -52,7 +52,7 @@ impl<'a, State: 'static> Next<'a, State> { self.next_middleware = next; current.handle(req, self) } else { - (self.endpoint)(req) + self.endpoint.call(req) } } } diff --git a/src/redirect.rs b/src/redirect.rs index a02e07848..934591916 100644 --- a/src/redirect.rs +++ b/src/redirect.rs @@ -1,8 +1,4 @@ -use async_std::future; -use async_std::task::{Context, Poll}; - -use std::pin::Pin; - +use crate::utils::BoxFuture; use crate::{Endpoint, Request, Response}; /// Redirect a route to another route. @@ -21,7 +17,7 @@ use crate::{Endpoint, Request, Response}; /// app.listen("127.0.0.1:8080").await?; /// # /// # Ok(()) }) } -/// ```` +/// ``` pub fn redirect(location: impl AsRef) -> impl Endpoint { let location = location.as_ref().to_owned(); Redirect { location } @@ -33,22 +29,8 @@ pub struct Redirect { } impl Endpoint for Redirect { - type Fut = Future; - - fn call(&self, _req: Request) -> Self::Fut { + fn call<'a>(&'a self, _req: Request) -> BoxFuture<'a, Response> { let res = Response::new(307).set_header("Location", &self.location); - Future { res: Some(res) } - } -} - -/// Future returned from `redirect`. -pub struct Future { - res: Option, -} - -impl future::Future for Future { - type Output = Response; - fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - Poll::Ready(self.res.take().unwrap()) + Box::pin(async move { res }) } } diff --git a/src/router.rs b/src/router.rs index 7c52a7fef..6f3a1e1a8 100644 --- a/src/router.rs +++ b/src/router.rs @@ -33,12 +33,12 @@ impl Router { self.method_map .entry(method) .or_insert_with(MethodRouter::new) - .add(path, Box::new(move |cx| Box::pin(ep.call(cx)))) + .add(path, Box::new(ep)) } pub(crate) fn add_all(&mut self, path: &str, ep: impl Endpoint) { self.all_method_router - .add(path, Box::new(move |cx| Box::pin(ep.call(cx)))) + .add(path, Box::new(ep)) } pub(crate) fn route(&self, path: &str, method: http::Method) -> Selection<'_, State> { diff --git a/src/server/mod.rs b/src/server/mod.rs index b6acb45a5..757e183bd 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -321,7 +321,6 @@ impl Server { /// /// This type is useful only in conjunction with the [`HttpService`] trait, /// i.e. for hosting a Tide app within some custom HTTP server. -#[derive(Clone)] #[allow(missing_debug_implementations)] pub struct Service { router: Arc>, @@ -329,6 +328,16 @@ pub struct Service { middleware: Arc>>>, } +impl Clone for Service { + fn clone(&self) -> Self { + Self { + router: self.router.clone(), + state: self.state.clone(), + middleware: self.middleware.clone(), + } + } +} + #[derive(Debug)] pub struct ReadyFuture; @@ -351,17 +360,17 @@ impl HttpService for Service { fn respond(&self, _conn: &mut (), req: http_service::Request) -> Self::ResponseFuture { let req = Request::new(self.state.clone(), req, Vec::new()); - let fut = self.call(req); - Box::pin(async move { Ok(fut.await.into()) }) + let service = self.clone(); + Box::pin(async move { + Ok(service.call(req).await.into()) + }) } } impl Endpoint for Service { - type Fut = BoxFuture<'static, Response>; - - fn call(&self, req: Request) -> Self::Fut { + fn call<'a>(&'a self, req: Request) -> BoxFuture<'a, Response> { let Request { request: req, mut route_params, diff --git a/src/server/route.rs b/src/server/route.rs index 0ddf19ea6..3d6649918 100644 --- a/src/server/route.rs +++ b/src/server/route.rs @@ -1,4 +1,5 @@ -use crate::{router::Router, Endpoint}; +use crate::utils::BoxFuture; +use crate::{router::Router, Endpoint, Response}; /// A handle to a route. /// @@ -172,9 +173,7 @@ impl Clone for StripPrefixEndpoint { } impl> Endpoint for StripPrefixEndpoint { - type Fut = E::Fut; - - fn call(&self, mut req: crate::Request) -> Self::Fut { + fn call<'a>(&'a self, mut req: crate::Request) -> BoxFuture<'a, Response> { let rest = req.rest().unwrap_or(""); let mut path_and_query = format!("/{}", rest); let uri = req.uri(); From 720e9ee079511a19e5ee517fb0ce56f29c1288c0 Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Sat, 1 Feb 2020 03:29:16 +0900 Subject: [PATCH 2/3] cargo fmt --- src/router.rs | 3 +-- src/server/mod.rs | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/router.rs b/src/router.rs index 6f3a1e1a8..6b358a07b 100644 --- a/src/router.rs +++ b/src/router.rs @@ -37,8 +37,7 @@ impl Router { } pub(crate) fn add_all(&mut self, path: &str, ep: impl Endpoint) { - self.all_method_router - .add(path, Box::new(ep)) + self.all_method_router.add(path, Box::new(ep)) } pub(crate) fn route(&self, path: &str, method: http::Method) -> Selection<'_, State> { diff --git a/src/server/mod.rs b/src/server/mod.rs index 757e183bd..e1876359d 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -361,9 +361,7 @@ impl HttpService for Service { fn respond(&self, _conn: &mut (), req: http_service::Request) -> Self::ResponseFuture { let req = Request::new(self.state.clone(), req, Vec::new()); let service = self.clone(); - Box::pin(async move { - Ok(service.call(req).await.into()) - }) + Box::pin(async move { Ok(service.call(req).await.into()) }) } } From cd975d88046d2de0e901e7c36bd418528b60374a Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Sat, 1 Feb 2020 03:37:52 +0900 Subject: [PATCH 3/3] cargo fmt --all on 1.41.0 --- examples/json.rs | 7 +++---- tests/nested.rs | 8 +++----- tests/server.rs | 20 ++++++++------------ 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/examples/json.rs b/examples/json.rs index f771fd648..cdb0825bb 100644 --- a/examples/json.rs +++ b/examples/json.rs @@ -11,8 +11,8 @@ fn main() -> io::Result<()> { task::block_on(async { let mut app = tide::new(); - app.at("/submit").post(|mut req: tide::Request<()>| { - async move { + app.at("/submit") + .post(|mut req: tide::Request<()>| async move { let cat: Cat = req.body_json().await.unwrap(); println!("cat name: {}", cat.name); @@ -20,8 +20,7 @@ fn main() -> io::Result<()> { name: "chashu".into(), }; tide::Response::new(200).body_json(&cat).unwrap() - } - }); + }); app.listen("127.0.0.1:8080").await?; Ok(()) diff --git a/tests/nested.rs b/tests/nested.rs index 965237a35..2a45ac6e4 100644 --- a/tests/nested.rs +++ b/tests/nested.rs @@ -93,11 +93,9 @@ fn nested_middleware() { fn nested_with_different_state() { let mut outer = tide::new(); let mut inner = tide::with_state(42); - inner.at("/").get(|req: tide::Request| { - async move { - let num = req.state(); - format!("the number is {}", num) - } + inner.at("/").get(|req: tide::Request| async move { + let num = req.state(); + format!("the number is {}", num) }); outer.at("/").get(|_| async move { "Hello, world!" }); outer.at("/foo").nest(inner); diff --git a/tests/server.rs b/tests/server.rs index cb7804526..79321f207 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -9,11 +9,9 @@ fn hello_world() -> Result<(), surf::Exception> { task::block_on(async { let server = task::spawn(async { let mut app = tide::new(); - app.at("/").get(|mut req: tide::Request<()>| { - async move { - assert_eq!(req.body_string().await.unwrap(), "nori".to_string()); - tide::Response::new(200).body_string("says hello".to_string()) - } + app.at("/").get(|mut req: tide::Request<()>| async move { + assert_eq!(req.body_string().await.unwrap(), "nori".to_string()); + tide::Response::new(200).body_string("says hello".to_string()) }); app.listen("localhost:8080").await?; Result::<(), surf::Exception>::Ok(()) @@ -67,13 +65,11 @@ fn json() -> Result<(), surf::Exception> { task::block_on(async { let server = task::spawn(async { let mut app = tide::new(); - app.at("/").get(|mut req: tide::Request<()>| { - async move { - let mut counter: Counter = req.body_json().await.unwrap(); - assert_eq!(counter.count, 0); - counter.count = 1; - tide::Response::new(200).body_json(&counter).unwrap() - } + app.at("/").get(|mut req: tide::Request<()>| async move { + let mut counter: Counter = req.body_json().await.unwrap(); + assert_eq!(counter.count, 0); + counter.count = 1; + tide::Response::new(200).body_json(&counter).unwrap() }); app.listen("localhost:8082").await?; Result::<(), surf::Exception>::Ok(())