However, this is not as robust as I would like, since it assumes that the user didn't rename the crate my_crate to something else in their Cargo.toml. Also, I can't use this macro in tests within my_crate, since I should instead write ::crate::{MyTrait, MyType} in this situation.
Another solution is to write only MyTrait and MyType, but then the users need to import all the types that MyTrait uses (which in my case is a lot), so this isn't acceptable either.
I like how tokio solves this with an attribute: main in tokio - Rust. But my honest opinion would be not to worry too much about it and only add it once someone raises an issue requesting such a feature.
There's unfortunately no perfect solution yet. The typical solution is to hardcode absolute paths that assume the runtime crate is a direct dependency and not renamed, as well as offer an optional helper attribute that specifies a non-default path to the crate.
For function like proc macros specifically, you can make a macro_rules! wrapper which provides a $crate token, but there's no such way to wrap derive or attribute macros.
For this there's a niche feature that you can write extern crate self as my_crate, which will allow you to use ::my_crate in addition to ::crate.
Thank you to both of you; I wish I could set both as "Solution", since I used both of your answers as part of my current implementation!
I ended up
not worrying about crate renaming for now - I can always use the tokio trick if ever someone requests it
combine the extern crate self as my_crate trick with further inspiration from serde
I added an extra helper attribute to my derive macro called #[mock] (undocumented in the public docs of my library). I use it to indicate to my macro that it is being used in the context of my crate. Then, I either generate
// When not in my crate
const (): _ = {
extern crate my_crate as _my_crate;
// .. my stuff, with all paths starting with _my_crate
};
// When in my crate (#[mock] is present)
const (): _ = {
extern crate self as _my_crate;
// .. my stuff, with all paths starting with _my_crate
};
I got this idea from serde. The advantage here is that my whole implementation simply uses paths that start with _my_crate::, without needing to care if we're in my crate or not.
A perhaps simpler alternative would be just add extern crate self as my_crate (and use my_crate:: paths everywhere) - which I believe is what @CAD97 was suggesting - but my guess is that dtolnay saw that this created some name clashes sometimes, and hence preferred to create a new symbol (without polluting the global namespace)? In any case, it works now, thank you!
just want to add, there's already effort to solve this problem, but not a definite conclusion yet. there's proposal to use cargo (with an added section for the Cargo.toml manifest such as [runtime-dependencies] or [macro-dependencies]) to resolve and unify the crate, there's also proposal to add hygiene context in proc macros similar to declarative macros. you can check the discussion here
Got it. I removed the extra const (): _ stuff, and now I simply add extern crate self as my_crate when the macro is used within my_crate, as you suggested.