Add chapter for re-exports in the rustdoc book

This commit is contained in:
Guillaume Gomez 2023-06-05 11:03:01 +02:00
parent a2ec5f8a77
commit 44b1365885
3 changed files with 180 additions and 1 deletions

View File

@ -7,6 +7,7 @@
- [How to write documentation](how-to-write-documentation.md)
- [What to include (and exclude)](write-documentation/what-to-include.md)
- [The `#[doc]` attribute](write-documentation/the-doc-attribute.md)
- [Re-exports](write-documentation/re-exports.md)
- [Linking to items by name](write-documentation/linking-to-items-by-name.md)
- [Documentation tests](write-documentation/documentation-tests.md)
- [Rustdoc-specific lints](lints.md)

View File

@ -0,0 +1,172 @@
# Re-exports
Let's start by explaining what are re-exports. To do so, we will use an example where we are
writing a library (named `lib`) with some types dispatched in sub-modules:
```rust
pub mod sub_module1 {
pub struct Foo;
}
pub mod sub_module2 {
pub struct AnotherFoo;
}
```
Users can import them like this:
```rust,ignore (inline)
use lib::sub_module1::Foo;
use lib::sub_module2::AnotherFoo;
```
But what if you want the types to be available directly at the crate root or if we don't want the
modules to be visible for users? That's where re-exports come in:
```rust,ignore (inline)
// `sub_module1` and `sub_module2` are not visible outside.
mod sub_module1 {
pub struct Foo;
}
mod sub_module2 {
pub struct AnotherFoo;
}
// We re-export both types:
pub use crate::sub_module1::Foo;
pub use crate::sub_module2::AnotherFoo;
```
And now users will be able to do:
```rust,ignore (inline)
use lib::{Foo, AnotherFoo};
```
And since both `sub_module1` and `sub_module2` are private, users won't be able to import them.
Now what's interesting is that the generated documentation for this crate will show both `Foo` and
`AnotherFoo` directly at the crate root, meaning they have been inlined. There are a few rules to
know whether or not a re-exported item will be inlined.
## Inlining rules
If a public item comes from a private module, it will be inlined:
```rust,ignore (inline)
mod private_module {
pub struct Public;
}
pub mod public_mod {
// `Public` will inlined here since `private_module` is private.
pub use super::private_module::Public;
}
// `Public` will not be inlined here since `public_mod` is public.
pub use self::public_mod::Public;
```
Likewise, if an item inherits `#[doc(hidden)]` from any of its ancestors, it will be inlined:
```rust,ignore (inline)
#[doc(hidden)]
pub mod public_mod {
pub struct Public;
}
// `Public` be inlined since its parent (`public_mod`) has `#[doc(hidden)]`.
pub use self::public_mod::Public;
```
If an item has `#[doc(hidden)]`, it won't be inlined (nor visible in the generated documentation):
```rust,ignore (inline)
// This struct won't be visible.
#[doc(hidden)]
pub struct Hidden;
// This re-export won't be visible.
pub use self::Hidden as InlinedHidden;
```
The same applies on re-exports themselves: if you have multiple re-exports and some of them have
`#[doc(hidden)]`, then these ones (and only these) own't appear in the documentation:
```rust,ignore (inline)
mod private_mod {
/// First
pub struct InPrivate;
}
/// Second
#[doc(hidden)]
pub use self::private_mod::InPrivate as Hidden;
/// Third
pub use self::Hidden as Visible;
```
In this case, `InPrivate` will be inlined as `Visible`. However, its documentation will be
`First Third` and not `First Second Third` because the re-export with `Second` as documentation has
`#[doc(hidden)]`, therefore, all its attributes are ignored.
## Inlining with `#[doc(inline)]`
You can use the `#[doc(inline)]` attribute if you want to force an item to be inlined:
```rust,ignore (inline)
pub mod public_mod {
pub struct Public;
}
#[doc(inline)]
pub use self::public_mod::Public;
```
With this code, even though `public_mod::Public` is public and present in the documentation, the
`Public` type will be present both at the crate root and in the `public_mod` module.
## Preventing inlining with `#[doc(no_inline)]`
On the opposite of the `#[doc(inline)]` attribute, if you want to prevent an item from being
inlined, you can use `#[doc(no_inline)]`:
```rust,ignore (inline)
mod private_mod {
pub struct Public;
}
#[doc(no_inline)]
pub use self::private_mod::Public;
```
In the generated documentation, you will see a re-export at the crate root and not the type
directly.
## Attributes
When an item is inlined, its doc comments and most of its attributes will be inlined along with it:
```rust,ignore (inline)
mod private_mod {
/// First
#[cfg(a)]
pub struct InPrivate;
/// Second
#[cfg(b)]
pub use self::InPrivate as Second;
}
/// Third
#[doc(inline)]
#[cfg(c)]
pub use self::private_mod::Second as Visible;
```
In this case, `Visible` will have as documentation `First Second Third` and will also have as `cfg`:
`#[cfg(a, b, c)]`.
[Intra-doc links](./linking-to-items-by-name.md) are resolved relative to where the doc comment is
defined.
There are a few attributes which are not inlined though:
* `#[doc(alias="")]`
* `#[doc(inline)]`
* `#[doc(no_inline)]`
* `#[doc(hidden)]` (because the re-export itself and its attributes are ignored).
All other attributes are inherited when inlined, so that the documentation matches the behavior if
the inlined item was directly defined at the spot where it's shown.

View File

@ -223,12 +223,18 @@ Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
not eagerly inline it as a module unless you add `#[doc(inline)]`.
If you want to know more about inlining rules, take a look at the
[`re-exports` chapter](./re-exports.md).
### `hidden`
<span id="dochidden"></span>
Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
the `strip-hidden` pass is removed.
the `strip-hidden` pass is removed. Re-exported items where one of its ancestors has
`#[doc(hidden)]` will be considered the same as private.
You can find more information in the [`re-exports` chapter](./re-exports.md).
### `alias`