From 51630b6b5e309a8122d4c3978f1c73503718fb5c Mon Sep 17 00:00:00 2001 From: David Laban Date: Tue, 21 Jan 2020 19:15:45 +0000 Subject: [PATCH 1/2] make deps more similar to combinator version --- examples/handlers/simple_async_handlers_await/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/handlers/simple_async_handlers_await/Cargo.toml b/examples/handlers/simple_async_handlers_await/Cargo.toml index df20d0f35..cf7b1ca30 100644 --- a/examples/handlers/simple_async_handlers_await/Cargo.toml +++ b/examples/handlers/simple_async_handlers_await/Cargo.toml @@ -10,8 +10,8 @@ edition = "2018" gotham = { path = "../../../gotham" } gotham_derive = { path = "../../../gotham_derive" } -mime = "0.3.16" +mime = "0.3" futures = "0.3.1" -serde = "1.0.104" -serde_derive = "1.0.104" +serde = "1.0" +serde_derive = "1.0" tokio = "0.2.9" From 491cede02c15a4770b13525d1ed2ed8b4dcd5946 Mon Sep 17 00:00:00 2001 From: David Laban Date: Tue, 21 Jan 2020 21:10:12 +0000 Subject: [PATCH 2/2] can't get the lifetimes right --- .../simple_async_handlers_await/src/main.rs | 29 +++++-------------- gotham/src/handler/mod.rs | 5 ++-- gotham/src/router/builder/single.rs | 25 +++++++++++----- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/examples/handlers/simple_async_handlers_await/src/main.rs b/examples/handlers/simple_async_handlers_await/src/main.rs index 3d0a1449f..24f1985ca 100644 --- a/examples/handlers/simple_async_handlers_await/src/main.rs +++ b/examples/handlers/simple_async_handlers_await/src/main.rs @@ -4,9 +4,9 @@ use futures::prelude::*; use std::pin::Pin; use std::time::{Duration, Instant}; -use gotham::hyper::{Body, StatusCode}; +use gotham::hyper::{Body, Response, StatusCode}; -use gotham::handler::HandlerResult; +use gotham::handler::{HandlerError, HandlerResult}; use gotham::helpers::http::response::create_response; use gotham::router::builder::DefineSingleRoute; use gotham::router::builder::{build_simple_router, DrawRoutes}; @@ -60,34 +60,21 @@ fn sleep(seconds: u64) -> SleepFuture { /// This handler sleeps for the requested number of seconds, using the `sleep()` /// helper method, above. -async fn sleep_handler(mut state: State) -> HandlerResult { - let seconds = QueryStringExtractor::take_from(&mut state).seconds; +async fn sleep_handler(state: &mut State) -> HandlerResult { + let seconds = QueryStringExtractor::take_from(state).seconds; println!("sleep for {} seconds once: starting", seconds); - // Here, we call the sleep function and turn its old-style future into - // a new-style future. Note that this step doesn't block: it just sets - // up the timer so that we can use it later. let sleep_future = sleep(seconds); - - // Here is where the serious sleeping happens. We yield execution of - // this block until sleep_future is resolved. - // The Ok("slept for x seconds") value is stored in result. let data = sleep_future.await; - - // Here, we convert the result from `sleep()` into the form that Gotham - // expects: `state` is owned by this block so we need to return it. - // We also convert any errors that we have into the form that Hyper - // expects, using the helper from IntoHandlerError. let res = create_response(&state, StatusCode::OK, mime::TEXT_PLAIN, data); - println!("sleep for {} seconds once: finished", seconds); - Ok((state, res)) + Ok(res) } /// It calls sleep(1) as many times as needed to make the requested duration. /// /// Notice how much easier it is to read than the version in /// `simple_async_handlers`. -async fn loop_handler(mut state: State) -> HandlerResult { - let seconds = QueryStringExtractor::take_from(&mut state).seconds; +async fn loop_handler(state: &mut State) -> HandlerResult { + let seconds = QueryStringExtractor::take_from(state).seconds; println!("sleep for one second {} times: starting", seconds); // The code within this block reads exactly like syncronous code. @@ -106,7 +93,7 @@ async fn loop_handler(mut state: State) -> HandlerResult { Body::from(accumulator), ); println!("sleep for one second {} times: finished", seconds); - Ok((state, res)) + Ok(res) } /// Create a `Router`. diff --git a/gotham/src/handler/mod.rs b/gotham/src/handler/mod.rs index 1a4f452a0..c3175b93c 100644 --- a/gotham/src/handler/mod.rs +++ b/gotham/src/handler/mod.rs @@ -24,13 +24,14 @@ pub mod assets; pub use self::error::{HandlerError, IntoHandlerError}; /// A type alias for the results returned by async fns that can be passed to to_async. -pub type HandlerResult = std::result::Result<(State, Response), (State, HandlerError)>; +pub type HandlerResult = std::result::Result, HandlerError>; /// A type alias for the trait objects returned by `HandlerService`. /// /// When the `Future` resolves to an error, the `(State, HandlerError)` value is used to generate /// an appropriate HTTP error response. -pub type HandlerFuture = dyn Future + Send; +pub type HandlerFuture = + dyn Future), (State, HandlerError)>> + Send; /// A `Handler` is an asynchronous function, taking a `State` value which represents the request /// and related runtime state, and returns a future which resolves to a response. diff --git a/gotham/src/router/builder/single.rs b/gotham/src/router/builder/single.rs index 8e6e7ca6a..8337ec809 100644 --- a/gotham/src/router/builder/single.rs +++ b/gotham/src/router/builder/single.rs @@ -4,7 +4,7 @@ use std::panic::RefUnwindSafe; use crate::extractor::{PathExtractor, QueryStringExtractor}; use crate::handler::assets::{DirHandler, FileHandler, FileOptions, FilePathExtractor}; -use crate::handler::{Handler, HandlerResult, NewHandler}; +use crate::handler::{Handler, HandlerFuture, HandlerResult, NewHandler}; use crate::pipeline::chain::PipelineHandleChain; use crate::router::builder::{ ExtendRouteMatcher, ReplacePathExtractor, ReplaceQueryStringExtractor, SingleRouteBuilder, @@ -127,9 +127,9 @@ pub trait DefineSingleRoute { /// # use gotham::middleware::session::NewSessionMiddleware; /// # use gotham::test::TestServer; /// # - /// async fn my_handler(state: State) -> HandlerResult { + /// async fn my_handler(state: &mut State) -> HandlerResult { /// // Handler implementation elided. - /// # Ok((state, Response::builder().status(StatusCode::ACCEPTED).body(Body::empty()).unwrap())) + /// # Ok(Response::builder().status(StatusCode::ACCEPTED).body(Body::empty()).unwrap()) /// } /// # /// # fn router() -> Router { @@ -152,13 +152,24 @@ pub trait DefineSingleRoute { /// # assert_eq!(response.status(), StatusCode::ACCEPTED); /// # } /// ``` - fn to_async(self, handler: H) + fn to_async<'s, H, Fut>(self, handler: H) where Self: Sized, - H: (FnOnce(State) -> Fut) + RefUnwindSafe + Copy + Send + Sync + 'static, - Fut: Future + Send + 'static, + H: (FnOnce(&'_ mut State) -> Fut) + RefUnwindSafe + Copy + Send + Sync + 'static, + Fut: Future + Send, { - self.to_new_handler(move || Ok(move |s: State| handler(s).boxed())) + self.to_new_handler(move || { + Ok(move |mut state: State| { + async move { + let res = { handler(&mut state).await }; + match res { + Ok(r) => Ok((state, r)), + Err(e) => Err((state, e)), + } + } + .boxed() + }) + }) } /// Directs the route to the given `NewHandler`. This gives more control over how `Handler` /// values are constructed.