#![recursion_limit="128"] #![doc(html_root_url = "https://api.rocket.rs/master")] #![doc(html_favicon_url = "https://rocket.rs/images/favicon.ico")] #![doc(html_logo_url = "https://rocket.rs/images/logo-boxed.png")] #![warn(rust_2018_idioms)] //! # Rocket - Code Generation //! //! This crate implements the code generation portions of Rocket. This includes //! custom derives, custom attributes, and procedural macros. The documentation //! here is purely technical. The code generation facilities are documented //! thoroughly in the [Rocket programming guide](https://rocket.rs/master/guide). //! //! # Usage //! //! You **_should not_** directly depend on this library. To use the macros, //! attributes, and derives in this crate, it suffices to depend on `rocket` in //! `Cargo.toml`: //! //! ```toml //! [dependencies] //! rocket = "0.5.0-dev" //! ``` //! //! And to import all macros, attributes, and derives via `#[macro_use]` in the //! crate root: //! //! ```rust //! #[macro_use] extern crate rocket; //! # #[get("/")] fn hello() { } //! # fn main() { rocket::ignite().mount("/", routes![hello]); } //! ``` //! //! Or, alternatively, selectively import from the top-level scope: //! //! ```rust //! # extern crate rocket; //! //! use rocket::{get, routes}; //! # #[get("/")] fn hello() { } //! # fn main() { rocket::ignite().mount("/", routes![hello]); } //! ``` //! //! # Debugging Codegen //! //! When the `ROCKET_CODEGEN_DEBUG` environment variable is set, this crate //! logs, at compile-time and to the console, the items it generates. For //! example, you might run the following to build a Rocket application with //! codegen debug logging enabled: //! //! ```sh //! ROCKET_CODEGEN_DEBUG=1 cargo build //! ``` #[macro_use] extern crate quote; use rocket_http as http; #[macro_use] mod exports; mod proc_macro_ext; mod derive; mod attribute; mod bang; mod http_codegen; mod syn_ext; mod name; use crate::http::Method; use proc_macro::TokenStream; use devise::{proc_macro2, syn}; static URI_MACRO_PREFIX: &str = "rocket_uri_macro_"; static ROCKET_IDENT_PREFIX: &str = "__rocket_"; macro_rules! emit { ($tokens:expr) => ({ use devise::ext::SpanDiagnosticExt; let mut tokens = $tokens; if std::env::var_os("ROCKET_CODEGEN_DEBUG").is_some() { let debug_tokens = proc_macro2::Span::call_site() .note("emitting Rocket code generation debug output") .note(tokens.to_string()) .emit_as_item_tokens(); tokens.extend(debug_tokens); } tokens.into() }) } macro_rules! route_attribute { ($name:ident => $method:expr) => ( /// Attribute to generate a [`Route`] and associated metadata. /// /// This and all other route attributes can only be applied to free /// functions: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[get("/")] /// fn index() -> &'static str { /// "Hello, world!" /// } /// ``` /// /// There are 7 method-specific route attributes: /// /// * [`get`] - `GET` specific route /// * [`put`] - `PUT` specific route /// * [`post`] - `POST` specific route /// * [`delete`] - `DELETE` specific route /// * [`head`] - `HEAD` specific route /// * [`options`] - `OPTIONS` specific route /// * [`patch`] - `PATCH` specific route /// /// Additionally, [`route`] allows the method and uri to be explicitly /// specified: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[route(GET, uri = "/")] /// fn index() -> &'static str { /// "Hello, world!" /// } /// ``` /// /// [`get`]: attr.get.html /// [`put`]: attr.put.html /// [`post`]: attr.post.html /// [`delete`]: attr.delete.html /// [`head`]: attr.head.html /// [`options`]: attr.options.html /// [`patch`]: attr.patch.html /// [`route`]: attr.route.html /// /// # Grammar /// /// The grammar for all method-specific route attributes is defined as: /// /// ```text /// route := '"' uri ('?' query)? '"' (',' parameter)* /// /// uri := ('/' segment)* /// /// query := segment ('&' segment)* /// /// segment := URI_SEG /// | SINGLE_PARAM /// | TRAILING_PARAM /// /// parameter := 'rank' '=' INTEGER /// | 'format' '=' '"' MEDIA_TYPE '"' /// | 'data' '=' '"' SINGLE_PARAM '"' /// /// SINGLE_PARAM := '<' IDENT '>' /// TRAILING_PARAM := '<' IDENT '..>' /// /// URI_SEG := valid, non-percent-encoded HTTP URI segment /// MEDIA_TYPE := valid HTTP media type or known shorthand /// /// INTEGER := unsigned integer, as defined by Rust /// IDENT := valid identifier, as defined by Rust, except `_` /// ``` /// /// The generic route attribute is defined as: /// /// ```text /// generic-route := METHOD ',' 'uri' '=' route /// ``` /// /// # Typing Requirements /// /// Every identifier that appears in a dynamic parameter (`SINGLE_PARAM` /// or `TRAILING_PARAM`) must appear as an argument to the function. For /// example, the following route requires the decorated function to have /// the arguments `foo`, `baz`, `msg`, `rest`, and `form`: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # use rocket::form::Form; /// # use std::path::PathBuf; /// # #[derive(FromForm)] struct F { a: usize } /// #[get("//bar/?&closed&", data = "
")] /// # fn f(foo: usize, baz: PathBuf, msg: String, rest: F, form: Form) { } /// ``` /// /// The type of each function argument corresponding to a dynamic /// parameter is required to implement one of Rocket's guard traits. The /// exact trait that is required to be implemented depends on the kind /// of dynamic parameter (`SINGLE` or `TRAILING`) and where in the route /// attribute the parameter appears. The table below summarizes trait /// requirements: /// /// | position | kind | trait | /// |----------|-------------|-------------------| /// | path | `` | [`FromParam`] | /// | path | `` | [`FromSegments`] | /// | query | `` | [`FromForm`] | /// | query | `` | [`FromFrom`] | /// | data | `` | [`FromData`] | /// /// The type of each function argument that _does not_ have a /// corresponding dynamic parameter is required to implement the /// [`FromRequest`] trait. /// /// The return type of the decorated function must implement the /// [`Responder`] trait. /// /// [`FromParam`]: ../rocket/request/trait.FromParam.html /// [`FromSegments`]: ../rocket/request/trait.FromSegments.html /// [`FromFormField`]: ../rocket/request/trait.FromFormField.html /// [`FromForm`]: ../rocket/form/trait.FromForm.html /// [`FromData`]: ../rocket/data/trait.FromData.html /// [`FromRequest`]: ../rocket/request/trait.FromRequest.html /// [`Route`]: ../rocket/struct.Route.html /// [`Responder`]: ../rocket/response/trait.Responder.html /// /// # Semantics /// /// The attribute generates three items: /// /// 1. A route [`Handler`]. /// /// The generated handler validates and generates all arguments for /// the generated function according to the trait that their type /// must implement. The order in which arguments are processed is: /// /// 1. Request guards from left to right. /// /// If a request guard fails, the request is forwarded if the /// [`Outcome`] is `Forward` or failed if the [`Outcome`] is /// `Failure`. See [`FromRequest` Outcomes] for further /// detail. /// /// 2. Path and query guards in an unspecified order. If a path /// or query guard fails, the request is forwarded. /// /// 3. Data guard, if any. /// /// If a data guard fails, the request is forwarded if the /// [`Outcome`] is `Forward` or failed if the [`Outcome`] is /// `Failure`. See [`FromData` Outcomes] for further detail. /// /// If all validation succeeds, the decorated function is called. /// The returned value is used to generate a [`Response`] via the /// type's [`Responder`] implementation. /// /// 2. A static structure used by [`routes!`] to generate a [`Route`]. /// /// The static structure (and resulting [`Route`]) is populated /// with the name (the function's name), path, query, rank, and /// format from the route attribute. The handler is set to the /// generated handler. /// /// 3. A macro used by [`uri!`] to type-check and generate an /// [`Origin`]. /// /// [`Handler`]: rocket::handler::Handler /// [`routes!`]: macro.routes.html /// [`uri!`]: macro.uri.html /// [`Origin`]: rocket::http::uri::Origin /// [`Outcome`]: rocket::outcome::Outcome /// [`Response`]: rocket::Response /// [`FromRequest` Outcomes]: rocket::request::FromRequest#outcomes /// [`FromData` Outcomes]: rocket::data::FromData#outcomes #[proc_macro_attribute] pub fn $name(args: TokenStream, input: TokenStream) -> TokenStream { emit!(attribute::route::route_attribute($method, args, input)) } ) } route_attribute!(route => None); route_attribute!(get => Method::Get); route_attribute!(put => Method::Put); route_attribute!(post => Method::Post); route_attribute!(delete => Method::Delete); route_attribute!(head => Method::Head); route_attribute!(patch => Method::Patch); route_attribute!(options => Method::Options); /// Attribute to generate a [`Catcher`] and associated metadata. /// /// This attribute can only be applied to free functions: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// use rocket::Request; /// use rocket::http::Status; /// /// #[catch(404)] /// fn not_found(req: &Request) -> String { /// format!("Sorry, {} does not exist.", req.uri()) /// } /// /// #[catch(default)] /// fn default(status: Status, req: &Request) -> String { /// format!("{} - {} ({})", status.code, status.reason, req.uri()) /// } /// ``` /// /// # Grammar /// /// The grammar for the `#[catch]` attributes is defined as: /// /// ```text /// catch := STATUS | 'default' /// /// STATUS := valid HTTP status code (integer in [200, 599]) /// ``` /// /// # Typing Requirements /// /// The decorated function may take zero, one, or two arguments. It's type /// signature must be one of the following, where `R:`[`Responder`]: /// /// * `fn() -> R` /// * `fn(`[`&Request`]`) -> R` /// * `fn(`[`Status`]`, `[`&Request`]`) -> R` /// /// # Semantics /// /// The attribute generates two items: /// /// 1. An [`ErrorHandler`]. /// /// The generated handler calls the decorated function, passing in the /// [`Status`] and [`&Request`] values if requested. The returned value is /// used to generate a [`Response`] via the type's [`Responder`] /// implementation. /// /// 2. A static structure used by [`catchers!`] to generate a [`Catcher`]. /// /// The static structure (and resulting [`Catcher`]) is populated with the /// name (the function's name) and status code from the route attribute or /// `None` if `default`. The handler is set to the generated handler. /// /// [`&Request`]: rocket::Request /// [`Status`]: rocket::http::Status /// [`ErrorHandler`]: rocket::catcher::ErrorHandler /// [`catchers!`]: macro.catchers.html /// [`Catcher`]: rocket::Catcher /// [`Response`]: rocket::Response /// [`Responder`]: rocket::Responder #[proc_macro_attribute] pub fn catch(args: TokenStream, input: TokenStream) -> TokenStream { emit!(attribute::catch::catch_attribute(args, input)) } #[proc_macro_attribute] pub fn async_test(args: TokenStream, input: TokenStream) -> TokenStream { emit!(attribute::entry::async_test_attribute(args, input)) } #[proc_macro_attribute] pub fn main(args: TokenStream, input: TokenStream) -> TokenStream { emit!(attribute::entry::main_attribute(args, input)) } #[proc_macro_attribute] pub fn launch(args: TokenStream, input: TokenStream) -> TokenStream { emit!(attribute::entry::launch_attribute(args, input)) } /// Derive for the [`FromFormField`] trait. /// /// The [`FromFormField`] derive can be applied to enums with nullary /// (zero-length) fields: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[derive(FromFormField)] /// enum MyValue { /// First, /// Second, /// Third, /// } /// ``` /// /// The derive generates an implementation of the [`FromFormField`] trait for /// the decorated `enum`. The implementation returns successfully when the form /// value matches, case insensitively, the stringified version of a variant's /// name, returning an instance of said variant. If there is no match, an error /// recording all of the available options is returned. /// /// As an example, for the `enum` above, the form values `"first"`, `"FIRST"`, /// `"fiRSt"`, and so on would parse as `MyValue::First`, while `"second"` and /// `"third"` would parse as `MyValue::Second` and `MyValue::Third`, /// respectively. /// /// The `field` field attribute can be used to change the string value that is /// compared against for a given variant: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[derive(FromFormField)] /// enum MyValue { /// First, /// Second, /// #[field(value = "fourth")] /// Third, /// } /// ``` /// /// The `#[field]` attribute's grammar is: /// /// ```text /// field := 'value' '=' STRING_LIT /// /// STRING_LIT := any valid string literal, as defined by Rust /// ``` /// /// The attribute accepts a single string parameter of name `value` /// corresponding to the string to use to match against for the decorated /// variant. In the example above, the the strings `"fourth"`, `"FOUrth"` and so /// on would parse as `MyValue::Third`. /// /// [`FromFormField`]: rocket::form::FromFormField /// [`FromFormField::Error`]: rocket::form::FromFormField::Error #[proc_macro_derive(FromFormField, attributes(field))] pub fn derive_from_form_field(input: TokenStream) -> TokenStream { emit!(derive::from_form_field::derive_from_form_field(input)) } /// Derive for the [`FromForm`] trait. /// /// The [`FromForm`] derive can be applied to structures with named fields: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[derive(FromForm)] /// struct MyStruct<'r> { /// field: usize, /// #[field(name = "renamed_field")] /// #[field(name = uncased("RenamedField"))] /// other: &'r str, /// #[field(validate = range(1..))] /// r#type: usize, /// } /// ``` /// /// Each field's type is required to implement [`FromForm`]. /// /// The derive generates an implementation of the [`FromForm`] trait. The /// implementation parses a form whose field names match the field names of the /// structure on which the derive was applied. Each field's value is parsed with /// the [`FromForm`] implementation of the field's type. The `FromForm` /// implementation succeeds only when all of the field parses succeed or return /// a default. Errors are collected into a [`form::Errors`] and return if /// non-empty after parsing all fields. /// /// The derive accepts one field attribute: `field`, with the following syntax: /// /// ```text /// field := name? validate* /// /// name := 'name' '=' name_val /// name_val := '"' FIELD_NAME '"' /// | 'uncased(' '"' FIELD_NAME '"' ') /// /// validate := 'validate' '=' EXPR /// /// FIELD_NAME := valid field name, according to the HTML5 spec /// EXPR := valid expression, as defined by Rust /// ``` /// /// The attribute can be applied any number of times on a field. When applied, /// the attribute looks as follows: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[derive(FromForm)] /// struct MyStruct { /// field: usize, /// #[field(name = "renamed_field")] /// #[field(name = uncased("anotherName"))] /// #[field(validate = eq("banana"))] /// #[field(validate = neq("orange"))] /// other: String /// } /// ``` /// /// **`name`** /// /// A `name` attribute changes the name to match against when parsing the form /// field. The value is either an exact string to match against (`"foo"`), or /// `uncased("foo")`, which causes the match to be case-insensitive but /// case-preserving. When more than one `name` attribute is applied, the field /// will match against _any_ of the names. /// /// **`validate`** /// /// The validation expression will be run if the field type parses successfully. /// The expression must return a value of type `Result<(), form::Errors>`. On /// `Err`, the errors are added to the thus-far collected errors. If more than /// one `validate` attribute is applied, _all_ validations are run. /// /// [`FromForm`]: rocket::form::FromForm /// [`form::Errors`]: rocket::form::Errors #[proc_macro_derive(FromForm, attributes(field))] pub fn derive_from_form(input: TokenStream) -> TokenStream { emit!(derive::from_form::derive_from_form(input)) } /// Derive for the [`Responder`] trait. /// /// The [`Responder`] derive can be applied to enums and structs with named /// fields. When applied to enums, variants must have at least one field. When /// applied to structs, the struct must have at least one field. /// /// ```rust /// # #[macro_use] extern crate rocket; /// # use std::fs::File; /// # use rocket::http::ContentType; /// # type OtherResponder = MyResponderA; /// # /// #[derive(Responder)] /// enum MyResponderA { /// A(String), /// B(File, ContentType), /// } /// /// #[derive(Responder)] /// struct MyResponderB { /// inner: OtherResponder, /// header: ContentType, /// } /// ``` /// /// The derive generates an implementation of the [`Responder`] trait for the /// decorated enum or structure. The derive uses the _first_ field of a variant /// or structure to generate a [`Response`]. As such, the type of the first /// field must implement [`Responder`]. The remaining fields of a variant or /// structure are set as headers in the produced [`Response`] using /// [`Response::set_header()`]. As such, every other field (unless explicitly /// ignored, explained next) must implement `Into
`. /// /// Except for the first field, fields decorated with `#[response(ignore)]` are /// ignored by the derive: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # use std::fs::File; /// # use rocket::http::ContentType; /// # use rocket::response::NamedFile; /// # type Other = usize; /// # /// #[derive(Responder)] /// enum MyResponder { /// A(String), /// B(File, ContentType, #[response(ignore)] Other), /// } /// /// #[derive(Responder)] /// struct MyOtherResponder { /// inner: NamedFile, /// header: ContentType, /// #[response(ignore)] /// other: Other, /// } /// ``` /// /// Decorating the first field with `#[response(ignore)]` has no effect. /// /// Additionally, the `response` attribute can be used on named structures and /// enum variants to override the status and/or content-type of the [`Response`] /// produced by the generated implementation. The `response` attribute used in /// these positions has the following grammar: /// /// ```text /// response := parameter (',' parameter)? /// /// parameter := 'status' '=' STATUS /// | 'content_type' '=' CONTENT_TYPE /// /// STATUS := unsigned integer >= 100 and < 600 /// CONTENT_TYPE := string literal, as defined by Rust, identifying a valid /// Content-Type, as defined by Rocket /// ``` /// /// It can be used as follows: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # use rocket::http::ContentType; /// # use rocket::response::NamedFile; /// # type Other = usize; /// # type InnerResponder = String; /// # /// #[derive(Responder)] /// enum Error { /// #[response(status = 500, content_type = "json")] /// A(String), /// #[response(status = 404)] /// B(NamedFile, ContentType), /// } /// /// #[derive(Responder)] /// #[response(status = 400)] /// struct MyResponder { /// inner: InnerResponder, /// header: ContentType, /// #[response(ignore)] /// other: Other, /// } /// ``` /// /// The attribute accepts two key/value pairs: `status` and `content_type`. The /// value of `status` must be an unsigned integer representing a valid status /// code. The [`Response`] produced from the generated implementation will have /// its status overridden to this value. /// /// The value of `content_type` must be a valid media-type in `top/sub` form or /// `shorthand` form. Examples include: /// /// * `"text/html"` /// * `"application/x-custom"` /// * `"html"` /// * `"json"` /// * `"plain"` /// * `"binary"` /// /// See [`ContentType::parse_flexible()`] for a full list of available /// shorthands. The [`Response`] produced from the generated implementation will /// have its content-type overridden to this value. /// /// [`Responder`]: ../rocket/response/trait.Responder.html /// [`Response`]: ../rocket/struct.Response.html /// [`Response::set_header()`]: ../rocket/response/struct.Response.html#method.set_header /// [`ContentType::parse_flexible()`]: ../rocket/http/struct.ContentType.html#method.parse_flexible #[proc_macro_derive(Responder, attributes(response))] pub fn derive_responder(input: TokenStream) -> TokenStream { emit!(derive::responder::derive_responder(input)) } /// Derive for the [`UriDisplay`] trait. /// /// The [`UriDisplay`] derive can be applied to enums and structs. When /// applied to enums, variants must have at least one field. When applied to /// structs, the struct must have at least one field. /// /// ```rust /// # #[macro_use] extern crate rocket; /// #[derive(UriDisplayQuery)] /// enum Kind { /// A(String), /// B(usize), /// } /// /// #[derive(UriDisplayQuery)] /// struct MyStruct { /// name: String, /// id: usize, /// kind: Kind, /// } /// ``` /// /// Each field's type is required to implement [`UriDisplay`]. /// /// The derive generates an implementation of the [`UriDisplay`] trait. /// The implementation calls [`Formatter::write_named_value()`] for every named /// field, using the field's name (unless overridden, explained next) as the /// `name` parameter, and [`Formatter::write_value()`] for every unnamed field /// in the order the fields are declared. /// /// The derive accepts one field attribute: `field`, with the following syntax: /// /// ```text /// field := 'name' '=' '"' IDENT '"' /// /// IDENT := valid identifier, as defined by Rust /// ``` /// /// When applied, the attribute looks as follows: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # #[derive(UriDisplayQuery)] /// # struct Kind(String); /// #[derive(UriDisplayQuery)] /// struct MyStruct { /// name: String, /// id: usize, /// #[field(name = "type")] /// kind: Kind, /// } /// ``` /// /// The field attribute directs that a different field name be used when calling /// [`Formatter::write_named_value()`] for the given field. The value of the /// `name` attribute is used instead of the structure's actual field name. In /// the example above, the field `MyStruct::kind` is rendered with a name of /// `type`. /// /// [`UriDisplay`]: ../rocket/http/uri/trait.UriDisplay.html /// [`Formatter::write_named_value()`]: ../rocket/http/uri/struct.Formatter.html#method.write_named_value /// [`Formatter::write_value()`]: ../rocket/http/uri/struct.Formatter.html#method.write_value #[proc_macro_derive(UriDisplayQuery, attributes(field))] pub fn derive_uri_display_query(input: TokenStream) -> TokenStream { emit!(derive::uri_display::derive_uri_display_query(input)) } /// Derive for the [`UriDisplay`] trait. /// /// The [`UriDisplay`] derive can only be applied to tuple structs with /// one field. /// /// ```rust /// # #[macro_use] extern crate rocket; /// #[derive(UriDisplayPath)] /// struct Name(String); /// /// #[derive(UriDisplayPath)] /// struct Age(usize); /// ``` /// /// The field's type is required to implement [`UriDisplay`]. /// /// The derive generates an implementation of the [`UriDisplay`] trait. /// The implementation calls [`Formatter::write_value()`] for the field. /// /// [`UriDisplay`]: ../rocket/http/uri/trait.UriDisplay.html /// [`Formatter::write_value()`]: ../rocket/http/uri/struct.Formatter.html#method.write_value #[proc_macro_derive(UriDisplayPath)] pub fn derive_uri_display_path(input: TokenStream) -> TokenStream { emit!(derive::uri_display::derive_uri_display_path(input)) } /// Generates a [`Vec`] of [`Route`]s from a set of route paths. /// /// The `routes!` macro expands a list of route paths into a [`Vec`] of their /// corresponding [`Route`] structures. For example, given the following routes: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[get("/")] /// fn index() { /* .. */ } /// /// mod person { /// #[post("/hi/")] /// pub fn hello(person: String) { /* .. */ } /// } /// ``` /// /// The `routes!` macro can be used as: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// # use rocket::http::Method; /// # /// # #[get("/")] fn index() { /* .. */ } /// # mod person { /// # #[post("/hi/")] pub fn hello(person: String) { /* .. */ } /// # } /// let my_routes = routes![index, person::hello]; /// assert_eq!(my_routes.len(), 2); /// /// let index_route = &my_routes[0]; /// assert_eq!(index_route.method, Method::Get); /// assert_eq!(index_route.name.as_ref().unwrap(), "index"); /// assert_eq!(index_route.uri.path(), "/"); /// /// let hello_route = &my_routes[1]; /// assert_eq!(hello_route.method, Method::Post); /// assert_eq!(hello_route.name.as_ref().unwrap(), "hello"); /// assert_eq!(hello_route.uri.path(), "/hi/"); /// ``` /// /// The grammar for `routes!` is defined as: /// /// ```text /// routes := PATH (',' PATH)* /// /// PATH := a path, as defined by Rust /// ``` /// /// [`Route`]: ../rocket/struct.Route.html #[proc_macro] pub fn routes(input: TokenStream) -> TokenStream { emit!(bang::routes_macro(input)) } /// Generates a [`Vec`] of [`Catcher`]s from a set of catcher paths. /// /// The `catchers!` macro expands a list of catcher paths into a [`Vec`] of /// their corresponding [`Catcher`] structures. For example, given the following /// catchers: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[catch(404)] /// fn not_found() { /* .. */ } /// /// mod inner { /// #[catch(400)] /// pub fn unauthorized() { /* .. */ } /// } /// /// #[catch(default)] /// fn default_catcher() { /* .. */ } /// ``` /// /// The `catchers!` macro can be used as: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// # #[catch(404)] fn not_found() { /* .. */ } /// # #[catch(default)] fn default_catcher() { /* .. */ } /// # mod inner { /// # #[catch(400)] pub fn unauthorized() { /* .. */ } /// # } /// let my_catchers = catchers![not_found, inner::unauthorized, default_catcher]; /// assert_eq!(my_catchers.len(), 3); /// /// let not_found = &my_catchers[0]; /// assert_eq!(not_found.code, Some(404)); /// /// let unauthorized = &my_catchers[1]; /// assert_eq!(unauthorized.code, Some(400)); /// /// let default = &my_catchers[2]; /// assert_eq!(default.code, None); /// ``` /// /// The grammar for `catchers!` is defined as: /// /// ```text /// catchers := PATH (',' PATH)* /// /// PATH := a path, as defined by Rust /// ``` /// /// [`Catcher`]: ../rocket/struct.Catcher.html #[proc_macro] pub fn catchers(input: TokenStream) -> TokenStream { emit!(bang::catchers_macro(input)) } /// Type-safe, URI-safe generation of an [`Origin`] URI from a route. /// /// The `uri!` macro creates a type-safe, URL-safe URI given a route and values /// for the route's URI parameters. The inputs to the macro are the path to a /// route, a colon, and one argument for each dynamic parameter (parameters in /// `<>`) in the route's path and query. /// /// For example, for the following route: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// #[get("/person/?")] /// fn person(name: String, age: Option) -> String { /// # "".into() /* /// ... /// # */ /// } /// ``` /// /// A URI can be created as follows: /// /// ```rust /// # #[macro_use] extern crate rocket; /// # /// # #[get("/person/?")] /// # fn person(name: String, age: Option) { } /// # /// // with unnamed parameters, in route path declaration order /// let mike = uri!(person: "Mike Smith", Some(28)); /// assert_eq!(mike.to_string(), "/person/Mike%20Smith?age=28"); /// /// // with named parameters, order irrelevant /// let mike = uri!(person: name = "Mike", age = Some(28)); /// let mike = uri!(person: age = Some(28), name = "Mike"); /// assert_eq!(mike.to_string(), "/person/Mike?age=28"); /// /// // with a specific mount-point /// let mike = uri!("/api", person: name = "Mike", age = Some(28)); /// assert_eq!(mike.to_string(), "/api/person/Mike?age=28"); /// /// // with unnamed values ignored /// let mike = uri!(person: "Mike", _); /// assert_eq!(mike.to_string(), "/person/Mike"); /// /// // with unnamed values, explicitly `None`. /// let option: Option = None; /// let mike = uri!(person: "Mike", option); /// assert_eq!(mike.to_string(), "/person/Mike"); /// /// // with named values ignored /// let mike = uri!(person: name = "Mike", age = _); /// assert_eq!(mike.to_string(), "/person/Mike"); /// /// // with named values, explicitly `None` /// let option: Option = None; /// let mike = uri!(person: name = "Mike", age = option); /// assert_eq!(mike.to_string(), "/person/Mike"); /// ``` /// /// ## Grammar /// /// The grammar for the `uri!` macro is: /// /// ```text /// uri := (mount ',')? PATH (':' params)? /// /// mount = STRING /// params := unnamed | named /// unnamed := expr (',' expr)* /// named := IDENT = expr (',' named)? /// expr := EXPR | '_' /// /// EXPR := a valid Rust expression (examples: `foo()`, `12`, `"hey"`) /// IDENT := a valid Rust identifier (examples: `name`, `age`) /// STRING := an uncooked string literal, as defined by Rust (example: `"hi"`) /// PATH := a path, as defined by Rust (examples: `route`, `my_mod::route`) /// ``` /// /// ## Semantics /// /// The `uri!` macro returns an [`Origin`] structure with the URI of the /// supplied route interpolated with the given values. Note that `Origin` /// implements `Into` (and by extension, `TryInto`), so it can be /// converted into a [`Uri`] using `.into()` as needed. /// /// A `uri!` invocation only typechecks if the type of every value in the /// invocation matches the type declared for the parameter in the given route, /// after conversion with [`FromUriParam`], or if a value is ignored using `_` /// and the corresponding route type implements [`Ignorable`]. /// /// Each value passed into `uri!` is rendered in its appropriate place in the /// URI using the [`UriDisplay`] implementation for the value's type. The /// `UriDisplay` implementation ensures that the rendered value is URI-safe. /// /// If a mount-point is provided, the mount-point is prepended to the route's /// URI. /// /// ### Conversion /// /// The [`FromUriParam`] trait is used to typecheck and perform a conversion for /// each value passed to `uri!`. If a `FromUriParam` implementation exists /// for a type `T` for part URI part `P`, then a value of type `S` can be used /// in `uri!` macro for a route URI parameter declared with a type of `T` in /// part `P`. For example, the following implementation, provided by Rocket, /// allows an `&str` to be used in a `uri!` invocation for route URI parameters /// declared as `String`: /// /// ```rust,ignore /// impl FromUriParam for String { .. } /// ``` /// /// ### Ignorables /// /// Query parameters can be ignored using `_` in place of an expression. The /// corresponding type in the route URI must implement [`Ignorable`]. Ignored /// parameters are not interpolated into the resulting `Origin`. Path parameters /// are not ignorable. /// /// [`Uri`]: ../rocket/http/uri/enum.Uri.html /// [`Origin`]: ../rocket/http/uri/struct.Origin.html /// [`FromUriParam`]: ../rocket/http/uri/trait.FromUriParam.html /// [`UriDisplay`]: ../rocket/http/uri/trait.UriDisplay.html /// [`Ignorable`]: ../rocket/http/uri/trait.Ignorable.html #[proc_macro] pub fn uri(input: TokenStream) -> TokenStream { emit!(bang::uri_macro(input)) } #[doc(hidden)] #[proc_macro] pub fn rocket_internal_uri(input: TokenStream) -> TokenStream { emit!(bang::uri_internal_macro(input)) } #[doc(hidden)] #[proc_macro] pub fn internal_guide_tests(input: TokenStream) -> TokenStream { emit!(bang::guide_tests_internal(input)) }