When developing procedural macros, it's a common pattern that you need to access some accessory types or names from the related "runtime" crate. This is commonly done simply by assuming some fixed crate name. For example, in case of ref-cast, macros assumes that runtime crate will be ref_cast.
This works most of the time, however, it's not ideal (although, it's worth mentioning that 99% of the time it works exactly as designed):
- If runtime crate is renamed via
Cargo.tomlfor whatever reason, code will stop compiling:
# This will break `#[derive(Fail)]` functionality!
success = { package = "failure", version = "0.1.6" }
For macro_rules, there is a $crate metavariable which always points to the defining crate.
- Sometimes, there is a need to hide somebody's else procedural macro behind your own abstractions.
For example, here inventory crate is used inside gflags crate; inventory crate needs ctor crate and to avoid forcing everyone to have an explicit dependency on ctor, inventory re-exports ctor from inventory itself. However, when inventory is used internally by gflags, the inventory is no longer a direct dependency of gflags users so ::inventory::ctor will no longer compile. To solve that, inventory supports a special attribute telling it which prefix to use.
However, most of the procedural macros don't support anything like that since it's not anticipated that they are going to be used from other crates or that their "runtime" crates might be renamed.
Question
The question I have is if it would be possible to define some magic $crate metavariable, but for procedural macroses? So, every time procedural macro needs its dependencies it can generate code like:
quote! {
// We don't really know our "runtime" crate name, but that's okay!
use $crate::internal::SomeImportantTrait;
}
Here is how I think it might work. Oftentimes, procedural macroses are re-exported from the "runtime" crate, like this:
pub use ref_cast_impl::RefCast;
What if there was an attribute that would allow to change what $crate would expand via an attribute on a use statement. Like this:
// This would make `$crate` generated by `ref_cast_impl::RefCast` to be replaced by `ref_cell`
#[crate = ref_cell]
pub use ref_cast_impl::RefCast;
Or like this:
// This would make `$crate` generated by `ref_cast_impl::RefCast` to be replaced by whatever name this crate has in code where `derive(RefCell)` is used.
#[crate = crate]
pub use ref_cast_impl::RefCast;
Or even like this:
// Now I'm re-exporting it again, and this time I'm making the target macro to produce `<this crate>::ref_cast` in place of `$crate`!
#[crate = crate::ref_cast]
pub use ref_cell::OurRefCast;
// Re-export all ref_cast runtime needs so `OurRefCast` can reference them.
#[doc(hidden)]
pub use ref_cast;
And the default behavior could be #[crate = crate], i.e, when you re-export procedural macro, it's $crate is "bound" to the crate doing the re-exporting.
Is it possible? Does it make any sense?