How to import in a macro without conflicting?


#1

I have a macro that is exported by my crate and used by other crates. It needs certain items to be imported. However, we run into the following problem:

  • If the macro itself doesn’t import the items, we need to put the onus on the user to have these items already imported
  • If the macro imports the items itself, then if the user has already imported the same items, we get an error about the re-importing of an already-imported item

Is there a good way around this problem? To make it concrete, the macro in question is this one.


#2

I recently ran into this problem myself. The key is to use $crate.

https://doc.rust-lang.org/1.7.0/book/macros.html#the-variable-crate


#3

Ah, so the issue is that these items are not from my crate.

Technically I could probably do #[doc(hidden)] pub use other_crate::foo in my crate and then $crate::foo in my macro, but that seems like a whole lot of scaffolding just for this.


#4

You don’t have to import using use, you can just use the canonical path to the object.

So for example, if the object is a function called myfunc in a module called module in a crate called mycrate, then the path ::mycrate::module::myfunc will work anywhere (provided you have an extern crate mycrate).

This is often used in macros, because of exactly the problems you mention.

The $crate path (documented in the book) is actually for when you want to reference something in your own crate, and you don’t know how that crate is represented (within the crate it is nothing, outside it is the crate name). It’s a hack because macros 1.0 are cannot rewrite crate names to match the environment.


#5

I’m not exactly sure how to handle when someone does extern crate name_a as name_b.


#6

Oh, and one other problem: one of them is a trait that needs to be in scope since I use trait methods. So I can’t reference it directly (unless I want to do $crate::Trait::method(foo, ...) instead of foo.method(..), but that seems painful).