Description
Suppose our main crate foo
defines a trait Foo
. Now we want to write a derive(Foo)
proc macro (or any other kind of proc macro which emits code using Foo
). We define that proc macro in the foo-macro
crate. Our main crate foo
wants to rexport the proc macro so that users only have to depend on foo
.
The code for this example:
Cargo.toml
[package]
name = "foo"
[dependencies]
foo-macro = { path = "foo-macro" }
src/lib.rs
pub use foo_macro::Foo;
trait Foo {}
foo-macro/Cargo.toml
[package]
name = "foo-macro"
foo-macro/src/lib.rs
#[proc_macro_derive(Foo)]
fn derive_foo(_: TokenStream) -> TokenStream {
// ...
quote! { impl foo::Foo for #name {} }
}
The question is now: how to document the custom derive in a way such that cargo test
can test included example code?. I don't think it's currently possible.
If we document the function derive_foo
in the proc macro crate, we have to make all examples ignore
because they cannot be compiled, because compiling them would require using the foo
crate. But this leads to a cyclic dependency (not even dev-dependencies
works). foo-macros
cannot depend on foo
.
But we also can't document the reexport (that documentation is ignored/not shown). So it's not possible to write the documentation in the foo
crate either. As a consequence, we don't have checked documentation tests -- which probably leads to stale and incorrect example code.
Now I can think of three workarounds:
- Add
#[cfg(not(rustdoc))]
to the reexport, and add some other item with#[cfg(rustdoc)]
and the actual documentation to yourfoo
crate. That way, the reexport doesn't happen when rustdoc generates the documentation and instead renders the other dummy item with the correct documentation. For function like proc macros, it might be fine to have amacro_rules
macro as dummy item, but for other kinds of proc macros, this... absolutely not nice. - Add a feature to your main
foo
crate (likeno_macro_reexport
). When that feature is activated, your main crate does not reexport macros and does not depend on thefoo-macro
crate. Now thefoo-macro
crate can depend onfoo
viadev-dependencies
and activate thatno_macro_reexport
feature. That prevents the cyclic dependency. But now your main crate has a feature that should be implementation detail and you often have to build your main crate twice. - Just don't bother and document your proc macros somewhere else (e.g. how
serde
does it). I don't think that's a good solution at all: rustdoc should be able to also properly document proc macros.
So neither of these workarounds is particularly nice. I guess it's clear that there should be some kind of solution to this.
Potentially related: