Documentation
First Sentence is One Line; Approx. 15 Words (M-FIRST-DOC-SENTENCE)
When you document your item, the first sentence becomes the "summary sentence" that is extracted and shown in the module summary:
#![allow(unused)] fn main() { /// This is the summary sentence, shown in the module summary. /// /// This is other documentation. It is only shown in that item's detail view. /// Sentences here can be as long as you like and it won't cause any issues. fn some_item() { } }
Since Rust API documentation is rendered with a fixed max width, there is a naturally preferred sentence length you should not exceed to keep things tidy on most screens.
If you keep things in a line, your docs will become easily skimmable. Compare, for example, the standard library:
Otherwise, you might end up with widows and a generally unpleasant reading flow:
As a rule of thumb, the first sentence should not exceed 15 words.
Has Comprehensive Module Documentation (M-MODULE-DOCS)
Any public library module must have //!
module documentation, and the first sentence must follow M-DOC-FIRST-SENTENCE.
pub mod ffi {
//! Contains FFI abstractions.
pub struct String {};
}
The rest of the module documentation should be comprehensive, i.e., cover the most relevant technical aspects of the contained items, including
- what the module contains
- when it should be used, possibly when not
- examples
- subsystem specifications (e.g.,
std::fmt
also describes its formatting language) - observable side effects, including what guarantees are made about these, if any
- relevant implementation details, e.g., the used system APIs
Great examples include:
This does not mean every module should contain all of these items. But if there is something to say about the interaction of the contained types, their module documentation is the right place.
Documentation Has Canonical Sections (M-CANONICAL-DOCS)
Public library items must contain the canonical doc sections. The summary sentence must always be present. Extended documentation and examples are strongly encouraged. The other sections must be present when applicable.
#![allow(unused)] fn main() { /// Summary sentence < 15 words. /// /// Extended documentation in free form. /// /// # Examples /// One or more examples that show API usage like so. /// /// # Errors /// If fn returns `Result`, list known error conditions /// /// # Panics /// If fn may panic, list when this may happen /// /// # Safety /// If fn is `unsafe` or may otherwise cause UB, this section must list /// all conditions a caller must uphold. /// /// # Abort /// If fn may abort the process, list when this may happen. pub fn foo() {} }
In contrast to other languages, you should not create a table of parameters. Instead parameter use is explained in plain text. In other words, do not
/// Copies a file.
///
/// # Parameters
/// - src: The source.
/// - dst: The destination.
fn copy(src: File, dst: File) {}
but instead:
/// Copies a file from `src` to `dst`.
fn copy(from: File, to: File) {}
Related Reading
- Function docs include error, panic, and safety considerations (C-FAILURE)
Mark pub use
Items with #[doc(inline)]
(M-DOC-INLINE)
When publicly re-exporting crate items via pub use foo::Foo
or pub use foo::*
, they show up in an opaque re-export block. In most cases, this is not
helpful to the reader:
Instead, you should annotate them with #[doc(inline)]
at the use
site, for them to be inlined organically:
pub(crate) mod foo { pub struct Foo; }
#[doc(inline)]
pub use foo::*;
// or
#[doc(inline)]
pub use foo::Foo;
This does not apply to std
or 3rd party types; these should always be re-exported without inlining to make it clear they are external.
Still avoid glob exports The
#[doc(inline)]
trick above does not change M-NO-GLOB-REEXPORTS; you generally should not re-export items via wildcards.