Using a re-export in a macro

Hi, I have a crate (my-macro-crate) which exports a macro. This crate requires rust-embed and for convenience to crates that want to use this (my-dependee-crate) I want to re-export rust-embed for them. The problem is, how do I refer to the "re-exported" rust-embed in the macro itself?

So I have something like:
my-macro-crate/lib.rs:

#[macro_export]
macro_rules! mod_assets_static_handler {
    ($assets_path:literal) => {
        mod assets {
            use rust_embed::RustEmbed;
// <snip>
        }
   })
}

This obviously fails if the using crate doesn't also include rust-embed. So, for convenience, I want to re-export rust-embed. My question, is how do I refer to rust-embed in the macro so the using crate (my-dependee-crate) doesn't need to include it?:

  • use rust_embed::RustEmbed; still requires the my-dependee-crate to include rust-embed
  • use $crate::rust_embed::RustEmbed; didn't replace crate with the (possible alias) for the declaring (e.g. my-macro-crate) as I'd hoped so back to square one
  • use my-macro-crate::rust_embed::RustEmbed; doesn't work because my-dependee-crate has no idea what my-dependee-crate actually is, and it may be aliased.

I'm sort of throwing-spaghetti-at-the-wall coding with this. What am I missing? Is it just impossible to get macros to be able to refer to re-exports in the same crate as the macro?

What error were you getting? Because this should expand to ::my_macro_crate::rust_embed::RustEmbed when you call it from a foreign crate.

1 Like

Actually, I think I was thrown off by cargo expand not replacing $crate and the

#[derive($crate::rust_embed::RustEmbed)]
            #[folder = $assets_path]
            struct Assets;
// <snip>

fragment in my macro not using the qualified $crate::rust_embed::.. in generated code, but instead using rust_embed::...

So actually, I think I have my answer, if I've understood:

  • $crate is the right mechanism to refer to the (possible aliased) crate the macro is in, wrt to how the crate using it refers to the "macro" crate
  • there is no magic to influence how derive generates code, so making rust_embed refer to the crate's report (via use $create::rust_embed::self) is the magic needed here.

Thanks for your help (again!)

(for context):

I have in my-macro-crate/lib.rs: pub use rust_embed;
I have in `my-macro-crate/fileserver.rs:

#[macro_export]
macro_rules! mod_assets_static_handler {
    ($assets_path:literal) => {
        mod assets {

            use axum::{extract::Path, http::StatusCode, response::IntoResponse};

            #[derive($crate::rust_embed::RustEmbed)]
            #[folder = $assets_path]
            struct Assets;
// <snip>

I have in my-dependee-crate/main.rs:

// this is actually `my-macro-crate`
use nhg::web::mod_assets_static_handler;

// <snip>

// the macro
mod_assets_static_handler!("assets/public");

This cargo expands to:

// <snip>
use nhg::web::mod_assets_static_handler;

mod assets {
    use axum::{extract::Path, http::StatusCode, response::IntoResponse};
    #[folder = "assets/public"]
    struct Assets;
    #[cfg(debug_assertions)]
    impl Assets {
// NOTE: the qualified `rust_embed` generated by the `derive` in the macro
        fn matcher() -> rust_embed::utils::PathMatcher {
 
// <snip>

// again, unqualified
    impl rust_embed::RustEmbed for Assets {

// <snip>
}

Ah I see. The RustEmbed derive macro generates the faulty path, as the procedural macro does not know about the fact that the rust_embed crate is reƫxported from your crate. Derive macros need to be told explicitly if the crate they generate code for is aliased or reƫxported. This must be implemented by the macro itself though, there is no general machanism like $crate for procedural macros. Tokio's main macro supports renaming for example. I think RustEmbed has support for a renamed crate as well with the #[crate_path = "$crate::rust_embed"] attribute.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.