Expanding Inner Macros

I am trying to make a proc macro that needs to know the file/crate path to the caller at compile time.

The simplest example similar to what I am trying to do is hashing the module path. The hash_macro!() should be same if and only if they are called within the same module.

I tried to do something like:

#[proc_macro]
pub fn hashing_macro(_input: TokenStream) -> TokenStream {
    let mut hasher = std::hash::DefaultHasher::new();
    module_path!().hash(&mut hasher);
    line!().hash(&mut hasher);
    let hash = hasher.finish();

    quote! {
        #hash
    }.into()
}

but this didn't work, so I reluctantly tried a janky version that was more annoying

#[proc_macro]
pub fn jank_hashing_helper(input: TokenStream) -> TokenStream {
    let mut hasher = std::hash::DefaultHasher::new();
    input.to_string().hash(&mut hasher);
    let hash = hasher.finish();

    quote! {
        #hash
    }.into()
}
#[proc_macro]
pub fn jank_hashing_macro(_input: TokenStream) -> TokenStream {
    quote! {
        jank_hashing_helper!(module_path!())
    }.into()
}

and this one didn't work either.

I tested their values with the following script:

use my_macro_crate::{hashing_macro, jank_hashing_helper, jank_hashing_macro};

const HASH: u64 = hashing_macro!();
const JANK_HASH_HELPER: u64 = jank_hashing_helper!(module_path!());
const JANK_HASH: u64 = jank_hashing_macro!();

#[test]
fn print_hash() {
    dbg!(HASH);
    dbg!(JANK_HASH_HELPER);
    dbg!(JANK_HASH);
    dbg!(module_path!());
}

I ran this exact same script in two different testing files, one called module_a and the other called module_b.
This was the output for module_a:

[.../tests/module_a.rs:9:5] HASH = 17192937734722882082
[.../tests/module_a.rs:10:5] JANK_HASH_HELPER = 9961261794398595528
[.../tests/module_a.rs:11:5] JANK_HASH = 3029096996050824686
[.../tests/module_a.rs:12:5] module_path!() = "module_a"

This was the output for module_b:

[.../tests/module_b.rs:9:5] HASH = 17192937734722882082
[.../tests/module_b.rs:10:5] JANK_HASH_HELPER = 9961261794398595528
[.../tests/module_b.rs:11:5] JANK_HASH = 3029096996050824686
[.../tests/module_b.rs:12:5] module_path!() = "module_b"

The "module_path!()" are different, but all of my hashing attempts resulted in the same output for the two different modules.

Could I have some help with this?

(This is my first post, so if there are meta-comments, please let me know about that as well.)

Much thanks!

This results in jank_hashing_helper receiving the tokens module_path, !, (), which is why your hash would be the same every time. Macro expressions like that are evaluated starting from the outside.

macros are not "evaluated" (inner most arguments first) like functions, they are "expanded" (outer most macros first).

so, given the macro:

jank_hashing_helper!(module_path!())

the token stream given to jank_hashing_helper is the literal form module_path!(), i.e. an identifier module_path, followed by an exclamation mark !, followed by a pair of parenthesis. you will not be able to receive the expanded result of module_path!().

I'm not experienced with procedural macros, you can get the call site location via Span::call_site(), but I'm not sure how or whether you can get the module path.

I think there’s possibly simply no good way of writing your macro. I might of course be missing something here. There’s some unstable API that’s relevant… glancing at the relevant GitHub issue makes it sound like these APIs are adding new capabilities to the language.

I’d recommend you share some context though. Why are you writing a proc macro that needs to know file/crate path to the caller at compile time?

Yes, something like that is what I am looking for.

I wanted to send Packets over a unix socket, where every type that impl'd a Packet would have a unique const ID, which would be sent as the first 8 bytes of every packet message. If the receiver supports that packet, then it will parse it and do whatever it needs to with the packet. If the receiver doesn't support the packet, then it would just ignore it. I wanted a proc derive macro to automate the packet ID, which would change with the packet type's content, name, and the module it was defined in.
However, if accessing the module in the proc macro isn't supported, then I will just make a hash based off of the content and name.