Search code examples
rustmacrosalloc

Refer to an extern crate in macro expansion


I'm trying to write some macros that work in nostd environment as well as in std environment. In order to do so I have this kind of code in proc macro crate:

#[cfg(not(feature = "alloc"))]
{
    quote!(err.message = Some(::std::borrow::Cow::from(#m));)
}
#[cfg(feature = "alloc")]
{
    quote!(err.message = Some(::alloc::borrow::Cow::from(#m));)
}

This correctly produces the code that uses alloc when alloc feature is enabled, but the compiler complains

error[E0433]: failed to resolve: could not find `alloc` in the list of imported crates

Of course the reason is that the macro expansion is missing

extern crate alloc;

But adding that is a problem. Since it's a procedural derive macro, the extern crate will be added on each derive call. How can I refer to an extern crate in macro expansion? Using $crate does not seem to work inside quote!.


Solution

  • You can wrap the expansion in a block, then you can define alloc multiple times.

    Another common practice for proc macros that need auxiliary types is to create a crate that provides them, and reexport the macro from it. E.g. create mycrate and mycrate-macros. Then you can get rid of the whole alloc feature if you only need alloc-accessible types, like:

    #![no_std]
    
    extern crate alloc;
    
    #[doc(inline)]
    pub use mycrate_macros::my_macro;
    
    #[doc(hidden)]
    pub use alloc:borrow::Cow;
    

    Then in the macro refer to ::my_crate::Cow.