From 70b42e6f0eb181f4540788162609328c9af277b6 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sun, 14 Mar 2021 19:57:59 -0700 Subject: [PATCH] Remove second lifetime from 'FromRequest'. While offering some utility, the lifetime did not carry its weight, and in practice offered no further ability to borrow. This greatly simplifies request guard implementations. --- contrib/codegen/src/database.rs | 6 +- .../ui-fail-nightly/database-types.stderr | 36 ++--- .../ui-fail-stable/database-types.stderr | 36 ++--- contrib/lib/src/databases/connection.rs | 4 +- contrib/lib/src/templates/metadata.rs | 4 +- .../ui-fail-nightly/route-type-errors.stderr | 16 +-- .../ui-fail-stable/route-type-errors.stderr | 16 +-- core/lib/src/config/config.rs | 4 +- core/lib/src/config/secret_key.rs | 4 +- core/lib/src/cookies.rs | 4 +- core/lib/src/data/limits.rs | 4 +- core/lib/src/fairing/mod.rs | 4 +- core/lib/src/outcome.rs | 8 +- core/lib/src/request/from_request.rs | 124 ++++++++---------- core/lib/src/request/request.rs | 2 +- core/lib/src/response/flash.rs | 4 +- core/lib/src/shutdown.rs | 4 +- core/lib/src/state.rs | 29 ++-- .../local-request-content-type-issue-505.rs | 4 +- examples/request_guard/src/main.rs | 4 +- examples/request_local_state/src/main.rs | 16 +-- examples/session/src/main.rs | 4 +- site/guide/6-state.md | 8 +- 23 files changed, 170 insertions(+), 175 deletions(-) diff --git a/contrib/codegen/src/database.rs b/contrib/codegen/src/database.rs index 6d844267..f4bde41a 100644 --- a/contrib/codegen/src/database.rs +++ b/contrib/codegen/src/database.rs @@ -47,10 +47,10 @@ fn parse_invocation(attr: TokenStream, input: TokenStream) -> Result Result #request::FromRequest<'a, 'r> for #guard_type { + impl<'r> #request::FromRequest<'r> for #guard_type { type Error = (); - async fn from_request(__r: &'a #request::Request<'r>) -> #request::Outcome { + async fn from_request(__r: &'r #request::Request<'_>) -> #request::Outcome { <#conn>::from_request(__r).await.map(Self) } } diff --git a/contrib/codegen/tests/ui-fail-nightly/database-types.stderr b/contrib/codegen/tests/ui-fail-nightly/database-types.stderr index 95e996f9..92c1ddd6 100644 --- a/contrib/codegen/tests/ui-fail-nightly/database-types.stderr +++ b/contrib/codegen/tests/ui-fail-nightly/database-types.stderr @@ -1,21 +1,21 @@ error[E0277]: the trait bound `Unknown: Poolable` is not satisfied - --> $DIR/database-types.rs:7:10 - | -7 | struct A(Unknown); - | ^^^^^^^ the trait `Poolable` is not implemented for `Unknown` - | - ::: $WORKSPACE/contrib/lib/src/databases.rs - | - | pub struct Connection { - | -------- required by this bound in `rocket_contrib::databases::Connection` + --> $DIR/database-types.rs:7:10 + | +7 | struct A(Unknown); + | ^^^^^^^ the trait `Poolable` is not implemented for `Unknown` + | + ::: $WORKSPACE/contrib/lib/src/databases/connection.rs + | + | pub struct Connection { + | -------- required by this bound in `rocket_contrib::databases::Connection` error[E0277]: the trait bound `Vec: Poolable` is not satisfied - --> $DIR/database-types.rs:10:10 - | -10 | struct B(Vec); - | ^^^^^^^^ the trait `Poolable` is not implemented for `Vec` - | - ::: $WORKSPACE/contrib/lib/src/databases.rs - | - | pub struct Connection { - | -------- required by this bound in `rocket_contrib::databases::Connection` + --> $DIR/database-types.rs:10:10 + | +10 | struct B(Vec); + | ^^^^^^^^ the trait `Poolable` is not implemented for `Vec` + | + ::: $WORKSPACE/contrib/lib/src/databases/connection.rs + | + | pub struct Connection { + | -------- required by this bound in `rocket_contrib::databases::Connection` diff --git a/contrib/codegen/tests/ui-fail-stable/database-types.stderr b/contrib/codegen/tests/ui-fail-stable/database-types.stderr index 870829a1..76e5787d 100644 --- a/contrib/codegen/tests/ui-fail-stable/database-types.stderr +++ b/contrib/codegen/tests/ui-fail-stable/database-types.stderr @@ -1,21 +1,21 @@ error[E0277]: the trait bound `Unknown: Poolable` is not satisfied - --> $DIR/database-types.rs:7:10 - | -7 | struct A(Unknown); - | ^^^^^^^ the trait `Poolable` is not implemented for `Unknown` - | - ::: $WORKSPACE/contrib/lib/src/databases.rs - | - | pub struct Connection { - | -------- required by this bound in `rocket_contrib::databases::Connection` + --> $DIR/database-types.rs:7:10 + | +7 | struct A(Unknown); + | ^^^^^^^ the trait `Poolable` is not implemented for `Unknown` + | + ::: $WORKSPACE/contrib/lib/src/databases/connection.rs + | + | pub struct Connection { + | -------- required by this bound in `rocket_contrib::databases::Connection` error[E0277]: the trait bound `Vec: Poolable` is not satisfied - --> $DIR/database-types.rs:10:10 - | -10 | struct B(Vec); - | ^^^ the trait `Poolable` is not implemented for `Vec` - | - ::: $WORKSPACE/contrib/lib/src/databases.rs - | - | pub struct Connection { - | -------- required by this bound in `rocket_contrib::databases::Connection` + --> $DIR/database-types.rs:10:10 + | +10 | struct B(Vec); + | ^^^ the trait `Poolable` is not implemented for `Vec` + | + ::: $WORKSPACE/contrib/lib/src/databases/connection.rs + | + | pub struct Connection { + | -------- required by this bound in `rocket_contrib::databases::Connection` diff --git a/contrib/lib/src/databases/connection.rs b/contrib/lib/src/databases/connection.rs index 0985fd70..5aa76495 100644 --- a/contrib/lib/src/databases/connection.rs +++ b/contrib/lib/src/databases/connection.rs @@ -172,11 +172,11 @@ impl Drop for ConnectionPool { } #[rocket::async_trait] -impl<'a, 'r, K: 'static, C: Poolable> FromRequest<'a, 'r> for Connection { +impl<'r, K: 'static, C: Poolable> FromRequest<'r> for Connection { type Error = (); #[inline] - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { match request.managed_state::>() { Some(c) => c.get().await.into_outcome(Status::ServiceUnavailable), None => { diff --git a/contrib/lib/src/templates/metadata.rs b/contrib/lib/src/templates/metadata.rs index 3c095aef..1fe0cbd0 100644 --- a/contrib/lib/src/templates/metadata.rs +++ b/contrib/lib/src/templates/metadata.rs @@ -85,10 +85,10 @@ impl Metadata<'_> { /// an error is printed and an empty `Err` with status `InternalServerError` /// (`500`) is returned. #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for Metadata<'a> { +impl<'r> FromRequest<'r> for Metadata<'r> { type Error = (); - async fn from_request(request: &'a Request<'r>) -> request::Outcome { + async fn from_request(request: &'r Request<'_>) -> request::Outcome { request.guard::>().await .succeeded() .and_then(|cm| Some(request::Outcome::Success(Metadata(cm.inner())))) diff --git a/core/codegen/tests/ui-fail-nightly/route-type-errors.stderr b/core/codegen/tests/ui-fail-nightly/route-type-errors.stderr index 9cfd1fe7..45c6c90f 100644 --- a/core/codegen/tests/ui-fail-nightly/route-type-errors.stderr +++ b/core/codegen/tests/ui-fail-nightly/route-type-errors.stderr @@ -41,16 +41,16 @@ error[E0277]: the trait bound `Q: FromData<'_>` is not satisfied | async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome; | -- required by this bound in `rocket::data::FromData::from_data` -error[E0277]: the trait bound `Q: FromRequest<'_, '_>` is not satisfied +error[E0277]: the trait bound `Q: FromRequest<'_>` is not satisfied --> $DIR/route-type-errors.rs:21:10 | 21 | fn f5(a: Q, foo: Q) {} - | ^ the trait `FromRequest<'_, '_>` is not implemented for `Q` + | ^ the trait `FromRequest<'_>` is not implemented for `Q` | ::: $WORKSPACE/core/lib/src/request/from_request.rs | - | pub trait FromRequest<'a, 'r>: Sized { - | -- required by this bound in `from_request` + | async fn from_request(request: &'r Request<'_>) -> Outcome; + | -- required by this bound in `from_request` error[E0277]: the trait bound `Q: FromParam<'_>` is not satisfied --> $DIR/route-type-errors.rs:21:18 @@ -60,16 +60,16 @@ error[E0277]: the trait bound `Q: FromParam<'_>` is not satisfied | = note: required by `from_param` -error[E0277]: the trait bound `Q: FromRequest<'_, '_>` is not satisfied +error[E0277]: the trait bound `Q: FromRequest<'_>` is not satisfied --> $DIR/route-type-errors.rs:24:10 | 24 | fn f6(a: Q, foo: Q, good: usize, bar: Q) {} - | ^ the trait `FromRequest<'_, '_>` is not implemented for `Q` + | ^ the trait `FromRequest<'_>` is not implemented for `Q` | ::: $WORKSPACE/core/lib/src/request/from_request.rs | - | pub trait FromRequest<'a, 'r>: Sized { - | -- required by this bound in `from_request` + | async fn from_request(request: &'r Request<'_>) -> Outcome; + | -- required by this bound in `from_request` error[E0277]: the trait bound `Q: FromParam<'_>` is not satisfied --> $DIR/route-type-errors.rs:24:18 diff --git a/core/codegen/tests/ui-fail-stable/route-type-errors.stderr b/core/codegen/tests/ui-fail-stable/route-type-errors.stderr index 9cfd1fe7..45c6c90f 100644 --- a/core/codegen/tests/ui-fail-stable/route-type-errors.stderr +++ b/core/codegen/tests/ui-fail-stable/route-type-errors.stderr @@ -41,16 +41,16 @@ error[E0277]: the trait bound `Q: FromData<'_>` is not satisfied | async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome; | -- required by this bound in `rocket::data::FromData::from_data` -error[E0277]: the trait bound `Q: FromRequest<'_, '_>` is not satisfied +error[E0277]: the trait bound `Q: FromRequest<'_>` is not satisfied --> $DIR/route-type-errors.rs:21:10 | 21 | fn f5(a: Q, foo: Q) {} - | ^ the trait `FromRequest<'_, '_>` is not implemented for `Q` + | ^ the trait `FromRequest<'_>` is not implemented for `Q` | ::: $WORKSPACE/core/lib/src/request/from_request.rs | - | pub trait FromRequest<'a, 'r>: Sized { - | -- required by this bound in `from_request` + | async fn from_request(request: &'r Request<'_>) -> Outcome; + | -- required by this bound in `from_request` error[E0277]: the trait bound `Q: FromParam<'_>` is not satisfied --> $DIR/route-type-errors.rs:21:18 @@ -60,16 +60,16 @@ error[E0277]: the trait bound `Q: FromParam<'_>` is not satisfied | = note: required by `from_param` -error[E0277]: the trait bound `Q: FromRequest<'_, '_>` is not satisfied +error[E0277]: the trait bound `Q: FromRequest<'_>` is not satisfied --> $DIR/route-type-errors.rs:24:10 | 24 | fn f6(a: Q, foo: Q, good: usize, bar: Q) {} - | ^ the trait `FromRequest<'_, '_>` is not implemented for `Q` + | ^ the trait `FromRequest<'_>` is not implemented for `Q` | ::: $WORKSPACE/core/lib/src/request/from_request.rs | - | pub trait FromRequest<'a, 'r>: Sized { - | -- required by this bound in `from_request` + | async fn from_request(request: &'r Request<'_>) -> Outcome; + | -- required by this bound in `from_request` error[E0277]: the trait bound `Q: FromParam<'_>` is not satisfied --> $DIR/route-type-errors.rs:24:18 diff --git a/core/lib/src/config/config.rs b/core/lib/src/config/config.rs index 94d40f9b..674ccb63 100644 --- a/core/lib/src/config/config.rs +++ b/core/lib/src/config/config.rs @@ -380,10 +380,10 @@ impl Provider for Config { } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'r Config { +impl<'r> FromRequest<'r> for &'r Config { type Error = std::convert::Infallible; - async fn from_request(req: &'a Request<'r>) -> request::Outcome { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { request::Outcome::Success(req.config()) } } diff --git a/core/lib/src/config/secret_key.rs b/core/lib/src/config/secret_key.rs index a5d54c51..7c697584 100644 --- a/core/lib/src/config/secret_key.rs +++ b/core/lib/src/config/secret_key.rs @@ -182,10 +182,10 @@ impl PartialEq for SecretKey { } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'a SecretKey { +impl<'r> FromRequest<'r> for &'r SecretKey { type Error = std::convert::Infallible; - async fn from_request(req: &'a Request<'r>) -> Outcome { + async fn from_request(req: &'r Request<'_>) -> Outcome { Outcome::Success(&req.state.config.secret_key) } } diff --git a/core/lib/src/cookies.rs b/core/lib/src/cookies.rs index b9dbf8da..e9b374b4 100644 --- a/core/lib/src/cookies.rs +++ b/core/lib/src/cookies.rs @@ -111,10 +111,10 @@ pub use self::cookie::{Cookie, SameSite, Iter}; /// struct User(usize); /// /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for User { +/// impl<'r> FromRequest<'r> for User { /// type Error = std::convert::Infallible; /// -/// async fn from_request(request: &'a Request<'r>) -> request::Outcome { +/// async fn from_request(request: &'r Request<'_>) -> request::Outcome { /// request.cookies() /// .get_private("user_id") /// .and_then(|c| c.value().parse().ok()) diff --git a/core/lib/src/data/limits.rs b/core/lib/src/data/limits.rs index e1dbe113..c064fa06 100644 --- a/core/lib/src/data/limits.rs +++ b/core/lib/src/data/limits.rs @@ -300,10 +300,10 @@ impl fmt::Display for Limits { } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'r Limits { +impl<'r> FromRequest<'r> for &'r Limits { type Error = std::convert::Infallible; - async fn from_request(req: &'a Request<'r>) -> Outcome { + async fn from_request(req: &'r Request<'_>) -> Outcome { Outcome::Success(req.limits()) } } diff --git a/core/lib/src/fairing/mod.rs b/core/lib/src/fairing/mod.rs index 0f4c29e5..386a2e81 100644 --- a/core/lib/src/fairing/mod.rs +++ b/core/lib/src/fairing/mod.rs @@ -353,10 +353,10 @@ pub use self::info_kind::{Info, Kind}; /// /// // Allows a route to access the time a request was initiated. /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for StartTime { +/// impl<'r> FromRequest<'r> for StartTime { /// type Error = (); /// -/// async fn from_request(request: &'a Request<'r>) -> request::Outcome { +/// async fn from_request(request: &'r Request<'_>) -> request::Outcome { /// match *request.local_cache(|| TimerStart(None)) { /// TimerStart(Some(time)) => request::Outcome::Success(StartTime(time)), /// TimerStart(None) => request::Outcome::Failure((Status::InternalServerError, ())), diff --git a/core/lib/src/outcome.rs b/core/lib/src/outcome.rs index b0e23e6b..9b86db0c 100644 --- a/core/lib/src/outcome.rs +++ b/core/lib/src/outcome.rs @@ -645,10 +645,10 @@ impl<'a, S: Send + 'a, E: Send + 'a, F: Send + 'a> Outcome { /// struct Guard2; /// /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for Guard1 { +/// impl<'r> FromRequest<'r> for Guard1 { /// type Error = (); /// -/// async fn from_request(req: &'a Request<'r>) -> request::Outcome { +/// async fn from_request(req: &'r Request<'_>) -> request::Outcome { /// // Attempt to fetch the guard, passing through any error or forward. /// let atomics = try_outcome!(req.guard::>().await); /// atomics.uncached.fetch_add(1, Ordering::Relaxed); @@ -659,10 +659,10 @@ impl<'a, S: Send + 'a, E: Send + 'a, F: Send + 'a> Outcome { /// } /// /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for Guard2 { +/// impl<'r> FromRequest<'r> for Guard2 { /// type Error = (); /// -/// async fn from_request(req: &'a Request<'r>) -> request::Outcome { +/// async fn from_request(req: &'r Request<'_>) -> request::Outcome { /// // Attempt to fetch the guard, passing through any error or forward. /// let guard1: Guard1 = try_outcome!(req.guard::().await); /// Success(Guard2) diff --git a/core/lib/src/request/from_request.rs b/core/lib/src/request/from_request.rs index 562419e6..084fe006 100644 --- a/core/lib/src/request/from_request.rs +++ b/core/lib/src/request/from_request.rs @@ -1,8 +1,6 @@ use std::fmt::Debug; use std::net::{IpAddr, SocketAddr}; -use futures::future::BoxFuture; - use crate::router::Route; use crate::request::Request; use crate::outcome::{self, IntoOutcome}; @@ -60,10 +58,10 @@ impl IntoOutcome for Result { /// # type MyError = String; /// /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for MyType { +/// impl<'r> FromRequest<'r> for MyType { /// type Error = MyError; /// -/// async fn from_request(req: &'a Request<'r>) -> request::Outcome { +/// async fn from_request(req: &'r Request<'_>) -> request::Outcome { /// /* .. */ /// # unimplemented!() /// } @@ -203,42 +201,36 @@ impl IntoOutcome for Result { /// use rocket::http::Status; /// use rocket::request::{self, Outcome, Request, FromRequest}; /// -/// struct ApiKey(String); -/// -/// /// Returns true if `key` is a valid API key string. -/// fn is_valid(key: &str) -> bool { -/// key == "valid_api_key" -/// } +/// struct ApiKey<'r>(&'r str); /// /// #[derive(Debug)] /// enum ApiKeyError { -/// BadCount, /// Missing, /// Invalid, /// } /// /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for ApiKey { +/// impl<'r> FromRequest<'r> for ApiKey<'r> { /// type Error = ApiKeyError; /// -/// async fn from_request(req: &'a Request<'r>) -> Outcome { -/// let keys: Vec<_> = req.headers().get("x-api-key").collect(); -/// match keys.len() { -/// 0 => Outcome::Failure((Status::BadRequest, ApiKeyError::Missing)), -/// 1 if is_valid(keys[0]) => Outcome::Success(ApiKey(keys[0].to_string())), -/// 1 => Outcome::Failure((Status::BadRequest, ApiKeyError::Invalid)), -/// _ => Outcome::Failure((Status::BadRequest, ApiKeyError::BadCount)), +/// async fn from_request(req: &'r Request<'_>) -> Outcome { +/// /// Returns true if `key` is a valid API key string. +/// fn is_valid(key: &str) -> bool { +/// key == "valid_api_key" +/// } +/// +/// match req.headers().get_one("x-api-key") { +/// None => Outcome::Failure((Status::BadRequest, ApiKeyError::Missing)), +/// Some(key) if is_valid(key) => Outcome::Success(ApiKey(key)), +/// Some(_) => Outcome::Failure((Status::BadRequest, ApiKeyError::Invalid)), /// } /// } /// } /// /// #[get("/sensitive")] -/// fn sensitive(key: ApiKey) -> &'static str { -/// # let _key = key; +/// fn sensitive(key: ApiKey<'_>) -> &'static str { /// "Sensitive data." /// } -/// -/// # fn main() { } /// ``` /// /// # Request-Local State @@ -264,9 +256,9 @@ impl IntoOutcome for Result { /// # } /// # } /// # #[rocket::async_trait] -/// # impl<'a, 'r> FromRequest<'a, 'r> for Database { +/// # impl<'r> FromRequest<'r> for Database { /// # type Error = (); -/// # async fn from_request(request: &'a Request<'r>) -> Outcome { +/// # async fn from_request(request: &'r Request<'_>) -> Outcome { /// # Outcome::Success(Database) /// # } /// # } @@ -274,10 +266,10 @@ impl IntoOutcome for Result { /// # struct Admin { user: User } /// # /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for User { +/// impl<'r> FromRequest<'r> for User { /// type Error = (); /// -/// async fn from_request(request: &'a Request<'r>) -> Outcome { +/// async fn from_request(request: &'r Request<'_>) -> Outcome { /// let db = try_outcome!(request.guard::().await); /// request.cookies() /// .get_private("user_id") @@ -288,10 +280,10 @@ impl IntoOutcome for Result { /// } /// /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for Admin { +/// impl<'r> FromRequest<'r> for Admin { /// type Error = (); /// -/// async fn from_request(request: &'a Request<'r>) -> Outcome { +/// async fn from_request(request: &'r Request<'_>) -> Outcome { /// // This will unconditionally query the database! /// let user = try_outcome!(request.guard::().await); /// if user.is_admin { @@ -328,9 +320,9 @@ impl IntoOutcome for Result { /// # } /// # } /// # #[rocket::async_trait] -/// # impl<'a, 'r> FromRequest<'a, 'r> for Database { +/// # impl<'r> FromRequest<'r> for Database { /// # type Error = (); -/// # async fn from_request(request: &'a Request<'r>) -> Outcome { +/// # async fn from_request(request: &'r Request<'_>) -> Outcome { /// # Outcome::Success(Database) /// # } /// # } @@ -338,10 +330,10 @@ impl IntoOutcome for Result { /// # struct Admin<'a> { user: &'a User } /// # /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for &'a User { +/// impl<'r> FromRequest<'r> for &'r User { /// type Error = std::convert::Infallible; /// -/// async fn from_request(request: &'a Request<'r>) -> Outcome { +/// async fn from_request(request: &'r Request<'_>) -> Outcome { /// // This closure will execute at most once per request, regardless of /// // the number of times the `User` guard is executed. /// let user_result = request.local_cache_async(async { @@ -357,10 +349,10 @@ impl IntoOutcome for Result { /// } /// /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for Admin<'a> { +/// impl<'r> FromRequest<'r> for Admin<'r> { /// type Error = std::convert::Infallible; /// -/// async fn from_request(request: &'a Request<'r>) -> Outcome { +/// async fn from_request(request: &'r Request<'_>) -> Outcome { /// let user = try_outcome!(request.guard::<&User>().await); /// if user.is_admin { /// Outcome::Success(Admin { user }) @@ -377,7 +369,7 @@ impl IntoOutcome for Result { /// /// [request-local state]: https://rocket.rs/master/guide/state/#request-local-state #[crate::async_trait] -pub trait FromRequest<'a, 'r>: Sized { +pub trait FromRequest<'r>: Sized { /// The associated error to be returned if derivation fails. type Error: Debug; @@ -387,32 +379,32 @@ pub trait FromRequest<'a, 'r>: Sized { /// the derivation fails in an unrecoverable fashion, `Failure` is returned. /// `Forward` is returned to indicate that the request should be forwarded /// to other matching routes, if any. - async fn from_request(request: &'a Request<'r>) -> Outcome; + async fn from_request(request: &'r Request<'_>) -> Outcome; } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for Method { +impl<'r> FromRequest<'r> for Method { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { Success(request.method()) } } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'a Origin<'a> { +impl<'r> FromRequest<'r> for &'r Origin<'r> { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { Success(request.uri()) } } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'r Route { +impl<'r> FromRequest<'r> for &'r Route { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { match request.route() { Some(route) => Success(route), None => Forward(()) @@ -421,19 +413,19 @@ impl<'a, 'r> FromRequest<'a, 'r> for &'r Route { } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'a CookieJar<'r> { +impl<'r> FromRequest<'r> for &'r CookieJar<'r> { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { Success(request.cookies()) } } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'a Accept { +impl<'r> FromRequest<'r> for &'r Accept { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { match request.accept() { Some(accept) => Success(accept), None => Forward(()) @@ -442,10 +434,10 @@ impl<'a, 'r> FromRequest<'a, 'r> for &'a Accept { } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'a ContentType { +impl<'r> FromRequest<'r> for &'r ContentType { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { match request.content_type() { Some(content_type) => Success(content_type), None => Forward(()) @@ -454,10 +446,10 @@ impl<'a, 'r> FromRequest<'a, 'r> for &'a ContentType { } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for IpAddr { +impl<'r> FromRequest<'r> for IpAddr { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { match request.client_ip() { Some(addr) => Success(addr), None => Forward(()) @@ -466,10 +458,10 @@ impl<'a, 'r> FromRequest<'a, 'r> for IpAddr { } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for SocketAddr { +impl<'r> FromRequest<'r> for SocketAddr { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { match request.remote() { Some(addr) => Success(addr), None => Forward(()) @@ -477,33 +469,27 @@ impl<'a, 'r> FromRequest<'a, 'r> for SocketAddr { } } -impl<'a, 'r, T: FromRequest<'a, 'r> + 'a> FromRequest<'a, 'r> for Result { +#[crate::async_trait] +impl<'r, T: FromRequest<'r>> FromRequest<'r> for Result { type Error = std::convert::Infallible; - fn from_request<'y>(request: &'a Request<'r>) -> BoxFuture<'y, Outcome> - where 'a: 'y, 'r: 'y - { - // TODO: FutureExt::map is a workaround (see rust-lang/rust#60658) - use futures::future::FutureExt; - T::from_request(request).map(|x| match x { + async fn from_request(request: &'r Request<'_>) -> Outcome { + match T::from_request(request).await { Success(val) => Success(Ok(val)), Failure((_, e)) => Success(Err(e)), Forward(_) => Forward(()), - }).boxed() + } } } -impl<'a, 'r, T: FromRequest<'a, 'r> + 'a> FromRequest<'a, 'r> for Option { +#[crate::async_trait] +impl<'r, T: FromRequest<'r>> FromRequest<'r> for Option { type Error = std::convert::Infallible; - fn from_request<'y>(request: &'a Request<'r>) -> BoxFuture<'y, Outcome> - where 'a: 'y, 'r: 'y - { - // TODO: FutureExt::map is a workaround (see rust-lang/rust#60658) - use futures::future::FutureExt; - T::from_request(request).map(|x| match x { + async fn from_request(request: &'r Request<'_>) -> Outcome { + match T::from_request(request).await { Success(val) => Success(Some(val)), Failure(_) | Forward(_) => Success(None), - }).boxed() + } } } diff --git a/core/lib/src/request/request.rs b/core/lib/src/request/request.rs index 9526c919..69d4aa0a 100644 --- a/core/lib/src/request/request.rs +++ b/core/lib/src/request/request.rs @@ -531,7 +531,7 @@ impl<'r> Request<'r> { /// # }) /// ``` pub fn guard<'z, 'a, T>(&'a self) -> BoxFuture<'z, Outcome> - where T: FromRequest<'a, 'r> + 'z, 'a: 'z, 'r: 'z + where T: FromRequest<'a> + 'z, 'a: 'z, 'r: 'z { T::from_request(self) } diff --git a/core/lib/src/response/flash.rs b/core/lib/src/response/flash.rs index fccbad35..af26c97a 100644 --- a/core/lib/src/response/flash.rs +++ b/core/lib/src/response/flash.rs @@ -237,10 +237,10 @@ impl<'a> FlashMessage<'a> { /// The suggested use is through an `Option` and the `FlashMessage` type alias /// in `request`: `Option`. #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for FlashMessage<'a> { +impl<'r> FromRequest<'r> for FlashMessage<'r> { type Error = (); - async fn from_request(req: &'a Request<'r>) -> request::Outcome { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { trace_!("Flash: attempting to retrieve message."); req.cookies().get(FLASH_COOKIE_NAME).ok_or(()).and_then(|cookie| { trace_!("Flash: retrieving message: {:?}", cookie); diff --git a/core/lib/src/shutdown.rs b/core/lib/src/shutdown.rs index 68f9e6cb..3c1c9e5c 100644 --- a/core/lib/src/shutdown.rs +++ b/core/lib/src/shutdown.rs @@ -50,11 +50,11 @@ impl Shutdown { } #[crate::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for Shutdown { +impl<'r> FromRequest<'r> for Shutdown { type Error = std::convert::Infallible; #[inline] - async fn from_request(request: &'a Request<'r>) -> Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { Outcome::Success(request.state.shutdown.clone()) } } diff --git a/core/lib/src/state.rs b/core/lib/src/state.rs index 25a9947c..39cc93c8 100644 --- a/core/lib/src/state.rs +++ b/core/lib/src/state.rs @@ -53,24 +53,33 @@ use crate::http::Status; /// # Within Request Guards /// /// Because `State` is itself a request guard, managed state can be retrieved -/// from another request guard's implementation. In the following code example, -/// `Item` retrieves the `MyConfig` managed state in its [`FromRequest`] -/// implementation using the [`Request::guard()`] method. +/// from another request guard's implementation using either +/// [`Request::guard()`] or [`Request::managed_state()`]. In the following code +/// example, the `Item` request guard retrieves `MyConfig` from managed state: /// /// ```rust /// use rocket::State; /// use rocket::request::{self, Request, FromRequest}; +/// use rocket::outcome::IntoOutcome; /// /// # struct MyConfig{ user_val: String }; -/// struct Item(String); +/// struct Item<'r>(&'r str); /// /// #[rocket::async_trait] -/// impl<'a, 'r> FromRequest<'a, 'r> for Item { +/// impl<'r> FromRequest<'r> for Item<'r> { /// type Error = (); /// -/// async fn from_request(request: &'a Request<'r>) -> request::Outcome { -/// request.guard::>().await -/// .map(|my_config| Item(my_config.user_val.clone())) +/// async fn from_request(request: &'r Request<'_>) -> request::Outcome { +/// // Using `State` as a request guard. Use `inner()` to get an `'r`. +/// let outcome = request.guard::>().await +/// .map(|my_config| Item(&my_config.inner().user_val)); +/// +/// // Or alternatively, using `Request::managed_state()`: +/// let outcome = request.managed_state::() +/// .map(|my_config| Item(&my_config.user_val)) +/// .or_forward(()); +/// +/// outcome /// } /// } /// ``` @@ -160,11 +169,11 @@ impl<'r, T: Send + Sync + 'static> State<'r, T> { } #[crate::async_trait] -impl<'a, 'r, T: Send + Sync + 'static> FromRequest<'a, 'r> for State<'r, T> { +impl<'r, T: Send + Sync + 'static> FromRequest<'r> for State<'r, T> { type Error = (); #[inline(always)] - async fn from_request(req: &'a Request<'r>) -> request::Outcome, ()> { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { match req.state.managed.try_get::() { Some(state) => Outcome::Success(State(state)), None => { diff --git a/core/lib/tests/local-request-content-type-issue-505.rs b/core/lib/tests/local-request-content-type-issue-505.rs index 8310e431..9d6490f1 100644 --- a/core/lib/tests/local-request-content-type-issue-505.rs +++ b/core/lib/tests/local-request-content-type-issue-505.rs @@ -7,10 +7,10 @@ use rocket::outcome::IntoOutcome; struct HasContentType; #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for HasContentType { +impl<'r> FromRequest<'r> for HasContentType { type Error = (); - async fn from_request(req: &'a Request<'r>) -> request::Outcome { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { req.content_type().map(|_| HasContentType).or_forward(()) } } diff --git a/examples/request_guard/src/main.rs b/examples/request_guard/src/main.rs index b0a4ec91..cc9cbf28 100644 --- a/examples/request_guard/src/main.rs +++ b/examples/request_guard/src/main.rs @@ -7,10 +7,10 @@ use rocket::outcome::Outcome::*; struct HeaderCount(usize); #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for HeaderCount { +impl<'r> FromRequest<'r> for HeaderCount { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> request::Outcome { + async fn from_request(request: &'r Request<'_>) -> request::Outcome { Success(HeaderCount(request.headers().len())) } } diff --git a/examples/request_local_state/src/main.rs b/examples/request_local_state/src/main.rs index 996534a5..3b5e4bfb 100644 --- a/examples/request_local_state/src/main.rs +++ b/examples/request_local_state/src/main.rs @@ -20,10 +20,10 @@ struct Guard3; struct Guard4; #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for Guard1 { +impl<'r> FromRequest<'r> for Guard1 { type Error = (); - async fn from_request(req: &'a Request<'r>) -> request::Outcome { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { let atomics = try_outcome!(req.guard::>().await); atomics.uncached.fetch_add(1, Ordering::Relaxed); req.local_cache(|| atomics.cached.fetch_add(1, Ordering::Relaxed)); @@ -33,20 +33,20 @@ impl<'a, 'r> FromRequest<'a, 'r> for Guard1 { } #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for Guard2 { +impl<'r> FromRequest<'r> for Guard2 { type Error = (); - async fn from_request(req: &'a Request<'r>) -> request::Outcome { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { try_outcome!(req.guard::().await); Outcome::Success(Guard2) } } #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for Guard3 { +impl<'r> FromRequest<'r> for Guard3 { type Error = (); - async fn from_request(req: &'a Request<'r>) -> request::Outcome { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { let atomics = try_outcome!(req.guard::>().await); atomics.uncached.fetch_add(1, Ordering::Relaxed); req.local_cache_async(async { @@ -58,10 +58,10 @@ impl<'a, 'r> FromRequest<'a, 'r> for Guard3 { } #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for Guard4 { +impl<'r> FromRequest<'r> for Guard4 { type Error = (); - async fn from_request(req: &'a Request<'r>) -> request::Outcome { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { try_outcome!(Guard3::from_request(req).await); Outcome::Success(Guard4) } diff --git a/examples/session/src/main.rs b/examples/session/src/main.rs index 5b7d4bdd..b5bed24e 100644 --- a/examples/session/src/main.rs +++ b/examples/session/src/main.rs @@ -22,10 +22,10 @@ struct Login { struct User(usize); #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for User { +impl<'r> FromRequest<'r> for User { type Error = std::convert::Infallible; - async fn from_request(request: &'a Request<'r>) -> request::Outcome { + async fn from_request(request: &'r Request<'_>) -> request::Outcome { request.cookies() .get_private("user_id") .and_then(|cookie| cookie.value().parse().ok()) diff --git a/site/guide/6-state.md b/site/guide/6-state.md index 85e388b7..8971996b 100644 --- a/site/guide/6-state.md +++ b/site/guide/6-state.md @@ -128,10 +128,10 @@ use rocket::request::{self, Request, FromRequest}; # struct HitCount { count: AtomicUsize } # type ErrorType = (); #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for T { +impl<'r> FromRequest<'r> for T { type Error = ErrorType; - async fn from_request(req: &'a Request<'r>) -> request::Outcome { + async fn from_request(req: &'r Request<'_>) -> request::Outcome { let hit_count_state = try_outcome!(req.guard::>().await); let current_count = hit_count_state.count.load(Ordering::Relaxed); /* ... */ @@ -173,10 +173,10 @@ struct RequestId(pub usize); /// Returns the current request's ID, assigning one only as necessary. #[rocket::async_trait] -impl<'a, 'r> FromRequest<'a, 'r> for &'a RequestId { +impl<'r> FromRequest<'r> for &'r RequestId { type Error = (); - async fn from_request(request: &'a Request<'r>) -> request::Outcome { + async fn from_request(request: &'r Request<'_>) -> request::Outcome { // The closure passed to `local_cache` will be executed at most once per // request: the first time the `RequestId` guard is used. If it is // requested again, `local_cache` will return the same value.