1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;

use devise::{syn, Spanned, Result};
use self::syn::{Path, punctuated::Punctuated, parse::Parser, token::Comma};
use syn_ext::{IdentExt, syn_to_diag};
use {ROUTE_STRUCT_PREFIX, CATCH_STRUCT_PREFIX};

mod uri;
mod uri_parsing;
mod test_guide;

crate fn prefix_last_segment(path: &mut Path, prefix: &str) {
    let mut last_seg = path.segments.last_mut().expect("syn::Path has segments");
    last_seg.value_mut().ident = last_seg.value().ident.prepend(prefix);
}

fn _prefixed_vec(
    prefix: &str,
    input: TokenStream,
    ty: &TokenStream2
) -> Result<TokenStream2> {
    // Parse a comma-separated list of paths.
    let mut paths = <Punctuated<Path, Comma>>::parse_terminated
        .parse(input)
        .map_err(syn_to_diag)?;

    // Prefix the last segment in each path with `prefix`.
    paths.iter_mut().for_each(|p| prefix_last_segment(p, prefix));

    // Return a `vec!` of the prefixed, mapped paths.
    let prefixed_mapped_paths = paths.iter()
        .map(|path| quote_spanned!(path.span().into() => #ty::from(&#path)));

    Ok(quote!(vec![#(#prefixed_mapped_paths),*]))
}

fn prefixed_vec(prefix: &str, input: TokenStream, ty: TokenStream2) -> TokenStream {
    let vec = _prefixed_vec(prefix, input, &ty)
        .map_err(|diag| diag.emit())
        .unwrap_or_else(|_| quote!(vec![]));

    quote!({
        let __vector: Vec<#ty> = #vec;
        __vector
    }).into()
}

pub fn routes_macro(input: TokenStream) -> TokenStream {
    prefixed_vec(ROUTE_STRUCT_PREFIX, input, quote!(::rocket::Route))
}

pub fn catchers_macro(input: TokenStream) -> TokenStream {
    prefixed_vec(CATCH_STRUCT_PREFIX, input, quote!(::rocket::Catcher))
}

pub fn uri_macro(input: TokenStream) -> TokenStream {
    uri::_uri_macro(input)
        .map_err(|diag| diag.emit())
        .unwrap_or_else(|_| quote!(()).into())
}

pub fn uri_internal_macro(input: TokenStream) -> TokenStream {
    uri::_uri_internal_macro(input)
        .map_err(|diag| diag.emit())
        .unwrap_or_else(|_| quote!(()).into())
}

pub fn guide_tests_internal(input: TokenStream) -> TokenStream {
    test_guide::_macro(input)
        .map_err(|diag| diag.emit())
        .unwrap_or_else(|_| quote!(()).into())
}