(Meta: I've taken the liberty to reword a bit the thread's title to better take into account what the thread is about).
So, regarding the problem of namespacing a macro within a module, then indeed any non-pub
re-export written after the macro definition will achieve the desired effect, as I explained in this SO answer:
https://stackoverflow.com/a/67140319/10776437
That is, while you can't write:
//! Doesn't work!
mod a {
pub(…) macro_rules! name { … }
}
you can write:
mod a {
macro_rules! name { … }
pub(…) use name;
}
to achieve the same effect.
-
To be extra clear: this won't work with
pub
privacy, unless the macro is#[macro_export]
-ed (that is, without that annotation, the maximum visibility ofmacro_rules!
macros ispub(crate)
). -
Extra stuff to do if
name
collides with prelude attribute macros (e.g.,forbid
,deny
,warn
,allow
,test
)You must use a different name for the
macro_rules!
definition and then amend the name with the re-export:macro_rules! __warn__ { … } pub(…) use __warn__ as warn;
At that point, you have escaped the macro idiosyncrasies, and then you are back to a good old namespacing / re-exporting problem.
Answering the original thread's title / XY problem: quid of #[macro_export]
ed macros?
Sometimes we may need this behavior (that of namespacing a macro within a module) but for a fully pub
macro, since we just want to namespace a pub
lic / downstream-user-facing macro_rules!
macro.
In that case, for a macro_rules!
macro, annotating the macro with #[macro_export]
is necessary, and this will kind of magically perform a pub use path::to::that_macro;
at the root of the crate. So this, indeed, pollutes the top-level module of the crate with that macro.
There are two ways to palliate the issue:
-
The most robust but also cumbersome way is to involve an extra helper crate to perform the
#[macro_export]
s of those macros for use, and then we canpub use ::that_helper_crate::macro_name;
within the module of our choosing. It does involve an extra helper crate, and breaks$crate
, basically featuring the main drawbacks of procedural macros. -
Another approach is to
#[doc(hidden)]
-tag the macro, and mangle a bit the name, so that in practice it doesn't really pollute the top-level module:#[doc(hidden)] #[macro_export] macro_rules! __macro_name__ { … } #[doc(inline)] pub use __macro_name__ as macro_name;
Sadly,
#[doc(inline)]
is currently unable to override the original#[doc(hidden)]
, which makes this technique unusable in practice (I've already mentioned this issue to @jyn514 and @GuillaumeGomez: the fix is trivial to write, but whether#[doc(inline)]
ought to be able to override a#[doc(hidden)]
is a more debatable thing hence why I'm waiting on their green light).