Skip to content

Commit

Permalink
Convert core to async and add support for async routes.
Browse files Browse the repository at this point in the history
Minimum rustc bump required for rust-lang/rust#61775
  • Loading branch information
jebrosen committed Dec 11, 2019
1 parent 55ae2b9 commit 175c6c0
Show file tree
Hide file tree
Showing 37 changed files with 812 additions and 646 deletions.
16 changes: 9 additions & 7 deletions core/codegen/src/attribute/catch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub fn _catch(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
let status_code = status.0.code;

// Variables names we'll use and reuse.
define_vars_and_mods!(req, catcher, response, Request, Response);
define_vars_and_mods!(req, catcher, Request, Response, ErrorHandlerFuture);

// Determine the number of parameters that will be passed in.
let (fn_sig, inputs) = match catch.function.sig.inputs.len() {
Expand Down Expand Up @@ -83,12 +83,14 @@ pub fn _catch(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
#user_catcher_fn

/// Rocket code generated wrapping catch function.
#vis fn #generated_fn_name<'_b>(#req: &'_b #Request) -> #response::Result<'_b> {
let __response = #catcher_response;
#Response::build()
.status(#status)
.merge(__response)
.ok()
#vis fn #generated_fn_name<'_b>(#req: &'_b #Request) -> #ErrorHandlerFuture<'_b> {
Box::pin(async move {
let __response = #catcher_response;
#Response::build()
.status(#status)
.merge(__response)
.ok()
})
}

/// Rocket code generated static catcher info.
Expand Down
32 changes: 22 additions & 10 deletions core/codegen/src/attribute/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ fn data_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
define_vars_and_mods!(req, data, FromData, Outcome, Transform);
let span = ident.span().unstable().join(ty.span()).unwrap().into();
quote_spanned! { span =>
let __transform = <#ty as #FromData>::transform(#req, #data);
let __transform = <#ty as #FromData>::transform(#req, #data).await;

#[allow(unreachable_patterns, unreachable_code)]
let __outcome = match __transform {
Expand All @@ -195,7 +195,7 @@ fn data_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
};

#[allow(non_snake_case, unreachable_patterns, unreachable_code)]
let #ident: #ty = match <#ty as #FromData>::from_data(#req, __outcome) {
let #ident: #ty = match <#ty as #FromData>::from_data(#req, __outcome).await {
#Outcome::Success(__d) => __d,
#Outcome::Forward(__d) => return #Outcome::Forward(__d),
#Outcome::Failure((__c, _)) => return #Outcome::Failure(__c),
Expand Down Expand Up @@ -368,8 +368,18 @@ fn generate_respond_expr(route: &Route) -> TokenStream2 {
let parameter_names = route.inputs.iter()
.map(|(_, rocket_ident, _)| rocket_ident);

let responder_stmt = if route.function.sig.asyncness.is_some() {
quote_spanned! { ret_span =>
let ___responder = #user_handler_fn_name(#(#parameter_names),*).await;
}
} else {
quote_spanned! { ret_span =>
let ___responder = #user_handler_fn_name(#(#parameter_names),*);
}
};

quote_spanned! { ret_span =>
let ___responder = #user_handler_fn_name(#(#parameter_names),*);
#responder_stmt
#handler::Outcome::from(#req, ___responder)
}
}
Expand Down Expand Up @@ -402,7 +412,7 @@ fn codegen_route(route: Route) -> Result<TokenStream> {
}

// Gather everything we need.
define_vars_and_mods!(req, data, handler, Request, Data, StaticRouteInfo);
define_vars_and_mods!(req, data, Request, Data, StaticRouteInfo, HandlerFuture);
let (vis, user_handler_fn) = (&route.function.vis, &route.function);
let user_handler_fn_name = &user_handler_fn.sig.ident;
let generated_fn_name = user_handler_fn_name.prepend(ROUTE_FN_PREFIX);
Expand All @@ -422,12 +432,14 @@ fn codegen_route(route: Route) -> Result<TokenStream> {
#vis fn #generated_fn_name<'_b>(
#req: &'_b #Request,
#data: #Data
) -> #handler::Outcome<'_b> {
#(#req_guard_definitions)*
#(#parameter_definitions)*
#data_stmt

#generated_respond_expr
) -> #HandlerFuture<'_b> {
Box::pin(async move {
#(#req_guard_definitions)*
#(#parameter_definitions)*
#data_stmt

#generated_respond_expr
})
}

/// Rocket code generated wrapping URI macro.
Expand Down
3 changes: 3 additions & 0 deletions core/codegen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![feature(proc_macro_diagnostic, proc_macro_span)]
#![feature(async_await)]
#![recursion_limit="128"]

#![doc(html_root_url = "https://api.rocket.rs/v0.5")]
Expand Down Expand Up @@ -96,6 +97,8 @@ vars_and_mods! {
Data => rocket::Data,
StaticRouteInfo => rocket::StaticRouteInfo,
SmallVec => rocket::http::private::SmallVec,
HandlerFuture => rocket::handler::HandlerFuture,
ErrorHandlerFuture => rocket::handler::ErrorHandlerFuture,
}

macro_rules! define_vars_and_mods {
Expand Down
2 changes: 1 addition & 1 deletion core/codegen/tests/route.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(proc_macro_hygiene)]
#![feature(proc_macro_hygiene, async_await)]

// Rocket sometimes generates mangled identifiers that activate the
// non_snake_case lint. We deny the lint in this test to ensure that
Expand Down
9 changes: 2 additions & 7 deletions core/http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ edition = "2018"

[features]
default = []
tls = ["rustls", "hyper-sync-rustls"]
tls = ["tokio-rustls"]
private-cookies = ["cookie/secure"]

[dependencies]
Expand All @@ -27,16 +27,11 @@ http = "0.1.17"
mime = "0.3.13"
time = "0.1"
indexmap = "1.0"
rustls = { version = "0.15", optional = true }
state = "0.4"
tokio-rustls = { version = "0.9.2", optional = true }
cookie = { version = "0.12", features = ["percent-encode"] }
pear = "0.1"
unicode-xid = "0.2"

[dependencies.hyper-sync-rustls]
version = "=0.3.0-rc.5"
features = ["server"]
optional = true

[dev-dependencies]
rocket = { version = "0.5.0-dev", path = "../lib" }
39 changes: 24 additions & 15 deletions core/http/src/cookies.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::fmt;
use std::cell::RefMut;

use crate::Header;
use cookie::Delta;
Expand Down Expand Up @@ -128,7 +127,7 @@ mod key {
/// 32`.
pub enum Cookies<'a> {
#[doc(hidden)]
Jarred(RefMut<'a, CookieJar>, &'a Key),
Jarred(CookieJar, &'a Key, Box<dyn FnOnce(CookieJar) + Send + 'a>),
#[doc(hidden)]
Empty(CookieJar)
}
Expand All @@ -137,8 +136,8 @@ impl<'a> Cookies<'a> {
/// WARNING: This is unstable! Do not use this method outside of Rocket!
#[inline]
#[doc(hidden)]
pub fn new(jar: RefMut<'a, CookieJar>, key: &'a Key) -> Cookies<'a> {
Cookies::Jarred(jar, key)
pub fn new<F: FnOnce(CookieJar) + Send + 'a>(jar: CookieJar, key: &'a Key, on_drop: F) -> Cookies<'a> {
Cookies::Jarred(jar, key, Box::new(on_drop))
}

/// WARNING: This is unstable! Do not use this method outside of Rocket!
Expand All @@ -160,7 +159,7 @@ impl<'a> Cookies<'a> {
#[inline]
#[doc(hidden)]
pub fn add_original(&mut self, cookie: Cookie<'static>) {
if let Cookies::Jarred(ref mut jar, _) = *self {
if let Cookies::Jarred(ref mut jar, _, _) = *self {
jar.add_original(cookie)
}
}
Expand All @@ -180,7 +179,7 @@ impl<'a> Cookies<'a> {
/// ```
pub fn get(&self, name: &str) -> Option<&Cookie<'static>> {
match *self {
Cookies::Jarred(ref jar, _) => jar.get(name),
Cookies::Jarred(ref jar, _, _) => jar.get(name),
Cookies::Empty(_) => None
}
}
Expand All @@ -205,7 +204,7 @@ impl<'a> Cookies<'a> {
/// }
/// ```
pub fn add(&mut self, cookie: Cookie<'static>) {
if let Cookies::Jarred(ref mut jar, _) = *self {
if let Cookies::Jarred(ref mut jar, _, _) = *self {
jar.add(cookie)
}
}
Expand All @@ -231,7 +230,7 @@ impl<'a> Cookies<'a> {
/// }
/// ```
pub fn remove(&mut self, cookie: Cookie<'static>) {
if let Cookies::Jarred(ref mut jar, _) = *self {
if let Cookies::Jarred(ref mut jar, _, _) = *self {
jar.remove(cookie)
}
}
Expand All @@ -252,7 +251,7 @@ impl<'a> Cookies<'a> {
/// ```
pub fn iter(&self) -> impl Iterator<Item=&Cookie<'static>> {
match *self {
Cookies::Jarred(ref jar, _) => jar.iter(),
Cookies::Jarred(ref jar, _, _) => jar.iter(),
Cookies::Empty(ref jar) => jar.iter()
}
}
Expand All @@ -262,12 +261,22 @@ impl<'a> Cookies<'a> {
#[doc(hidden)]
pub fn delta(&self) -> Delta<'_> {
match *self {
Cookies::Jarred(ref jar, _) => jar.delta(),
Cookies::Jarred(ref jar, _, _) => jar.delta(),
Cookies::Empty(ref jar) => jar.delta()
}
}
}

impl<'a> Drop for Cookies<'a> {
fn drop(&mut self) {
if let Cookies::Jarred(ref mut jar, _, ref mut on_drop) = *self {
let jar = std::mem::replace(jar, CookieJar::new());
let on_drop = std::mem::replace(on_drop, Box::new(|_| {}));
on_drop(jar);
}
}
}

#[cfg(feature = "private-cookies")]
impl Cookies<'_> {
/// Returns a reference to the `Cookie` inside this collection with the name
Expand All @@ -290,7 +299,7 @@ impl Cookies<'_> {
/// ```
pub fn get_private(&mut self, name: &str) -> Option<Cookie<'static>> {
match *self {
Cookies::Jarred(ref mut jar, key) => jar.private(key).get(name),
Cookies::Jarred(ref mut jar, key, _) => jar.private(key).get(name),
Cookies::Empty(_) => None
}
}
Expand Down Expand Up @@ -326,7 +335,7 @@ impl Cookies<'_> {
/// }
/// ```
pub fn add_private(&mut self, mut cookie: Cookie<'static>) {
if let Cookies::Jarred(ref mut jar, key) = *self {
if let Cookies::Jarred(ref mut jar, key, _) = *self {
Cookies::set_private_defaults(&mut cookie);
jar.private(key).add(cookie)
}
Expand All @@ -336,7 +345,7 @@ impl Cookies<'_> {
/// WARNING: This is unstable! Do not use this method outside of Rocket!
#[doc(hidden)]
pub fn add_original_private(&mut self, mut cookie: Cookie<'static>) {
if let Cookies::Jarred(ref mut jar, key) = *self {
if let Cookies::Jarred(ref mut jar, key, _) = *self {
Cookies::set_private_defaults(&mut cookie);
jar.private(key).add_original(cookie)
}
Expand Down Expand Up @@ -390,7 +399,7 @@ impl Cookies<'_> {
/// }
/// ```
pub fn remove_private(&mut self, mut cookie: Cookie<'static>) {
if let Cookies::Jarred(ref mut jar, key) = *self {
if let Cookies::Jarred(ref mut jar, key, _) = *self {
if cookie.path().is_none() {
cookie.set_path("/");
}
Expand All @@ -403,7 +412,7 @@ impl Cookies<'_> {
impl fmt::Debug for Cookies<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Cookies::Jarred(ref jar, _) => jar.fmt(f),
Cookies::Jarred(ref jar, _, _) => jar.fmt(f),
Cookies::Empty(ref jar) => jar.fmt(f)
}
}
Expand Down
6 changes: 3 additions & 3 deletions core/http/src/hyper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
//! These types will, with certainty, be removed with time, but they reside here
//! while necessary.

#[doc(hidden)] pub use hyper::{Body, Request, Response};
#[doc(hidden)] pub use hyper::{Body, Request, Response, Server};
#[doc(hidden)] pub use hyper::body::Payload as Payload;
#[doc(hidden)] pub use hyper::error::Error;
#[doc(hidden)] pub use hyper::server::Server;
#[doc(hidden)] pub use hyper::service::{MakeService, Service};

#[doc(hidden)] pub use hyper::Chunk;
#[doc(hidden)] pub use http::header::HeaderMap;
#[doc(hidden)] pub use http::header::HeaderName as HeaderName;
#[doc(hidden)] pub use http::header::HeaderValue as HeaderValue;
#[doc(hidden)] pub use http::method::Method;
#[doc(hidden)] pub use http::request::Parts;
#[doc(hidden)] pub use http::request::Parts as RequestParts;
#[doc(hidden)] pub use http::status::StatusCode;
#[doc(hidden)] pub use http::uri::Uri;

Expand Down
7 changes: 5 additions & 2 deletions core/http/src/tls.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
pub use hyper_sync_rustls::{util, WrappedStream, ServerSession, TlsServer};
pub use rustls::{Certificate, PrivateKey};
pub use tokio_rustls::TlsAcceptor;
pub use tokio_rustls::rustls;

pub use rustls::internal::pemfile;
pub use rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig};
4 changes: 2 additions & 2 deletions core/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ tls = ["rocket_http/tls"]
private-cookies = ["rocket_http/private-cookies"]

[dependencies]
futures = "0.1"
rocket_codegen = { version = "0.5.0-dev", path = "../codegen" }
rocket_http = { version = "0.5.0-dev", path = "../http" }
futures-preview = { version = "0.3.0-alpha.14", features = ["compat", "io-compat"] }
tokio = "0.1.16"
yansi = "0.5"
log = "0.4"
log = { version = "0.4", features = ["std"] }
toml = "0.4.7"
num_cpus = "1.0"
state = "0.4.1"
Expand Down
4 changes: 2 additions & 2 deletions core/lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
use yansi::{Paint, Color::{Red, Yellow, Blue}};

// Specifies the minimum nightly version needed to compile Rocket.
const MIN_DATE: &'static str = "2019-04-05";
const MIN_VERSION: &'static str = "1.35.0-nightly";
const MIN_DATE: &'static str = "2019-07-03";
const MIN_VERSION: &'static str = "1.37.0-nightly";

macro_rules! err {
($version:expr, $date:expr, $msg:expr) => (
Expand Down
15 changes: 10 additions & 5 deletions core/lib/src/catcher.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use futures::future::Future;

use crate::response;
use crate::handler::ErrorHandler;
use crate::codegen::StaticCatchInfo;
Expand Down Expand Up @@ -98,7 +100,7 @@ impl Catcher {
}

#[inline(always)]
pub(crate) fn handle<'r>(&self, req: &'r Request<'_>) -> response::Result<'r> {
pub(crate) fn handle<'r>(&self, req: &'r Request<'_>) -> impl Future<Output = response::Result<'r>> {
(self.handler)(req)
}

Expand Down Expand Up @@ -149,10 +151,12 @@ macro_rules! default_catchers {
let mut map = HashMap::new();

$(
fn $fn_name<'r>(req: &'r Request<'_>) -> response::Result<'r> {
status::Custom(Status::from_code($code).unwrap(),
content::Html(error_page_template!($code, $name, $description))
).respond_to(req)
fn $fn_name<'r>(req: &'r Request<'_>) -> std::pin::Pin<Box<dyn std::future::Future<Output = response::Result<'r>> + Send + 'r>> {
(async move {
status::Custom(Status::from_code($code).unwrap(),
content::Html(error_page_template!($code, $name, $description))
).respond_to(req)
}).boxed()
}

map.insert($code, Catcher::new_default($code, $fn_name));
Expand All @@ -164,6 +168,7 @@ macro_rules! default_catchers {

pub mod defaults {
use super::Catcher;
use futures::future::FutureExt;

use std::collections::HashMap;

Expand Down
4 changes: 3 additions & 1 deletion core/lib/src/codegen.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use futures::future::Future;

use crate::{Request, Data};
use crate::handler::{Outcome, ErrorHandler};
use crate::http::{Method, MediaType};

/// Type of a static handler, which users annotate with Rocket's attribute.
pub type StaticHandler = for<'r> fn(&'r Request<'_>, Data) -> Outcome<'r>;
pub type StaticHandler = for<'r> fn(&'r Request<'_>, Data) -> std::pin::Pin<Box<dyn Future<Output = Outcome<'r>> + Send + 'r>>;

/// Information generated by the `route` attribute during codegen.
pub struct StaticRouteInfo {
Expand Down
Loading

0 comments on commit 175c6c0

Please sign in to comment.