This is something that might be very specific to what we are doing in our codebase.
We currently use failure::Fail for deriving error boilerplate. The way we use it in our codebase is we re-export it from our own "error library API" (which provides few more bits that are typically used in our error handling).
So, our client code can then import everything through our API:
use our_errors::{Fail, SomeOtherThingy};
However, the way failure::Fail derive macro works, it generates references to failure crate, so we have to add it as a dependency to every crate that uses error handling (in addition to the dependency on our own error handling crate).
thiserror would have the same issue in our codebase: it uses this little thiserror::private::AsDynError;, which would require us to add thiserror dependency to all of our crates.
I'm not sure how useful that would be for thiserror in particular, but some procedural macros go extra mile to allow being abstracted away by other crates (for example inventory supports crate = xyz attribute for that purpose).
On one hand, thiserror is not really meant to be embedded in other crates, it doesn't look like this would be very useful. It's just us doing weird (and, maybe, wrong) things.
On the other hand, I feel that pretty much every procedural macro should be somehow abstracted away from its "runtime" crate, similar to how $crate works in macro_rules, just for the "hygiene" reasons, maybe (also, in case crate gets renamed, etc)?
However, maybe, it's not the job of the macros to provide that abstraction and instead the Rust procedural macros framework should have something similar to $crate attribute. Though, due to the dependency ordering, it's not quite clear how exactly that could work...? Maybe, by doing something like:
// re-export and bind `$crate` to `xyz` for this particular re-export of procedural macro. `self` could be used to indicate self crate -- which would work even if crate gets renamed via `Cargo.toml`.
#[crate = xyz]
pub use thiserror_impl::*;
This is something that might be very specific to what we are doing in our codebase.
We currently use
failure::Failfor deriving error boilerplate. The way we use it in our codebase is we re-export it from our own "error library API" (which provides few more bits that are typically used in our error handling).So, our client code can then import everything through our API:
However, the way
failure::Failderive macro works, it generates references tofailurecrate, so we have to add it as a dependency to every crate that uses error handling (in addition to the dependency on our own error handling crate).thiserrorwould have the same issue in our codebase: it uses this littlethiserror::private::AsDynError;, which would require us to addthiserrordependency to all of our crates.I'm not sure how useful that would be for
thiserrorin particular, but some procedural macros go extra mile to allow being abstracted away by other crates (for example inventory supportscrate = xyzattribute for that purpose).On one hand,
thiserroris not really meant to be embedded in other crates, it doesn't look like this would be very useful. It's just us doing weird (and, maybe, wrong) things.On the other hand, I feel that pretty much every procedural macro should be somehow abstracted away from its "runtime" crate, similar to how
$crateworks inmacro_rules, just for the "hygiene" reasons, maybe (also, in case crate gets renamed, etc)?However, maybe, it's not the job of the macros to provide that abstraction and instead the Rust procedural macros framework should have something similar to
$crateattribute. Though, due to the dependency ordering, it's not quite clear how exactly that could work...? Maybe, by doing something like: