I have a proc-macro that also exposes some types, so I'm using the following crate structure:
foo_core exports FooTraitfoo_macro (depends on foo_core) exports foo_macro, which generates some structs that implement FooTraitfoo (depends on foo_core and foo_macro) re-exports FooTrait and foo_macroThe problem I'm running into is that re-exporting foo_core changes it's path.
foo_macro generates code that looks roughly like:
struct Bar;
impl ::foo_core::FooTrait for Bar {
// ...
}
I have a bunch of trybuild tests in foo_macro which pass, since foo_core is an available crate.
The problem is when I try to write tests in foo (or in crates that depend on foo only), I get the error telling me it can't find the crate foo_core.
This makes some sense to me; the consumer of foo hasn't explicitly depended on foo_core, but I'd like it if users of my crate didn't have to add foo and foo_core (and make sure the versions match), instead I'd like them to be able to add just foo and it would work.
Currently, I can access foo_core via foo::foo_core::FooTrait, but obviously this is different to how my macro generates the code (::foo_core::FooTrait). Is there a way to make foo re-export the entire foo_core crate?
If that's not possible, what's the best way of going about this pattern? Can I somehow make foo_macro change its behaviour depending on what crate it's defined in? Or should I just move all my tests to foo instead of foo_macro?
Is there a way to have a public trait in a proc-macro crate? An answer to this question mentions this problem, but simply says "you must use the fully-qualified names", but my understanding was that this is what the leading :: on the path means.
This seems like a relatively common pattern, so I'm hoping there's a nice solution out there.
In your foo crate, you can completely reexport foo_core with either:
pub extern crate foo_core;pub use foo_core;With either of those statements, all of foo_core can be accessed through foo::foo_core:: when only having foo in the [dependencies] section of your Cargo.toml. Your proc macro would emit ::foo::foo_core:: paths then. This of course requires that users don't use foo_macro and foo_core directly. But this is common: usually, people are not supposed to use the macro crate directly, but only the "top level crate".
This is a common pattern, not only with your own crates. For example, in one of my libraries, my proc macro generates call to serde functions (not my library). So I pub use serde; in my crate so that users of my library don't have to depend on serde directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With