Skip to content

Commit 44b1365

Browse files
Add chapter for re-exports in the rustdoc book
1 parent a2ec5f8 commit 44b1365

File tree

3 files changed

+180
-1
lines changed

3 files changed

+180
-1
lines changed

src/doc/rustdoc/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- [How to write documentation](how-to-write-documentation.md)
88
- [What to include (and exclude)](write-documentation/what-to-include.md)
99
- [The `#[doc]` attribute](write-documentation/the-doc-attribute.md)
10+
- [Re-exports](write-documentation/re-exports.md)
1011
- [Linking to items by name](write-documentation/linking-to-items-by-name.md)
1112
- [Documentation tests](write-documentation/documentation-tests.md)
1213
- [Rustdoc-specific lints](lints.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Re-exports
2+
3+
Let's start by explaining what are re-exports. To do so, we will use an example where we are
4+
writing a library (named `lib`) with some types dispatched in sub-modules:
5+
6+
```rust
7+
pub mod sub_module1 {
8+
pub struct Foo;
9+
}
10+
pub mod sub_module2 {
11+
pub struct AnotherFoo;
12+
}
13+
```
14+
15+
Users can import them like this:
16+
17+
```rust,ignore (inline)
18+
use lib::sub_module1::Foo;
19+
use lib::sub_module2::AnotherFoo;
20+
```
21+
22+
But what if you want the types to be available directly at the crate root or if we don't want the
23+
modules to be visible for users? That's where re-exports come in:
24+
25+
```rust,ignore (inline)
26+
// `sub_module1` and `sub_module2` are not visible outside.
27+
mod sub_module1 {
28+
pub struct Foo;
29+
}
30+
mod sub_module2 {
31+
pub struct AnotherFoo;
32+
}
33+
// We re-export both types:
34+
pub use crate::sub_module1::Foo;
35+
pub use crate::sub_module2::AnotherFoo;
36+
```
37+
38+
And now users will be able to do:
39+
40+
```rust,ignore (inline)
41+
use lib::{Foo, AnotherFoo};
42+
```
43+
44+
And since both `sub_module1` and `sub_module2` are private, users won't be able to import them.
45+
46+
Now what's interesting is that the generated documentation for this crate will show both `Foo` and
47+
`AnotherFoo` directly at the crate root, meaning they have been inlined. There are a few rules to
48+
know whether or not a re-exported item will be inlined.
49+
50+
## Inlining rules
51+
52+
If a public item comes from a private module, it will be inlined:
53+
54+
```rust,ignore (inline)
55+
mod private_module {
56+
pub struct Public;
57+
}
58+
pub mod public_mod {
59+
// `Public` will inlined here since `private_module` is private.
60+
pub use super::private_module::Public;
61+
}
62+
// `Public` will not be inlined here since `public_mod` is public.
63+
pub use self::public_mod::Public;
64+
```
65+
66+
Likewise, if an item inherits `#[doc(hidden)]` from any of its ancestors, it will be inlined:
67+
68+
```rust,ignore (inline)
69+
#[doc(hidden)]
70+
pub mod public_mod {
71+
pub struct Public;
72+
}
73+
// `Public` be inlined since its parent (`public_mod`) has `#[doc(hidden)]`.
74+
pub use self::public_mod::Public;
75+
```
76+
77+
If an item has `#[doc(hidden)]`, it won't be inlined (nor visible in the generated documentation):
78+
79+
```rust,ignore (inline)
80+
// This struct won't be visible.
81+
#[doc(hidden)]
82+
pub struct Hidden;
83+
84+
// This re-export won't be visible.
85+
pub use self::Hidden as InlinedHidden;
86+
```
87+
88+
The same applies on re-exports themselves: if you have multiple re-exports and some of them have
89+
`#[doc(hidden)]`, then these ones (and only these) own't appear in the documentation:
90+
91+
```rust,ignore (inline)
92+
mod private_mod {
93+
/// First
94+
pub struct InPrivate;
95+
}
96+
97+
/// Second
98+
#[doc(hidden)]
99+
pub use self::private_mod::InPrivate as Hidden;
100+
/// Third
101+
pub use self::Hidden as Visible;
102+
```
103+
104+
In this case, `InPrivate` will be inlined as `Visible`. However, its documentation will be
105+
`First Third` and not `First Second Third` because the re-export with `Second` as documentation has
106+
`#[doc(hidden)]`, therefore, all its attributes are ignored.
107+
108+
## Inlining with `#[doc(inline)]`
109+
110+
You can use the `#[doc(inline)]` attribute if you want to force an item to be inlined:
111+
112+
```rust,ignore (inline)
113+
pub mod public_mod {
114+
pub struct Public;
115+
}
116+
#[doc(inline)]
117+
pub use self::public_mod::Public;
118+
```
119+
120+
With this code, even though `public_mod::Public` is public and present in the documentation, the
121+
`Public` type will be present both at the crate root and in the `public_mod` module.
122+
123+
## Preventing inlining with `#[doc(no_inline)]`
124+
125+
On the opposite of the `#[doc(inline)]` attribute, if you want to prevent an item from being
126+
inlined, you can use `#[doc(no_inline)]`:
127+
128+
```rust,ignore (inline)
129+
mod private_mod {
130+
pub struct Public;
131+
}
132+
#[doc(no_inline)]
133+
pub use self::private_mod::Public;
134+
```
135+
136+
In the generated documentation, you will see a re-export at the crate root and not the type
137+
directly.
138+
139+
## Attributes
140+
141+
When an item is inlined, its doc comments and most of its attributes will be inlined along with it:
142+
143+
```rust,ignore (inline)
144+
mod private_mod {
145+
/// First
146+
#[cfg(a)]
147+
pub struct InPrivate;
148+
/// Second
149+
#[cfg(b)]
150+
pub use self::InPrivate as Second;
151+
}
152+
153+
/// Third
154+
#[doc(inline)]
155+
#[cfg(c)]
156+
pub use self::private_mod::Second as Visible;
157+
```
158+
159+
In this case, `Visible` will have as documentation `First Second Third` and will also have as `cfg`:
160+
`#[cfg(a, b, c)]`.
161+
162+
[Intra-doc links](./linking-to-items-by-name.md) are resolved relative to where the doc comment is
163+
defined.
164+
165+
There are a few attributes which are not inlined though:
166+
* `#[doc(alias="")]`
167+
* `#[doc(inline)]`
168+
* `#[doc(no_inline)]`
169+
* `#[doc(hidden)]` (because the re-export itself and its attributes are ignored).
170+
171+
All other attributes are inherited when inlined, so that the documentation matches the behavior if
172+
the inlined item was directly defined at the spot where it's shown.

src/doc/rustdoc/src/write-documentation/the-doc-attribute.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,18 @@ Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
223223
One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
224224
not eagerly inline it as a module unless you add `#[doc(inline)]`.
225225

226+
If you want to know more about inlining rules, take a look at the
227+
[`re-exports` chapter](./re-exports.md).
228+
226229
### `hidden`
227230

228231
<span id="dochidden"></span>
229232

230233
Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
231-
the `strip-hidden` pass is removed.
234+
the `strip-hidden` pass is removed. Re-exported items where one of its ancestors has
235+
`#[doc(hidden)]` will be considered the same as private.
236+
237+
You can find more information in the [`re-exports` chapter](./re-exports.md).
232238

233239
### `alias`
234240

0 commit comments

Comments
 (0)