Add 'FromRequestAsync' and use it in route codegen.

'FromRequestAsync' is automatically implemented for all types
that implement 'FromRequest'.
This commit is contained in:
Jeb Rosen 2019-10-20 14:25:04 -07:00 committed by Sergio Benitez
parent ea06878581
commit adf7e4233a
3 changed files with 28 additions and 2 deletions

View File

@ -313,7 +313,7 @@ fn request_guard_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
let span = ident.span().unstable().join(ty.span()).unwrap().into();
quote_spanned! { span =>
#[allow(non_snake_case, unreachable_patterns, unreachable_code)]
let #ident: #ty = match <#ty as #request::FromRequest>::from_request(#req) {
let #ident: #ty = match <#ty as #request::FromRequestAsync>::from_request(#req).await {
#Outcome::Success(__v) => __v,
#Outcome::Forward(_) => return #Outcome::Forward(#data),
#Outcome::Failure((__c, _)) => return #Outcome::Failure(__c),

View File

@ -1,6 +1,8 @@
use std::fmt::Debug;
use std::net::SocketAddr;
use futures_core::future::BoxFuture;
use crate::router::Route;
use crate::request::Request;
use crate::outcome::{self, IntoOutcome};
@ -32,6 +34,22 @@ impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
}
}
/// Type alias for the future returned by [`FromRequestAsync::from_request`].
pub type FromRequestFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
pub trait FromRequestAsync<'a, 'r>: Sized {
/// The associated error to be returned if derivation fails.
type Error: Debug;
/// Derives an instance of `Self` from the incoming request metadata.
///
/// If the derivation is successful, an outcome of `Success` is returned. If
/// 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.
fn from_request<'fut>(request: &'a Request<'r>) -> FromRequestFuture<'fut, Self, Self::Error> where 'a: 'fut;
}
/// Trait implemented by request guards to derive a value from incoming
/// requests.
///
@ -356,6 +374,14 @@ pub trait FromRequest<'a, 'r>: Sized {
fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error>;
}
impl<'a, 'r, T: FromRequest<'a, 'r>> FromRequestAsync<'a, 'r> for T {
type Error = T::Error;
fn from_request<'fut>(request: &'a Request<'r>) -> BoxFuture<'fut, Outcome<Self, Self::Error>> where 'a: 'fut {
Box::pin(async move { T::from_request(request) })
}
}
impl FromRequest<'_, '_> for Method {
type Error = std::convert::Infallible;

View File

@ -13,7 +13,7 @@ mod tests;
#[doc(hidden)] pub use rocket_codegen::{FromForm, FromFormValue};
pub use self::request::Request;
pub use self::from_request::{FromRequest, Outcome};
pub use self::from_request::{FromRequest, FromRequestAsync, FromRequestFuture, Outcome};
pub use self::param::{FromParam, FromSegments};
pub use self::form::{FromForm, FromFormValue};
pub use self::form::{Form, LenientForm, FormItems, FormItem};