rocket_codegen/bang/
export.rs1use 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 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 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}