rocket_codegen/bang/
mod.rs

1mod uri;
2mod uri_parsing;
3mod test_guide;
4mod export;
5
6pub mod typed_stream;
7
8use devise::Result;
9use syn::{Path, punctuated::Punctuated, parse::Parser, Token};
10use syn::spanned::Spanned;
11use proc_macro2::TokenStream;
12
13fn struct_maker_vec(
14    input: proc_macro::TokenStream,
15    ty: TokenStream,
16    map: impl Fn(TokenStream) -> TokenStream,
17) -> Result<TokenStream> {
18    use crate::exports::_Vec;
19
20    // Parse a comma-separated list of paths.
21    let paths = <Punctuated<Path, Token![,]>>::parse_terminated.parse(input)?;
22    let exprs = paths.iter().map(|path| {
23        let expr = map(quote_spanned!(path.span() => ___struct));
24        quote_spanned!(path.span() => {
25            let ___struct = #path {};
26            let ___item: #ty = #expr;
27            ___item
28        })
29    });
30
31    Ok(quote!({
32        let ___vec: #_Vec<#ty> = vec![#(#exprs),*];
33        ___vec
34    }))
35}
36
37pub fn routes_macro(input: proc_macro::TokenStream) -> TokenStream {
38    struct_maker_vec(input, quote!(::rocket::Route), |e| quote!(#e.into_route()))
39        .unwrap_or_else(|diag| diag.emit_as_expr_tokens())
40}
41
42pub fn catchers_macro(input: proc_macro::TokenStream) -> TokenStream {
43    struct_maker_vec(input, quote!(::rocket::Catcher), |e| quote!(#e.into_catcher()))
44        .unwrap_or_else(|diag| diag.emit_as_expr_tokens())
45}
46
47pub fn uri_macro(input: proc_macro::TokenStream) -> TokenStream {
48    uri::_uri_macro(input.into())
49        .unwrap_or_else(|diag| diag.emit_as_expr_tokens_or(quote! {
50            rocket::http::uri::Origin::ROOT
51        }))
52}
53
54pub fn uri_internal_macro(input: proc_macro::TokenStream) -> TokenStream {
55    // TODO: Ideally we would generate a perfect `Origin::ROOT` so that we don't
56    // assist in propagating further errors. Alas, we can't set the span to the
57    // invocation of `uri!` without access to `span.parent()`, and
58    // `Span::call_site()` here points to the `#[route]`, immediate caller,
59    // generating a rather confusing error message when there's a type-mismatch.
60    uri::_uri_internal_macro(input.into())
61        .unwrap_or_else(|diag| diag.emit_as_expr_tokens_or(quote! {
62            rocket::http::uri::Origin::ROOT
63        }))
64}
65
66pub fn guide_tests_internal(input: proc_macro::TokenStream) -> TokenStream {
67    test_guide::_macro(input)
68        .unwrap_or_else(|diag| diag.emit_as_item_tokens())
69}
70
71pub fn export_internal(input: proc_macro::TokenStream) -> TokenStream {
72    export::_macro(input)
73        .unwrap_or_else(|diag| diag.emit_as_item_tokens())
74}
75
76pub fn typed_stream(input: proc_macro::TokenStream) -> TokenStream {
77    typed_stream::_macro(input)
78        .unwrap_or_else(|diag| diag.emit_as_item_tokens())
79}