From b358fa6a18e38559f753a34ece49e0a2cd6ab6bd Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <> Date: Mon, 9 Oct 2023 11:23:23 +0530 Subject: [PATCH 1/5] Adds ability to use provided ident verbatim for export --- core/src/lib.rs | 12 +++++++----- macros/src/lib.rs | 18 +++++++++++++----- src/lib.rs | 2 +- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 350855f..a7741d4 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -460,6 +460,7 @@ pub fn export_tokens_internal, E: Into>( attr: T, tokens: E, emit: bool, + hide_exported_ident: bool, ) -> Result { let attr = attr.into(); let item: Item = parse2(tokens.into())?; @@ -493,7 +494,7 @@ pub fn export_tokens_internal, E: Into>( None => parse2::(attr)?, }; let macro_ident = new_unique_export_tokens_ident(&ident); - let ident = export_tokens_macro_ident(&ident); + let ident = if hide_exported_ident { export_tokens_macro_ident(&ident) } else { ident }; let item_emit = match emit { true => quote! { #[allow(unused)] @@ -536,13 +537,14 @@ pub fn export_tokens_internal, E: Into>( pub fn export_tokens_alias_internal>( tokens: T, emit: bool, + hide_exported_ident: bool, ) -> Result { let alias = parse2::(tokens.into())?; let export_tokens_internal_path = macro_magic_path("e!(mm_core::export_tokens_internal)); Ok(quote! { #[proc_macro_attribute] pub fn #alias(attr: proc_macro::TokenStream, tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { - match #export_tokens_internal_path(attr, tokens, #emit) { + match #export_tokens_internal_path(attr, tokens, #emit, #hide_exported_ident) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } @@ -603,13 +605,13 @@ pub fn import_tokens_inner_internal>(tokens: T) -> Result< /// The internal implementation for the `forward_tokens` macro. /// /// You shouldn't need to call this in any circumstances but it is provided just in case. -pub fn forward_tokens_internal>(tokens: T) -> Result { +pub fn forward_tokens_internal>(tokens: T, hidden_source_path: bool) -> Result { let args = parse2::(tokens.into())?; let mm_path = match args.mm_path { Some(path) => path, None => macro_magic_root(), }; - let source_path = export_tokens_macro_path(&args.source); + let source_path = if hidden_source_path { export_tokens_macro_path(&args.source) } else { args.source }; let target_path = args.target; if let Some(extra) = args.extra { Ok(quote! { @@ -872,7 +874,7 @@ pub fn import_tokens_attr_internal, T2: Into return err.to_compile_error().into() }; quote::quote! { - #pound resolved_mm_override_path::forward_tokens! { + #pound resolved_mm_override_path::forward_tokens_verbatim! { #pound path, #orig_sig_ident, #pound resolved_mm_override_path, diff --git a/macros/src/lib.rs b/macros/src/lib.rs index e53012b..fbfb1cc 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -65,7 +65,7 @@ use proc_macro::TokenStream; /// private/inaccessible contexts, however this was removed in 0.4.x. #[proc_macro_attribute] pub fn export_tokens(attr: TokenStream, tokens: TokenStream) -> TokenStream { - match export_tokens_internal(attr, tokens, true) { + match export_tokens_internal(attr, tokens, true, true) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } @@ -78,7 +78,7 @@ pub fn export_tokens(attr: TokenStream, tokens: TokenStream) -> TokenStream { /// and/or do not need to be used locally. #[proc_macro_attribute] pub fn export_tokens_no_emit(attr: TokenStream, tokens: TokenStream) -> TokenStream { - match export_tokens_internal(attr, tokens, false) { + match export_tokens_internal(attr, tokens, false, true) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } @@ -93,7 +93,7 @@ pub fn export_tokens_no_emit(attr: TokenStream, tokens: TokenStream) -> TokenStr /// Can only be used within a proc macro crate. #[proc_macro] pub fn export_tokens_alias(tokens: TokenStream) -> TokenStream { - match export_tokens_alias_internal(tokens, true) { + match export_tokens_alias_internal(tokens, true, true) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } @@ -105,7 +105,7 @@ pub fn export_tokens_alias(tokens: TokenStream) -> TokenStream { /// Can only be used within a proc macro crate. #[proc_macro] pub fn export_tokens_alias_no_emit(tokens: TokenStream) -> TokenStream { - match export_tokens_alias_internal(tokens, false) { + match export_tokens_alias_internal(tokens, false, true) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } @@ -140,7 +140,15 @@ pub fn export_tokens_alias_no_emit(tokens: TokenStream) -> TokenStream { /// ``` #[proc_macro] pub fn forward_tokens(tokens: TokenStream) -> TokenStream { - match forward_tokens_internal(tokens) { + match forward_tokens_internal(tokens, true) { + Ok(tokens) => tokens.into(), + Err(err) => err.to_compile_error().into(), + } +} + +#[proc_macro] +pub fn forward_tokens_verbatim(tokens: TokenStream) -> TokenStream { + match forward_tokens_internal(tokens, false) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } diff --git a/src/lib.rs b/src/lib.rs index 11e21a0..feea47f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,7 +76,7 @@ pub mod mm_core { } pub use macro_magic_macros::{ - export_tokens, export_tokens_alias, export_tokens_no_emit, forward_tokens, use_attr, use_proc, + export_tokens, export_tokens_alias, export_tokens_no_emit, forward_tokens, forward_tokens_verbatim, use_attr, use_proc, }; #[cfg(feature = "proc_support")] From 3d02187803f263aa42a80fd53bb41034cb05078a Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <> Date: Mon, 9 Oct 2023 12:10:33 +0530 Subject: [PATCH 2/5] Supports both in import_attr --- core/src/lib.rs | 38 +++++++++++++++++++++++++++----------- macros/src/lib.rs | 10 +++++++++- src/lib.rs | 2 +- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index a7741d4..4d832f5 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -777,6 +777,7 @@ impl ToTokens for OverridePath { pub fn import_tokens_attr_internal, T2: Into>( attr: T1, tokens: T2, + hidden_source_path: bool, ) -> Result { let attr = attr.into(); let mm_override_path = parse2::(attr)?; @@ -873,18 +874,33 @@ pub fn import_tokens_attr_internal, T2: Into res, Err(err) => return err.to_compile_error().into() }; - quote::quote! { - #pound resolved_mm_override_path::forward_tokens_verbatim! { - #pound path, - #orig_sig_ident, - #pound resolved_mm_override_path, - { - { #pound attached_item }, - { #pound path }, - { #pound custom_parsed } + if #hidden_source_path { + quote::quote! { + #pound resolved_mm_override_path::forward_tokens! { + #pound path, + #orig_sig_ident, + #pound resolved_mm_override_path, + { + { #pound attached_item }, + { #pound path }, + { #pound custom_parsed } + } } - } - }.into() + }.into() + } else { + quote::quote! { + #pound resolved_mm_override_path::forward_tokens_verbatim! { + #pound path, + #orig_sig_ident, + #pound resolved_mm_override_path, + { + { #pound attached_item }, + { #pound path }, + { #pound custom_parsed } + } + } + }.into() + } } } }; diff --git a/macros/src/lib.rs b/macros/src/lib.rs index fbfb1cc..fffceb2 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -395,7 +395,15 @@ pub fn import_tokens_proc(attr: TokenStream, tokens: TokenStream) -> TokenStream /// For more information and an example see [`macro@with_custom_parsing`]. #[proc_macro_attribute] pub fn import_tokens_attr(attr: TokenStream, tokens: TokenStream) -> TokenStream { - match import_tokens_attr_internal(attr, tokens) { + match import_tokens_attr_internal(attr, tokens, true) { + Ok(tokens) => tokens.into(), + Err(err) => err.to_compile_error().into(), + } +} + +#[proc_macro_attribute] +pub fn import_tokens_attr_verbatim(attr: TokenStream, tokens: TokenStream) -> TokenStream { + match import_tokens_attr_internal(attr, tokens, false) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } diff --git a/src/lib.rs b/src/lib.rs index feea47f..b4cdde6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ pub use macro_magic_macros::{ #[cfg(feature = "proc_support")] pub use macro_magic_macros::{ - import_tokens, import_tokens_attr, import_tokens_proc, with_custom_parsing, + import_tokens, import_tokens_attr, import_tokens_attr_verbatim, import_tokens_proc, with_custom_parsing, }; /// Contains re-exports required at compile-time by the macro_magic macros and support From d0ef91fe3c6c5b254086b9c0959f2fa7a81c4297 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <> Date: Tue, 10 Oct 2023 10:16:16 +0530 Subject: [PATCH 3/5] Fixes tests --- core/src/lib.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 4d832f5..0c447bb 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -999,7 +999,7 @@ mod tests { #[test] fn export_tokens_internal_missing_ident() { assert!( - export_tokens_internal(quote!(), quote!(impl MyTrait for Something), true).is_err() + export_tokens_internal(quote!(), quote!(impl MyTrait for Something), true, true).is_err() ); } @@ -1010,6 +1010,7 @@ mod tests { quote!( struct MyStruct {} ), + true, true ) .unwrap() @@ -1025,6 +1026,7 @@ mod tests { struct Something {} ), true, + true ) .unwrap() .to_string() @@ -1039,6 +1041,7 @@ mod tests { struct MyStruct {} ), true, + true ) .unwrap() .to_string() @@ -1053,6 +1056,7 @@ mod tests { struct MyStruct {} ), true, + true ) .is_err()); assert!(export_tokens_internal( @@ -1061,6 +1065,7 @@ mod tests { struct MyStruct {} ), true, + true ) .is_err()); } @@ -1073,12 +1078,28 @@ mod tests { struct Something {} ), false, + true ) .unwrap() .to_string() .contains("some_name")); } + #[test] + fn export_tokens_internal_verbatim_ident() { + assert!(export_tokens_internal( + quote!(), + quote!( + struct MyStruct {} + ), + true, + false + ) + .unwrap() + .to_string() + .contains("MyStruct")); + } + #[test] fn import_tokens_internal_simple_path() { assert!( From ad2ea4500133b85a31173a6010f8a8db7e96dd6b Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <> Date: Tue, 10 Oct 2023 10:18:41 +0530 Subject: [PATCH 4/5] fmt --- core/src/lib.rs | 29 ++++++++++++++++++++++------- src/lib.rs | 6 ++++-- tests/test_macros/src/lib.rs | 18 ++++++++++++------ 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 0c447bb..c2bce85 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -258,7 +258,9 @@ impl ProcMacro { /// Constructs a [`ProcMacro`] from anything compatible with [`TokenStream2`]. pub fn from>(tokens: T) -> Result { let proc_fn = parse2::(tokens.into())?; - let Visibility::Public(_) = proc_fn.vis else { return Err(Error::new(proc_fn.vis.span(), "Visibility must be public")) }; + let Visibility::Public(_) = proc_fn.vis else { + return Err(Error::new(proc_fn.vis.span(), "Visibility must be public")); + }; let mut macro_type: Option = None; if proc_fn .attrs @@ -431,8 +433,9 @@ pub fn export_tokens_macro_ident(ident: &Ident) -> Ident { /// on the item at that path, the returned macro path will be invalid. pub fn export_tokens_macro_path(item_path: &Path) -> Path { let mut macro_path = item_path.clone(); - let Some(last_seg) = macro_path.segments.pop() - else { unreachable!("must have at least one segment") }; + let Some(last_seg) = macro_path.segments.pop() else { + unreachable!("must have at least one segment") + }; let last_seg = export_tokens_macro_ident(&last_seg.into_value().ident); macro_path.segments.push(last_seg.into()); macro_path @@ -494,7 +497,11 @@ pub fn export_tokens_internal, E: Into>( None => parse2::(attr)?, }; let macro_ident = new_unique_export_tokens_ident(&ident); - let ident = if hide_exported_ident { export_tokens_macro_ident(&ident) } else { ident }; + let ident = if hide_exported_ident { + export_tokens_macro_ident(&ident) + } else { + ident + }; let item_emit = match emit { true => quote! { #[allow(unused)] @@ -605,13 +612,20 @@ pub fn import_tokens_inner_internal>(tokens: T) -> Result< /// The internal implementation for the `forward_tokens` macro. /// /// You shouldn't need to call this in any circumstances but it is provided just in case. -pub fn forward_tokens_internal>(tokens: T, hidden_source_path: bool) -> Result { +pub fn forward_tokens_internal>( + tokens: T, + hidden_source_path: bool, +) -> Result { let args = parse2::(tokens.into())?; let mm_path = match args.mm_path { Some(path) => path, None => macro_magic_root(), }; - let source_path = if hidden_source_path { export_tokens_macro_path(&args.source) } else { args.source }; + let source_path = if hidden_source_path { + export_tokens_macro_path(&args.source) + } else { + args.source + }; let target_path = args.target; if let Some(extra) = args.extra { Ok(quote! { @@ -999,7 +1013,8 @@ mod tests { #[test] fn export_tokens_internal_missing_ident() { assert!( - export_tokens_internal(quote!(), quote!(impl MyTrait for Something), true, true).is_err() + export_tokens_internal(quote!(), quote!(impl MyTrait for Something), true, true) + .is_err() ); } diff --git a/src/lib.rs b/src/lib.rs index b4cdde6..03a4c20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,12 +76,14 @@ pub mod mm_core { } pub use macro_magic_macros::{ - export_tokens, export_tokens_alias, export_tokens_no_emit, forward_tokens, forward_tokens_verbatim, use_attr, use_proc, + export_tokens, export_tokens_alias, export_tokens_no_emit, forward_tokens, + forward_tokens_verbatim, use_attr, use_proc, }; #[cfg(feature = "proc_support")] pub use macro_magic_macros::{ - import_tokens, import_tokens_attr, import_tokens_attr_verbatim, import_tokens_proc, with_custom_parsing, + import_tokens, import_tokens_attr, import_tokens_attr_verbatim, import_tokens_proc, + with_custom_parsing, }; /// Contains re-exports required at compile-time by the macro_magic macros and support diff --git a/tests/test_macros/src/lib.rs b/tests/test_macros/src/lib.rs index 02f2a89..c72fcee 100644 --- a/tests/test_macros/src/lib.rs +++ b/tests/test_macros/src/lib.rs @@ -266,14 +266,18 @@ pub fn combine_structs(attr: TokenStream, tokens: TokenStream) -> TokenStream { let Fields::Named(local_fields) = local_struct.fields else { return Error::new( local_struct.fields.span(), - "unnamed fields are not supported" - ).to_compile_error().into() + "unnamed fields are not supported", + ) + .to_compile_error() + .into(); }; let Fields::Named(foreign_fields) = foreign_struct.fields else { return Error::new( foreign_struct.fields.span(), - "unnamed fields are not supported" - ).to_compile_error().into() + "unnamed fields are not supported", + ) + .to_compile_error() + .into(); }; let local_fields = local_fields.named.iter(); let foreign_fields = foreign_fields.named.iter(); @@ -303,8 +307,10 @@ pub fn require(tokens: TokenStream) -> TokenStream { return Error::new( external_mod.span(), "cannot import tokens from a file-based module since custom file-level \ - attributes are not yet supported by Rust" - ).to_compile_error().into() + attributes are not yet supported by Rust", + ) + .to_compile_error() + .into(); }; quote! { #(#stmts) From e23ca501a5196babc3070fd78ae5b1c0a323e308 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <> Date: Tue, 10 Oct 2023 10:25:46 +0530 Subject: [PATCH 5/5] Adds a note regarding the new var --- core/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/lib.rs b/core/src/lib.rs index c2bce85..84e3a4f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -459,6 +459,9 @@ fn new_unique_export_tokens_ident(ident: &Ident) -> Ident { /// all require `attr` to be specified. /// /// An empty [`TokenStream2`] is sufficient for opting out of using `attr` +/// +/// The `hide_exported_ident` variable specifies whether the macro uses an auto-generated name +/// via [`export_tokens_macro_ident`] or the name of the item itself. pub fn export_tokens_internal, E: Into>( attr: T, tokens: E,