rocket_codegen/bang/
export.rs

1use std::hash::Hash;
2
3use devise::Spanned;
4use devise::ext::SpanDiagnosticExt;
5use proc_macro2::{TokenStream, TokenTree, Punct};
6
7use crate::syn_ext::IdentExt;
8
9pub fn _macro(input: proc_macro::TokenStream) -> devise::Result<TokenStream> {
10    let mac: syn::ItemMacro = syn::parse(input)?;
11    let macro_name = match mac.ident {
12        Some(ident) => ident,
13        None => return Err(mac.span().error("expected `macro_rules!`")),
14    };
15
16    // We rename the actual `macro_export` macro so we don't accidentally use it
17    // internally from the auto-imported crate root macro namespace.
18    let (attrs, def) = (mac.attrs, mac.mac);
19    let internal_name = macro_name.prepend("___internal_");
20    let mod_name = macro_name.uniqueify_with(|mut hasher| def.hash(&mut hasher));
21
22    let macro_rules_tokens = def.tokens.clone();
23    let decl_macro_tokens: TokenStream = def.tokens.into_iter()
24        .map(|t| match t {
25            TokenTree::Punct(p) if p.as_char() == ';' => {
26                let mut token = Punct::new(',', p.spacing());
27                token.set_span(p.span());
28                TokenTree::Punct(token)
29            },
30            _ => t,
31        })
32        .collect();
33
34    // Only try using the `macro` syntax on nightly/dev or when we don't know.
35    let export = match version_check::is_feature_flaggable() {
36        Some(true) | None => quote! {
37            #(#attrs)*
38            #[cfg(all(nightly, doc))]
39            pub macro #macro_name {
40                #decl_macro_tokens
41            }
42
43            #[cfg(not(all(nightly, doc)))]
44            pub use #mod_name::#internal_name as #macro_name;
45        },
46        Some(false) => quote! {
47            pub use #mod_name::#internal_name as #macro_name;
48        }
49    };
50
51    Ok(quote! {
52        #[allow(non_snake_case)]
53        mod #mod_name {
54            #[doc(hidden)]
55            #[macro_export]
56            macro_rules! #internal_name {
57                #macro_rules_tokens
58            }
59
60            pub use #internal_name;
61        }
62
63        #export
64    })
65}