Add '#[rocket::launch]' attribute.

The attribute is applied everywhere it can be across the codebase and is
the newly preferred method for launching an application. This commit
also makes '#[rocket::main]` stricter by warning when it is applied to
functions other than 'main'.
This commit is contained in:
Sergio Benitez 2020-06-16 05:01:26 -07:00
parent c7c371910b
commit 12308b403f
58 changed files with 604 additions and 406 deletions

View File

@ -10,8 +10,6 @@ Rocket is a web framework for Rust (nightly) with a focus on ease-of-use,
expressibility, and speed. Here's an example of a complete Rocket application: expressibility, and speed. Here's an example of a complete Rocket application:
```rust ```rust
#![feature(proc_macro_hygiene)]
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
#[get("/<name>/<age>")] #[get("/<name>/<age>")]
@ -19,8 +17,9 @@ fn hello(name: String, age: u8) -> String {
format!("Hello, {} year old named {}!", age, name) format!("Hello, {} year old named {}!", age, name)
} }
fn main() { #[launch]
rocket::ignite().mount("/hello", routes![hello]).launch(); fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/hello", routes![hello])
} }
``` ```

View File

@ -62,12 +62,9 @@
//! #[database("sqlite_logs")] //! #[database("sqlite_logs")]
//! struct LogsDbConn(diesel::SqliteConnection); //! struct LogsDbConn(diesel::SqliteConnection);
//! //!
//! #[rocket::main] //! #[rocket::launch]
//! async fn main() { //! fn rocket() -> rocket::Rocket {
//! rocket::ignite() //! rocket::ignite().attach(LogsDbConn::fairing())
//! .attach(LogsDbConn::fairing())
//! .launch()
//! .await;
//! } //! }
//! # } fn main() {} //! # } fn main() {}
//! ``` //! ```
@ -152,8 +149,8 @@
//! use std::collections::HashMap; //! use std::collections::HashMap;
//! use rocket::config::{Config, Environment, Value}; //! use rocket::config::{Config, Environment, Value};
//! //!
//! #[rocket::main] //! #[rocket::launch]
//! async fn main() { //! fn rocket() -> rocket::Rocket {
//! let mut database_config = HashMap::new(); //! let mut database_config = HashMap::new();
//! let mut databases = HashMap::new(); //! let mut databases = HashMap::new();
//! //!
@ -167,7 +164,7 @@
//! .finalize() //! .finalize()
//! .unwrap(); //! .unwrap();
//! //!
//! rocket::custom(config).launch().await; //! rocket::custom(config)
//! } //! }
//! # } fn main() {} //! # } fn main() {}
//! ``` //! ```
@ -266,8 +263,8 @@
//! #[database("my_db")] //! #[database("my_db")]
//! struct MyDatabase(diesel::SqliteConnection); //! struct MyDatabase(diesel::SqliteConnection);
//! //!
//! #[rocket::main] //! #[rocket::launch]
//! async fn main() { //! fn rocket() -> rocket::Rocket {
//! # let mut db_config = HashMap::new(); //! # let mut db_config = HashMap::new();
//! # let mut databases = HashMap::new(); //! # let mut databases = HashMap::new();
//! # //! #
@ -280,10 +277,7 @@
//! # .finalize() //! # .finalize()
//! # .unwrap(); //! # .unwrap();
//! # //! #
//! rocket::custom(config) //! rocket::custom(config).attach(MyDatabase::fairing())
//! .attach(MyDatabase::fairing())
//! .launch()
//! .await;
//! } //! }
//! # } fn main() {} //! # } fn main() {}
//! ``` //! ```

View File

@ -130,19 +130,14 @@ impl std::ops::BitOr for Options {
/// `/public` path, allowing `index.html` files to be used to respond to /// `/public` path, allowing `index.html` files to be used to respond to
/// requests for a directory (the default), you might write the following: /// requests for a directory (the default), you might write the following:
/// ///
/// ```rust /// ```rust,no_run
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::serve::StaticFiles; /// use rocket_contrib::serve::StaticFiles;
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { /// rocket::ignite().mount("/public", StaticFiles::from("/static"))
/// rocket::ignite()
/// .mount("/public", StaticFiles::from("/static"))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
/// ///
@ -158,19 +153,15 @@ impl std::ops::BitOr for Options {
/// For example, to serve files in the `static` subdirectory of your crate at /// For example, to serve files in the `static` subdirectory of your crate at
/// `/`, you might write: /// `/`, you might write:
/// ///
/// ```rust /// ```rust,no_run
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::serve::StaticFiles; /// use rocket_contrib::serve::StaticFiles;
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false {
/// rocket::ignite() /// rocket::ignite()
/// .mount("/", StaticFiles::from(concat!(env!("CARGO_MANIFEST_DIR"), "/static"))) /// .mount("/", StaticFiles::from(concat!(env!("CARGO_MANIFEST_DIR"), "/static")))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
#[derive(Clone)] #[derive(Clone)]
@ -195,37 +186,27 @@ impl StaticFiles {
/// Serve the static files in the `/www/public` local directory on path /// Serve the static files in the `/www/public` local directory on path
/// `/static`. /// `/static`.
/// ///
/// ```rust /// ```rust,no_run
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::serve::StaticFiles; /// use rocket_contrib::serve::StaticFiles;
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { /// rocket::ignite().mount("/static", StaticFiles::from("/www/public"))
/// rocket::ignite()
/// .mount("/static", StaticFiles::from("/www/public"))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
/// ///
/// Exactly as before, but set the rank for generated routes to `30`. /// Exactly as before, but set the rank for generated routes to `30`.
/// ///
/// ```rust /// ```rust,no_run
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::serve::StaticFiles; /// use rocket_contrib::serve::StaticFiles;
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { /// rocket::ignite().mount("/static", StaticFiles::from("/www/public").rank(30))
/// rocket::ignite()
/// .mount("/static", StaticFiles::from("/www/public").rank(30))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
pub fn from<P: AsRef<Path>>(path: P) -> Self { pub fn from<P: AsRef<Path>>(path: P) -> Self {
@ -243,21 +224,17 @@ impl StaticFiles {
/// the same files on `/pub` with a route rank of -1 while also serving /// the same files on `/pub` with a route rank of -1 while also serving
/// index files and dot files. /// index files and dot files.
/// ///
/// ```rust /// ```rust,no_run
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::serve::{StaticFiles, Options}; /// use rocket_contrib::serve::{StaticFiles, Options};
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false {
/// let options = Options::Index | Options::DotFiles; /// let options = Options::Index | Options::DotFiles;
/// rocket::ignite() /// rocket::ignite()
/// .mount("/static", StaticFiles::from("/www/public")) /// .mount("/static", StaticFiles::from("/www/public"))
/// .mount("/pub", StaticFiles::new("/www/public", options).rank(-1)) /// .mount("/pub", StaticFiles::new("/www/public", options).rank(-1))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
pub fn new<P: AsRef<Path>>(path: P, options: Options) -> Self { pub fn new<P: AsRef<Path>>(path: P, options: Options) -> Self {

View File

@ -1,83 +1,126 @@
use proc_macro::{TokenStream, Span}; use proc_macro::{TokenStream, Span};
use devise::{syn, Result}; use devise::{syn, Spanned, Result};
use crate::proc_macro2::TokenStream as TokenStream2; use crate::proc_macro2::TokenStream as TokenStream2;
use crate::syn_ext::syn_to_diag; use crate::syn_ext::syn_to_diag;
#[derive(Copy, Clone)] trait EntryAttr {
enum Kind { /// Whether the attribute requires the attributed function to be `async`.
Main, const REQUIRES_ASYNC: bool;
Test,
/// Return a new or rewritten function, using block as the main execution.
fn function(f: &syn::ItemFn, body: &syn::Block) -> Result<TokenStream2>;
} }
impl Kind { struct Main;
// The name of the attribute, used for error messages
fn attr_name(&self) -> &'static str {
match self {
Kind::Main => "main",
Kind::Test => "async_test",
}
}
// Attributes to decorate the generated function with impl EntryAttr for Main {
fn attrs(&self) -> Option<TokenStream2> { const REQUIRES_ASYNC: bool = true;
match self {
Kind::Main => None,
Kind::Test => Some(quote!{ #[test] }),
}
}
// The path to the function to call fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream2> {
fn fn_path(&self) -> TokenStream2 { let (attrs, vis, mut sig) = (&f.attrs, &f.vis, f.sig.clone());
match self { if sig.ident != "main" {
Kind::Main => quote! { rocket :: async_main }, Span::call_site()
Kind::Test => quote! { rocket :: async_test }, .warning("attribute is typically applied to `main` function")
.span_note(sig.span(), "this function is not `main`")
.emit();
} }
sig.asyncness = None;
Ok(quote_spanned!(block.span().into() => #(#attrs)* #vis #sig {
::rocket::async_main(async move #block)
}))
} }
} }
fn parse_input(input: TokenStream, attr_name: &str) -> Result<syn::ItemFn> { struct Test;
let function: syn::ItemFn = syn::parse(input).map_err(syn_to_diag)
.map_err(|diag| diag.help(format!("`#[{}]` can only be applied to async functions", attr_name)))?;
if function.sig.asyncness.is_none() { impl EntryAttr for Test {
return Err(Span::call_site().error(format!("`#[{}]` can only be applied to async functions", attr_name))) const REQUIRES_ASYNC: bool = true;
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream2> {
let (attrs, vis, mut sig) = (&f.attrs, &f.vis, f.sig.clone());
sig.asyncness = None;
Ok(quote_spanned!(block.span().into() => #(#attrs)* #[test] #vis #sig {
::rocket::async_test(async move #block)
}))
}
}
struct Launch;
impl EntryAttr for Launch {
const REQUIRES_ASYNC: bool = false;
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream2> {
if f.sig.ident == "main" {
return Err(Span::call_site()
.error("attribute cannot be applied to `main` function")
.note("this attribute generates a `main` function")
.span_note(f.sig.span(), "this function cannot be `main`"));
}
let ty = match &f.sig.output {
syn::ReturnType::Type(_, ty) => ty,
_ => return Err(Span::call_site()
.error("attribute can only be applied to functions that return a value")
.span_note(f.sig.span(), "this function must return a value"))
};
let rocket = quote_spanned!(ty.span().into() => {
let ___rocket: #ty = #block;
let ___rocket: ::rocket::Rocket = ___rocket;
___rocket
});
let (vis, mut sig) = (&f.vis, f.sig.clone());
sig.ident = syn::Ident::new("main", sig.ident.span());
sig.output = syn::ReturnType::Default;
sig.asyncness = None;
Ok(quote_spanned!(block.span().into() =>
#[allow(dead_code)] #f
#vis #sig {
::rocket::async_main(async move { let _ = #rocket.launch().await; })
}
))
}
}
fn parse_input<A: EntryAttr>(input: TokenStream) -> Result<syn::ItemFn> {
let function: syn::ItemFn = syn::parse(input)
.map_err(syn_to_diag)
.map_err(|d| d.help("attribute can only be applied to functions"))?;
if A::REQUIRES_ASYNC && function.sig.asyncness.is_none() {
return Err(Span::call_site()
.error("attribute can only be applied to `async` functions")
.span_note(function.sig.span(), "this function must be `async`"));
} }
if !function.sig.inputs.is_empty() { if !function.sig.inputs.is_empty() {
return Err(Span::call_site().error(format!("`#[{}]` can only be applied to functions with no parameters", attr_name))); return Err(Span::call_site()
.error("attribute can only be applied to functions without arguments")
.span_note(function.sig.span(), "this function must take no arguments"));
} }
Ok(function) Ok(function)
} }
fn _async_entry(_args: TokenStream, input: TokenStream, kind: Kind) -> Result<TokenStream> { fn _async_entry<A: EntryAttr>(_args: TokenStream, input: TokenStream) -> Result<TokenStream> {
let function = parse_input(input, kind.attr_name())?; let function = parse_input::<A>(input)?;
A::function(&function, &function.block).map(|t| t.into())
let attrs = &function.attrs;
let vis = &function.vis;
let name = &function.sig.ident;
let output = &function.sig.output;
let body = &function.block;
let test_attr = kind.attrs();
let fn_path = kind.fn_path();
Ok(quote! {
#test_attr
#(#attrs)*
#vis fn #name() #output {
#fn_path (async move {
#body
})
}
}.into())
} }
pub fn async_test_attribute(args: TokenStream, input: TokenStream) -> TokenStream { pub fn async_test_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
_async_entry(args, input, Kind::Test).unwrap_or_else(|d| { d.emit(); TokenStream::new() }) _async_entry::<Test>(args, input).unwrap_or_else(|d| { d.emit(); TokenStream::new() })
} }
pub fn main_attribute(args: TokenStream, input: TokenStream) -> TokenStream { pub fn main_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
_async_entry(args, input, Kind::Main).unwrap_or_else(|d| { d.emit(); TokenStream::new() }) _async_entry::<Main>(args, input).unwrap_or_else(|d| { d.emit(); quote!(fn main() {}).into() })
}
pub fn launch_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
_async_entry::<Launch>(args, input).unwrap_or_else(|d| { d.emit(); quote!(fn main() {}).into() })
} }

View File

@ -405,16 +405,24 @@ pub fn catch(args: TokenStream, input: TokenStream) -> TokenStream {
emit!(attribute::catch::catch_attribute(args, input)) emit!(attribute::catch::catch_attribute(args, input))
} }
/// FIXME: Document.
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn async_test(args: TokenStream, input: TokenStream) -> TokenStream { pub fn async_test(args: TokenStream, input: TokenStream) -> TokenStream {
emit!(attribute::async_entry::async_test_attribute(args, input)) emit!(attribute::async_entry::async_test_attribute(args, input))
} }
/// FIXME: Document.
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn main(args: TokenStream, input: TokenStream) -> TokenStream { pub fn main(args: TokenStream, input: TokenStream) -> TokenStream {
emit!(attribute::async_entry::main_attribute(args, input)) emit!(attribute::async_entry::main_attribute(args, input))
} }
/// FIXME: Document.
#[proc_macro_attribute]
pub fn launch(args: TokenStream, input: TokenStream) -> TokenStream {
emit!(attribute::async_entry::launch_attribute(args, input))
}
/// Derive for the [`FromFormValue`] trait. /// Derive for the [`FromFormValue`] trait.
/// ///
/// The [`FromFormValue`] derive can be applied to enums with nullary /// The [`FromFormValue`] derive can be applied to enums with nullary

View File

@ -0,0 +1,76 @@
#![allow(dead_code, unused_variables)]
mod a {
// async launch that is async.
#[rocket::launch]
async fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().launch().await;
rocket::ignite()
}
async fn use_it() {
let rocket: rocket::Rocket = rocket().await;
}
}
mod b {
// async launch that isn't async.
#[rocket::launch]
async fn main2() -> rocket::Rocket {
rocket::ignite()
}
async fn use_it() {
let rocket: rocket::Rocket = main2().await;
}
}
mod c {
// non-async launch.
#[rocket::launch]
fn rocket() -> rocket::Rocket {
rocket::ignite()
}
fn use_it() {
let rocket: rocket::Rocket = rocket();
}
}
mod d {
// main with async, is async.
#[rocket::main]
async fn main() {
let _ = rocket::ignite().launch().await;
}
}
mod e {
// main with async, isn't async.
#[rocket::main]
async fn main() { }
}
mod f {
// main with async, is async, with termination return.
#[rocket::main]
async fn main() -> Result<(), String> {
let result = rocket::ignite().launch().await;
result.map_err(|e| e.to_string())
}
}
mod g {
// main with async, isn't async, with termination return.
#[rocket::main]
async fn main() -> Result<(), String> {
Ok(())
}
}
// main with async, is async, with termination return.
#[rocket::main]
async fn main() -> Result<(), String> {
let result = rocket::ignite().launch().await;
result.map_err(|e| e.to_string())
}

View File

@ -0,0 +1,109 @@
#![allow(dead_code)]
// rocket::main
mod main_a {
#[rocket::main]
fn foo() { }
//~^^ ERROR `async`
}
mod main_b {
#[rocket::main]
async fn foo() { }
//~^^ WARNING `main`
}
mod main_d {
#[rocket::main]
fn main() {
//~^^ ERROR `async`
let _ = rocket::ignite().launch().await;
}
}
mod main_f {
#[rocket::main]
async fn main() {
//~^ ERROR mismatched types
rocket::ignite()
}
}
// rocket::launch
mod launch_a {
#[rocket::launch]
async fn rocket() -> String {
//~^ ERROR mismatched types
let _ = rocket::ignite().launch().await;
rocket::ignite()
//~^ ERROR mismatched types
}
}
mod launch_b {
#[rocket::launch]
async fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().launch().await;
"hi".to_string()
//~^ ERROR mismatched types
}
}
mod launch_c {
#[rocket::launch]
fn main() -> rocket::Rocket {
//~^^ ERROR `main`
rocket::ignite()
}
}
mod launch_d {
#[rocket::launch]
async fn rocket() {
//~^^ ERROR functions that return
let _ = rocket::ignite().launch().await;
rocket::ignite()
}
}
mod launch_e {
#[rocket::launch]
fn rocket() {
//~^^ ERROR functions that return
rocket::ignite()
}
}
mod launch_f {
#[rocket::launch]
fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().launch().await;
//~^ ERROR only allowed inside `async`
rocket::ignite()
}
}
mod launch_g {
#[rocket::launch]
fn main() -> &'static str {
//~^^ ERROR `main`
let _ = rocket::ignite().launch().await;
"hi"
}
}
mod launch_h {
#[rocket::launch]
async fn main() -> rocket::Rocket {
//~^^ ERROR `main`
rocket::ignite()
}
}
#[rocket::main]
async fn main() -> rocket::Rocket {
//~^ ERROR invalid return type
rocket::ignite()
}

View File

@ -0,0 +1,162 @@
error: attribute can only be applied to `async` functions
--> $DIR/async-entry.rs:6:5
|
6 | #[rocket::main]
| ^^^^^^^^^^^^^^^
|
note: this function must be `async`
--> $DIR/async-entry.rs:7:5
|
7 | fn foo() { }
| ^^^^^^^^
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: attribute is typically applied to `main` function
--> $DIR/async-entry.rs:12:5
|
12 | #[rocket::main]
| ^^^^^^^^^^^^^^^
|
note: this function is not `main`
--> $DIR/async-entry.rs:13:5
|
13 | async fn foo() { }
| ^^^^^^^^^^^^^^
= note: this warning originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: attribute can only be applied to `async` functions
--> $DIR/async-entry.rs:18:5
|
18 | #[rocket::main]
| ^^^^^^^^^^^^^^^
|
note: this function must be `async`
--> $DIR/async-entry.rs:19:5
|
19 | fn main() {
| ^^^^^^^^^
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: attribute cannot be applied to `main` function
--> $DIR/async-entry.rs:55:5
|
55 | #[rocket::launch]
| ^^^^^^^^^^^^^^^^^
|
= note: this attribute generates a `main` function
note: this function cannot be `main`
--> $DIR/async-entry.rs:56:5
|
56 | fn main() -> rocket::Rocket {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: attribute can only be applied to functions that return a value
--> $DIR/async-entry.rs:63:5
|
63 | #[rocket::launch]
| ^^^^^^^^^^^^^^^^^
|
note: this function must return a value
--> $DIR/async-entry.rs:64:5
|
64 | async fn rocket() {
| ^^^^^^^^^^^^^^^^^
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: attribute can only be applied to functions that return a value
--> $DIR/async-entry.rs:72:5
|
72 | #[rocket::launch]
| ^^^^^^^^^^^^^^^^^
|
note: this function must return a value
--> $DIR/async-entry.rs:73:5
|
73 | fn rocket() {
| ^^^^^^^^^^^
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: attribute cannot be applied to `main` function
--> $DIR/async-entry.rs:89:5
|
89 | #[rocket::launch]
| ^^^^^^^^^^^^^^^^^
|
= note: this attribute generates a `main` function
note: this function cannot be `main`
--> $DIR/async-entry.rs:90:5
|
90 | fn main() -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: attribute cannot be applied to `main` function
--> $DIR/async-entry.rs:98:5
|
98 | #[rocket::launch]
| ^^^^^^^^^^^^^^^^^
|
= note: this attribute generates a `main` function
note: this function cannot be `main`
--> $DIR/async-entry.rs:99:5
|
99 | async fn main() -> rocket::Rocket {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/async-entry.rs:82:17
|
81 | fn rocket() -> rocket::Rocket {
| ------ this is not `async`
82 | let _ = rocket::ignite().launch().await;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
error[E0308]: mismatched types
--> $DIR/async-entry.rs:40:9
|
40 | rocket::ignite()
| ^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found struct `rocket::rocket::Rocket`
error[E0308]: mismatched types
--> $DIR/async-entry.rs:49:9
|
49 | "hi".to_string()
| ^^^^^^^^^^^^^^^^ expected struct `rocket::rocket::Rocket`, found struct `std::string::String`
error[E0308]: mismatched types
--> $DIR/async-entry.rs:27:21
|
27 | async fn main() {
| ^ expected `()` because of default return type
| _____________________|
| |
28 | | //~^ ERROR mismatched types
29 | | rocket::ignite()
30 | | }
| | ^- help: try adding a semicolon: `;`
| |_____|
| expected `()`, found struct `rocket::rocket::Rocket`
error[E0308]: mismatched types
--> $DIR/async-entry.rs:37:26
|
37 | async fn rocket() -> String {
| ^^^^^^
| |
| expected struct `rocket::rocket::Rocket`, found struct `std::string::String`
| expected due to this
error[E0277]: `main` has invalid return type `rocket::rocket::Rocket`
--> $DIR/async-entry.rs:106:20
|
106 | async fn main() -> rocket::Rocket {
| ^^^^^^^^^^^^^^ `main` can only return types that implement `std::process::Termination`
|
= help: consider using `()`, or a `Result`
error: aborting due to 13 previous errors; 1 warning emitted
Some errors have detailed explanations: E0277, E0308, E0728.
For more information about an error, try `rustc --explain E0277`.

View File

@ -35,7 +35,7 @@ use yansi::Color::*;
/// Catchers should rarely be used directly. Instead, they are typically /// Catchers should rarely be used directly. Instead, they are typically
/// declared using the `catch` decorator, as follows: /// declared using the `catch` decorator, as follows:
/// ///
/// ```rust /// ```rust,no_run
/// #![feature(proc_macro_hygiene)] /// #![feature(proc_macro_hygiene)]
/// ///
/// #[macro_use] extern crate rocket; /// #[macro_use] extern crate rocket;
@ -52,11 +52,9 @@ use yansi::Color::*;
/// format!("I couldn't find '{}'. Try something else?", req.uri()) /// format!("I couldn't find '{}'. Try something else?", req.uri())
/// } /// }
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { // We don't actually want to launch the server in an example. /// rocket::ignite().register(catchers![internal_error, not_found])
/// rocket::ignite().register(catchers![internal_error, not_found]).launch().await;
/// # }
/// } /// }
/// ``` /// ```
/// ///

View File

@ -41,7 +41,7 @@ pub type HandlerFuture<'r> = BoxFuture<'r, Outcome<'r>>;
/// ///
/// Such a handler might be written and used as follows: /// Such a handler might be written and used as follows:
/// ///
/// ```rust /// ```rust,no_run
/// # #[derive(Copy, Clone)] enum Kind { Simple, Intermediate, Complex, } /// # #[derive(Copy, Clone)] enum Kind { Simple, Intermediate, Complex, }
/// use rocket::{Request, Data, Route, http::Method}; /// use rocket::{Request, Data, Route, http::Method};
/// use rocket::handler::{self, Handler, Outcome, HandlerFuture}; /// use rocket::handler::{self, Handler, Outcome, HandlerFuture};
@ -65,14 +65,9 @@ pub type HandlerFuture<'r> = BoxFuture<'r, Outcome<'r>>;
/// } /// }
/// } /// }
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { /// rocket::ignite().mount("/", CustomHandler(Kind::Simple))
/// rocket::ignite()
/// .mount("/", CustomHandler(Kind::Simple))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
/// ///
@ -92,7 +87,7 @@ pub type HandlerFuture<'r> = BoxFuture<'r, Outcome<'r>>;
/// The previous example could have been implemented using a combination of /// The previous example could have been implemented using a combination of
/// managed state and a static route, as follows: /// managed state and a static route, as follows:
/// ///
/// ```rust /// ```rust,no_run
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # /// #
@ -114,15 +109,11 @@ pub type HandlerFuture<'r> = BoxFuture<'r, Outcome<'r>>;
/// } /// }
/// } /// }
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false {
/// rocket::ignite() /// rocket::ignite()
/// .mount("/", routes![custom_handler]) /// .mount("/", routes![custom_handler])
/// .manage(Kind::Simple) /// .manage(Kind::Simple)
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
/// ///

View File

@ -57,7 +57,7 @@
//! See the [guide](https://rocket.rs/v0.5/guide) for more information on how to //! See the [guide](https://rocket.rs/v0.5/guide) for more information on how to
//! write Rocket applications. Here's a simple example to get you started: //! write Rocket applications. Here's a simple example to get you started:
//! //!
//! ```rust //! ```rust,no_run
//! #![feature(proc_macro_hygiene)] //! #![feature(proc_macro_hygiene)]
//! //!
//! #[macro_use] extern crate rocket; //! #[macro_use] extern crate rocket;
@ -67,11 +67,9 @@
//! "Hello, world!" //! "Hello, world!"
//! } //! }
//! //!
//! #[rocket::main] //! #[rocket::launch]
//! async fn main() { //! fn rocket() -> rocket::Rocket {
//! # if false { // We don't actually want to launch the server in an example. //! rocket::ignite().mount("/", routes![hello])
//! rocket::ignite().mount("/", routes![hello]).launch().await;
//! # }
//! } //! }
//! ``` //! ```
//! //!

View File

@ -21,7 +21,7 @@ use crate::http::Status;
/// like to initialize at start-up and later access it in several handlers. The /// like to initialize at start-up and later access it in several handlers. The
/// following example does just this: /// following example does just this:
/// ///
/// ```rust /// ```rust,no_run
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// use rocket::State; /// use rocket::State;
@ -42,19 +42,11 @@ use crate::http::Status;
/// state.inner().user_val.as_str() /// state.inner().user_val.as_str()
/// } /// }
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// let config = MyConfig {
/// user_val: "user input".to_string()
/// };
///
/// # if false { // We don't actually want to launch the server in an example.
/// rocket::ignite() /// rocket::ignite()
/// .mount("/", routes![index, raw_config_value]) /// .mount("/", routes![index, raw_config_value])
/// .manage(config) /// .manage(MyConfig { user_val: "user input".to_string() })
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
/// ///

View File

@ -44,8 +44,8 @@ const FLASH_COOKIE_DELIM: char = ':';
/// ///
/// # Example /// # Example
/// ///
/// The following complete Rocket application illustrates the use of a `Flash` /// The following routes illustrate the use of a `Flash` message on both the
/// message on both the request and response sides. /// request and response sides.
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
@ -68,13 +68,6 @@ const FLASH_COOKIE_DELIM: char = ':';
/// flash.map(|msg| format!("{}: {}", msg.name(), msg.msg())) /// flash.map(|msg| format!("{}: {}", msg.name(), msg.msg()))
/// .unwrap_or_else(|| "Welcome!".to_string()) /// .unwrap_or_else(|| "Welcome!".to_string())
/// } /// }
///
/// #[rocket::main]
/// async fn main() {
/// # if false { // We don't actually want to launch the server in an example.
/// rocket::ignite().mount("/", routes![login, index]).launch().await;
/// # }
/// }
/// ``` /// ```
/// ///
/// On the response side (in `login`), a `Flash` error message is set if some /// On the response side (in `login`), a `Flash` error message is set if some

View File

@ -647,7 +647,7 @@ impl Rocket {
/// generation facilities. Requests to the `/hello/world` URI will be /// generation facilities. Requests to the `/hello/world` URI will be
/// dispatched to the `hi` route. /// dispatched to the `hi` route.
/// ///
/// ```rust /// ```rust,no_run
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # /// #
@ -656,12 +656,9 @@ impl Rocket {
/// "Hello!" /// "Hello!"
/// } /// }
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { // We don't actually want to launch the server in an example.
/// rocket::ignite().mount("/hello", routes![hi]) /// rocket::ignite().mount("/hello", routes![hi])
/// # .launch().await;
/// # }
/// } /// }
/// ``` /// ```
/// ///
@ -704,7 +701,7 @@ impl Rocket {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust,no_run
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// use rocket::Request; /// use rocket::Request;
@ -719,13 +716,9 @@ impl Rocket {
/// format!("I couldn't find '{}'. Try something else?", req.uri()) /// format!("I couldn't find '{}'. Try something else?", req.uri())
/// } /// }
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { // We don't actually want to launch the server in an example. /// rocket::ignite().register(catchers![internal_error, not_found])
/// rocket::ignite()
/// .register(catchers![internal_error, not_found])
/// # .launch().await;
/// # }
/// } /// }
/// ``` /// ```
#[inline] #[inline]
@ -750,7 +743,7 @@ impl Rocket {
/// ///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust,no_run
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// use rocket::State; /// use rocket::State;
@ -762,15 +755,11 @@ impl Rocket {
/// format!("The stateful value is: {}", state.0) /// format!("The stateful value is: {}", state.0)
/// } /// }
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { // We don't actually want to launch the server in an example.
/// rocket::ignite() /// rocket::ignite()
/// .mount("/", routes![index]) /// .mount("/", routes![index])
/// .manage(MyValue(10)) /// .manage(MyValue(10))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
#[inline] #[inline]
@ -793,22 +782,18 @@ impl Rocket {
/// ///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust,no_run
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// use rocket::Rocket; /// use rocket::Rocket;
/// use rocket::fairing::AdHoc; /// use rocket::fairing::AdHoc;
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { // We don't actually want to launch the server in an example.
/// rocket::ignite() /// rocket::ignite()
/// .attach(AdHoc::on_launch("Launch Message", |_| { /// .attach(AdHoc::on_launch("Launch Message", |_| {
/// println!("Rocket is launching!"); /// println!("Rocket is launching!");
/// })) /// }))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
#[inline] #[inline]
@ -1126,22 +1111,18 @@ impl Manifest {
/// ///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust,no_run
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// use rocket::Rocket; /// use rocket::Rocket;
/// use rocket::fairing::AdHoc; /// use rocket::fairing::AdHoc;
/// ///
/// #[rocket::main] /// #[rocket::launch]
/// async fn main() { /// fn rocket() -> rocket::Rocket {
/// # if false { // We don't actually want to launch the server in an example.
/// rocket::ignite() /// rocket::ignite()
/// .attach(AdHoc::on_launch("Config Printer", |manifest| { /// .attach(AdHoc::on_launch("Config Printer", |manifest| {
/// println!("Rocket launch config: {:?}", manifest.config()); /// println!("Rocket launch config: {:?}", manifest.config());
/// })) /// }))
/// .launch()
/// .await;
/// # }
/// } /// }
/// ``` /// ```
#[inline(always)] #[inline(always)]

View File

@ -12,7 +12,7 @@ use tokio::sync::mpsc;
/// ///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust,no_run
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # /// #
@ -26,13 +26,13 @@ use tokio::sync::mpsc;
/// ///
/// #[rocket::main] /// #[rocket::main]
/// async fn main() { /// async fn main() {
/// # if false { /// let result = rocket::ignite()
/// rocket::ignite()
/// .mount("/", routes![shutdown]) /// .mount("/", routes![shutdown])
/// .launch() /// .launch()
/// .await /// .await;
/// .expect("server failed unexpectedly"); ///
/// # } /// // If the server shut down (by visting `/shutdown`), `result` is `Ok`.
/// result.expect("server failed unexpectedly");
/// } /// }
/// ``` /// ```
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -1,5 +1,3 @@
// This example's illustration is the Rocket.toml file. // This example's illustration is the Rocket.toml file.
#[rocket::main] #[rocket::launch]
async fn main() { fn rocket() -> rocket::Rocket { rocket::ignite() }
let _ = rocket::ignite().launch().await;
}

View File

@ -63,10 +63,9 @@ fn not_found(request: &Request<'_>) -> Html<String> {
Html(html) Html(html)
} }
#[rocket::main] #[rocket::launch]
async fn main() { fn rocket() -> rocket::Rocket {
let _ = rocket::ignite() rocket::ignite()
.mount("/hello", routes![get_hello, post_hello]) .mount("/hello", routes![get_hello, post_hello])
.register(catchers![not_found]) .register(catchers![not_found])
.launch().await;
} }

View File

@ -5,11 +5,7 @@ use rocket::local::Client;
async fn test<H>(method: Method, uri: &str, header: H, status: Status, body: String) async fn test<H>(method: Method, uri: &str, header: H, status: Status, body: String)
where H: Into<Header<'static>> where H: Into<Header<'static>>
{ {
let rocket = rocket::ignite() let client = Client::new(super::rocket()).await.unwrap();
.mount("/hello", routes![super::get_hello, super::post_hello])
.register(catchers![super::not_found]);
let client = Client::new(rocket).await.unwrap();
let mut response = client.req(method, uri).header(header).dispatch().await; let mut response = client.req(method, uri).header(header).dispatch().await;
assert_eq!(response.status(), status); assert_eq!(response.status(), status);
assert_eq!(response.body_string().await, Some(body)); assert_eq!(response.body_string().await, Some(body));

View File

@ -34,11 +34,7 @@ fn index(cookies: Cookies<'_>) -> Template {
Template::render("index", &context) Template::render("index", &context)
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![submit, index]).attach(Template::fairing()) rocket::ignite().mount("/", routes![submit, index]).attach(Template::fairing())
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -63,6 +63,7 @@ fn token(token: State<'_, Token>) -> String {
format!("{}", token.0) format!("{}", token.0)
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![hello, token]) .mount("/", routes![hello, token])
@ -93,8 +94,3 @@ fn rocket() -> rocket::Rocket {
}) })
})) }))
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -41,11 +41,7 @@ fn index() -> Option<NamedFile> {
NamedFile::open("static/index.html").ok() NamedFile::open("static/index.html").ok()
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![index, sink]) rocket::ignite().mount("/", routes![index, sink])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -76,12 +76,8 @@ fn user_page(username: &RawStr) -> String {
format!("This is {}'s page.", username) format!("This is {}'s page.", username)
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![files::index, files::files, user_page, login]) .mount("/", routes![files::index, files::files, user_page, login])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -68,6 +68,7 @@ fn wow_helper(
Ok(()) Ok(())
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![index, hello, about]) .mount("/", routes![index, hello, about])
@ -76,8 +77,3 @@ fn rocket() -> rocket::Rocket {
engines.handlebars.register_helper("wow", Box::new(wow_helper)); engines.handlebars.register_helper("wow", Box::new(wow_helper));
})) }))
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -1,15 +1,11 @@
#![feature(proc_macro_hygiene)]
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
use rocket::{get, routes}; #[rocket::get("/")]
#[get("/")]
fn hello() -> &'static str { fn hello() -> &'static str {
"Hello, Rust 2018!" "Hello, Rust 2018!"
} }
#[rocket::main] #[rocket::launch]
async fn main() { fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().mount("/", routes![hello]).launch().await; rocket::ignite().mount("/", rocket::routes![hello])
} }

View File

@ -1,9 +1,8 @@
use rocket::{self, routes, local::Client}; use rocket::{self, local::Client};
#[rocket::async_test] #[rocket::async_test]
async fn hello_world() { async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]); let client = Client::new(super::rocket()).await.unwrap();
let client = Client::new(rocket).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, Rust 2018!".into())); assert_eq!(response.body_string().await, Some("Hello, Rust 2018!".into()));
} }

View File

@ -14,7 +14,7 @@ fn hi(name: String) -> String {
name name
} }
#[rocket::main] #[rocket::launch]
async fn main() { fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().mount("/", routes![hello, hi]).launch().await; rocket::ignite().mount("/", routes![hello, hi])
} }

View File

@ -1,17 +1,13 @@
use rocket::local::Client; use rocket::local::Client;
use rocket::http::Status; use rocket::http::Status;
async fn client() -> Client {
Client::new(rocket::ignite().mount("/", routes![super::hello, super::hi])).await.unwrap()
}
async fn test(uri: String, expected: String) { async fn test(uri: String, expected: String) {
let client = client().await; let client = Client::new(super::rocket()).await.unwrap();
assert_eq!(client.get(&uri).dispatch().await.body_string().await, Some(expected)); assert_eq!(client.get(&uri).dispatch().await.body_string().await, Some(expected));
} }
async fn test_404(uri: &'static str) { async fn test_404(uri: &'static str) {
let client = client().await; let client = Client::new(super::rocket()).await.unwrap();
assert_eq!(client.get(uri).dispatch().await.status(), Status::NotFound); assert_eq!(client.get(uri).dispatch().await.status(), Status::NotFound);
} }

View File

@ -1,5 +1,3 @@
#![feature(proc_macro_hygiene)]
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
@ -9,7 +7,7 @@ fn hello() -> &'static str {
"Hello, world!" "Hello, world!"
} }
#[rocket::main] #[launch]
async fn main() { fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().mount("/", routes![hello]).launch().await; rocket::ignite().mount("/", routes![hello])
} }

View File

@ -2,8 +2,7 @@ use rocket::local::Client;
#[rocket::async_test] #[rocket::async_test]
async fn hello_world() { async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]); let client = Client::new(super::rocket()).await.unwrap();
let client = Client::new(rocket).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, world!".into())); assert_eq!(response.body_string().await, Some("Hello, world!".into()));
} }

View File

@ -69,14 +69,10 @@ fn not_found() -> JsonValue {
}) })
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/message", routes![new, update, get]) .mount("/message", routes![new, update, get])
.register(catchers![not_found]) .register(catchers![not_found])
.manage(Mutex::new(HashMap::<ID, String>::new())) .manage(Mutex::new(HashMap::<ID, String>::new()))
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -19,13 +19,9 @@ fn pop(queue: State<'_, LogChannel>) -> Option<String> {
queue.0.pop().ok() queue.0.pop().ok()
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![push, pop]) .mount("/", routes![push, pop])
.manage(LogChannel(SegQueue::new())) .manage(LogChannel(SegQueue::new()))
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -98,6 +98,7 @@ impl Handler for CustomHandler {
} }
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
let always_forward = Route::ranked(1, Get, "/", forward); let always_forward = Route::ranked(1, Get, "/", forward);
let hello = Route::ranked(2, Get, "/", hi); let hello = Route::ranked(2, Get, "/", hi);
@ -117,8 +118,3 @@ fn rocket() -> rocket::Rocket {
.mount("/custom", CustomHandler::new("some data here")) .mount("/custom", CustomHandler::new("some data here"))
.register(vec![not_found_catcher]) .register(vec![not_found_catcher])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -23,11 +23,7 @@ fn create(data: MsgPack<Message<'_>>) -> String {
data.contents.to_string() data.contents.to_string()
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/message", routes![get, create]) rocket::ignite().mount("/message", routes![get, create])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -26,7 +26,7 @@ fn login() -> &'static str {
"Hi! That user doesn't exist. Maybe you need to log in?" "Hi! That user doesn't exist. Maybe you need to log in?"
} }
#[rocket::main] #[rocket::launch]
async fn main() { fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().mount("/", routes![root, user, login]).launch().await; rocket::ignite().mount("/", routes![root, user, login])
} }

View File

@ -1,22 +1,15 @@
use rocket::local::Client; use rocket::local::Client;
use rocket::http::Status; use rocket::http::Status;
async fn client() -> Client {
let rocket = rocket::ignite()
.mount("/", routes![super::root, super::user, super::login]);
Client::new(rocket).await.unwrap()
}
async fn test_200(uri: &str, expected_body: &str) { async fn test_200(uri: &str, expected_body: &str) {
let client = client().await; let client = Client::new(super::rocket()).await.unwrap();
let mut response = client.get(uri).dispatch().await; let mut response = client.get(uri).dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string().await, Some(expected_body.to_string())); assert_eq!(response.body_string().await, Some(expected_body.to_string()));
} }
async fn test_303(uri: &str, expected_location: &str) { async fn test_303(uri: &str, expected_location: &str) {
let client = client().await; let client = Client::new(super::rocket()).await.unwrap();
let response = client.get(uri).dispatch().await; let response = client.get(uri).dispatch().await;
let location_headers: Vec<_> = response.headers().get("Location").collect(); let location_headers: Vec<_> = response.headers().get("Location").collect();
assert_eq!(response.status(), Status::SeeOther); assert_eq!(response.status(), Status::SeeOther);

View File

@ -51,11 +51,7 @@ fn index() -> &'static str {
" "
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![index, upload, retrieve]) rocket::ignite().mount("/", routes![index, upload, retrieve])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -32,11 +32,7 @@ fn hello_20(person: LenientForm<Person>) -> String {
format!("20 years old? Hi, {}!", person.name) format!("20 years old? Hi, {}!", person.name)
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![hello, hello_20]) rocket::ignite().mount("/", routes![hello, hello_20])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -16,7 +16,7 @@ fn hi(name: String, age: &RawStr) -> String {
format!("Hi {}! Your age ({}) is kind of funky.", name, age) format!("Hi {}! Your age ({}) is kind of funky.", name, age)
} }
#[rocket::main] #[rocket::launch]
async fn main() { fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().mount("/", routes![hi, hello]).launch().await; rocket::ignite().mount("/", routes![hi, hello])
} }

View File

@ -1,8 +1,7 @@
use rocket::local::Client; use rocket::local::Client;
async fn test(uri: String, expected: String) { async fn test(uri: String, expected: String) {
let rocket = rocket::ignite().mount("/", routes![super::hello, super::hi]); let client = Client::new(super::rocket()).await.unwrap();
let client = Client::new(rocket).await.unwrap();
let mut response = client.get(&uri).dispatch().await; let mut response = client.get(&uri).dispatch().await;
assert_eq!(response.body_string().await, Some(expected)); assert_eq!(response.body_string().await, Some(expected));
} }

View File

@ -2,15 +2,12 @@
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
use rusqlite::types::ToSql;
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
use std::sync::Mutex; use std::sync::Mutex;
use rocket::{Rocket, State, response::Debug}; use rocket::{Rocket, State, response::Debug};
use rusqlite::{Connection, Error, types::ToSql};
use rusqlite::{Connection, Error};
type DbConn = Mutex<Connection>; type DbConn = Mutex<Connection>;
@ -35,6 +32,7 @@ fn hello(db_conn: State<'_, DbConn>) -> Result<String, Debug<Error>> {
.map_err(Debug) .map_err(Debug)
} }
#[rocket::launch]
fn rocket() -> Rocket { fn rocket() -> Rocket {
// Open a new in-memory SQLite database. // Open a new in-memory SQLite database.
let conn = Connection::open_in_memory().expect("in memory db"); let conn = Connection::open_in_memory().expect("in memory db");
@ -47,8 +45,3 @@ fn rocket() -> Rocket {
.manage(Mutex::new(conn)) .manage(Mutex::new(conn))
.mount("/", routes![hello]) .mount("/", routes![hello])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -17,11 +17,7 @@ fn index() -> &'static str {
"Upload your text files by POSTing them to /upload." "Upload your text files by POSTing them to /upload."
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![index, upload]) rocket::ignite().mount("/", routes![index, upload])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -16,7 +16,7 @@ fn login() -> &'static str {
"Hi! Please log in before continuing." "Hi! Please log in before continuing."
} }
#[rocket::main] #[rocket::launch]
async fn main() { fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().mount("/", routes![root, login]).launch().await; rocket::ignite().mount("/", routes![root, login])
} }

View File

@ -22,15 +22,11 @@ fn header_count(header_count: HeaderCount) -> String {
format!("Your request contained {} headers!", header_count.0) format!("Your request contained {} headers!", header_count.0)
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![header_count]) rocket::ignite().mount("/", routes![header_count])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use rocket::local::Client; use rocket::local::Client;

View File

@ -78,13 +78,9 @@ async fn r_async(_g1: Guard3, _g2: Guard4) {
// This exists only to run the request guards. // This exists only to run the request guards.
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.manage(Atomics::default()) .manage(Atomics::default())
.mount("/", routes![r_sync, r_async]) .mount("/", routes![r_sync, r_async])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -80,13 +80,9 @@ fn index() -> Redirect {
Redirect::to(uri!(login_page)) Redirect::to(uri!(login_page))
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.attach(Template::fairing()) .attach(Template::fairing())
.mount("/", routes![index, user_index, login, logout, login_user, login_page]) .mount("/", routes![index, user_index, login, logout, login_user, login_page])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -24,13 +24,9 @@ fn count(hit_count: State<'_, HitCount>) -> String {
hit_count.0.load(Ordering::Relaxed).to_string() hit_count.0.load(Ordering::Relaxed).to_string()
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![index, count]) .mount("/", routes![index, count])
.manage(HitCount(AtomicUsize::new(0))) .manage(HitCount(AtomicUsize::new(0)))
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -5,11 +5,7 @@ extern crate rocket_contrib;
use rocket_contrib::serve::StaticFiles; use rocket_contrib::serve::StaticFiles;
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", StaticFiles::from("static")) rocket::ignite().mount("/", StaticFiles::from("static"))
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -22,11 +22,7 @@ async fn file() -> Option<Stream<File>> {
File::open(FILENAME).await.map(Stream::from).ok() File::open(FILENAME).await.map(Stream::from).ok()
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![root, file]) rocket::ignite().mount("/", routes![root, file])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -35,14 +35,10 @@ fn not_found(req: &Request<'_>) -> Template {
Template::render("error/404", &map) Template::render("error/404", &map)
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![index, get]) .mount("/", routes![index, get])
.attach(Template::fairing()) .attach(Template::fairing())
.register(catchers![not_found]) .register(catchers![not_found])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -7,15 +7,11 @@ fn hello() -> &'static str {
"Hello, world!" "Hello, world!"
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![hello]) rocket::ignite().mount("/", routes![hello])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::rocket; use super::rocket;

View File

@ -9,7 +9,7 @@ fn hello() -> &'static str {
"Hello, world!" "Hello, world!"
} }
#[rocket::main] #[rocket::launch]
async fn main() { fn rocket() -> rocket::Rocket {
let _ = rocket::ignite().mount("/", routes![hello]).launch().await; rocket::ignite().mount("/", routes![hello])
} }

View File

@ -2,8 +2,7 @@ use rocket::local::Client;
#[rocket::async_test] #[rocket::async_test]
async fn hello_world() { async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]); let client = Client::new(super::rocket()).await.unwrap();
let client = Client::new(rocket).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, world!".into())); assert_eq!(response.body_string().await, Some("Hello, world!".into()));
} }

View File

@ -104,6 +104,7 @@ async fn run_db_migrations(mut rocket: Rocket) -> Result<Rocket, Rocket> {
} }
} }
#[rocket::launch]
fn rocket() -> Rocket { fn rocket() -> Rocket {
rocket::ignite() rocket::ignite()
.attach(DbConn::fairing()) .attach(DbConn::fairing())
@ -113,8 +114,3 @@ fn rocket() -> Rocket {
.mount("/todo", routes![new, toggle, delete]) .mount("/todo", routes![new, toggle, delete])
.attach(Template::fairing()) .attach(Template::fairing())
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -33,11 +33,7 @@ fn people(id: Uuid) -> Result<String, String> {
.ok_or_else(|| format!("Person not found for UUID: {}", id))?) .ok_or_else(|| format!("Person not found for UUID: {}", id))?)
} }
#[rocket::launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![people]) rocket::ignite().mount("/", routes![people])
} }
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}

View File

@ -238,9 +238,9 @@ You can find async-ready libraries on [crates.io](https://crates.io) with the
! note ! note
Rocket 0.5 uses the tokio (0.2) runtime. The runtime is started for you Rocket 0.5 uses the tokio (0.2) runtime. The runtime is started for you if you
if you use `#[rocket::main]`, but you can still `launch()` a rocket use `#[rocket::launch]` or `#[rocket::main]`, but you can still `launch()` a
instance on a custom-built `Runtime`. rocket instance on a custom-built `Runtime`.
### Cooperative Multitasking ### Cooperative Multitasking

View File

@ -232,7 +232,7 @@ fn main() {
``` ```
Notice the `rank` parameters in `user_int` and `user_str`. If we run this Notice the `rank` parameters in `user_int` and `user_str`. If we run this
application with the routes mounted at the root path, as is done in `main` application with the routes mounted at the root path, as is done in `rocket()`
above, requests to `/user/<id>` (such as `/user/123`, `/user/Bob`, and so on) above, requests to `/user/<id>` (such as `/user/123`, `/user/Bob`, and so on)
will be routed as follows: will be routed as follows:

View File

@ -47,8 +47,6 @@ margin = 9
[[sections]] [[sections]]
title = "Hello, Rocket!" title = "Hello, Rocket!"
code = ''' code = '''
#![feature(proc_macro_hygiene)]
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
#[get("/hello/<name>/<age>")] #[get("/hello/<name>/<age>")]
@ -56,8 +54,9 @@ code = '''
format!("Hello, {} year old named {}!", age, name) format!("Hello, {} year old named {}!", age, name)
} }
fn main() { #[launch]
rocket::ignite().mount("/", routes![hello]).launch(); fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![hello])
} }
''' '''
text = ''' text = '''

View File

@ -136,22 +136,23 @@ fn not_found() -> T { ... }
name = "Launching" name = "Launching"
content = ''' content = '''
Launching a Rocket application is the funnest part! For Rocket to begin Launching a Rocket application is the funnest part! For Rocket to begin
dispatching requests to routes, the routes need to be _mounted_. After mounting, dispatching requests to routes, routes need to be _mounted_. After mounting, the
the application needs to be _launched_. These two steps, usually done in `main`, application needs to be _launched_. These two steps, usually done in a `rocket`
look like: function, look like:
```rust ```rust
rocket::ignite() #[launch]
.mount("/base", routes![index, another]) fn rocket() -> Rocket {
.launch(); rocket::ignite().mount("/base", routes![index, another])
}
``` ```
The `mount` call takes a base path and a set of routes via the `routes!` macro. The `mount` call takes a base path and a set of routes via the `routes!` macro.
The base path (`/base` above) is prepended to the path of every route in the The base path (`/base` above) is prepended to the path of every route in the
list. This effectively namespaces the routes, allowing for easier composition. list. This namespaces the routes, allowing for composition. The `#[launch]`
attribute creates a `main` function that starts the server. In development,
The `launch` call starts the server. In development, Rocket prints useful Rocket prints useful information to the console to let you know everything is
information to the console to let you know everything is okay. okay.
```sh ```sh
🚀 Rocket has launched from http://localhost:8000 🚀 Rocket has launched from http://localhost:8000