Rocket/core/codegen/src/bang/mod.rs

80 lines
2.4 KiB
Rust

use devise::Result;
use crate::syn_ext::IdentExt;
use crate::syn::{Path, punctuated::Punctuated, parse::Parser, Token};
use crate::syn::spanned::Spanned;
use crate::proc_macro2::TokenStream;
use crate::{ROUTE_STRUCT_PREFIX, CATCH_STRUCT_PREFIX};
mod uri;
mod uri_parsing;
mod test_guide;
pub fn prefix_last_segment(path: &mut Path, prefix: &str) {
let mut last_seg = path.segments.last_mut().expect("syn::Path has segments");
last_seg.ident = last_seg.ident.prepend(prefix);
}
fn _prefixed_vec(
prefix: &str,
input: proc_macro::TokenStream,
ty: &TokenStream
) -> Result<TokenStream> {
// Parse a comma-separated list of paths.
let mut paths = <Punctuated<Path, Token![,]>>::parse_terminated.parse(input)?;
// 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: proc_macro::TokenStream,
ty: TokenStream
) -> TokenStream {
define_vars_and_mods!(_Vec);
_prefixed_vec(prefix, input, &ty)
.map(|vec| quote!({
let __vector: #_Vec<#ty> = #vec;
__vector
}))
.unwrap_or_else(|diag| {
let diag_tokens = diag.emit_as_expr_tokens();
quote!({
#diag_tokens
let __vec: #_Vec<#ty> = vec![];
__vec
})
})
}
pub fn routes_macro(input: proc_macro::TokenStream) -> TokenStream {
prefixed_vec(ROUTE_STRUCT_PREFIX, input, quote!(::rocket::Route))
}
pub fn catchers_macro(input: proc_macro::TokenStream) -> TokenStream {
prefixed_vec(CATCH_STRUCT_PREFIX, input, quote!(::rocket::Catcher))
}
pub fn uri_macro(input: proc_macro::TokenStream) -> TokenStream {
uri::_uri_macro(input.into())
.unwrap_or_else(|diag| diag.emit_as_expr_tokens())
}
pub fn uri_internal_macro(input: proc_macro::TokenStream) -> TokenStream {
let tokens = uri::_uri_internal_macro(input.into())
.unwrap_or_else(|diag| diag.emit_as_expr_tokens());
tokens
}
pub fn guide_tests_internal(input: proc_macro::TokenStream) -> TokenStream {
test_guide::_macro(input)
.unwrap_or_else(|diag| diag.emit_as_item_tokens())
}