Documentation & rustdoc
Rust treats documentation as a core part of the language toolchain. The rustdoc
tool ships with every Rust installation and can generate polished HTML documentation
directly from your source code. The convention of keeping docs and code together means
your documentation never drifts out of sync — and the doc tests ensure the examples
actually compile and run.
Outer Doc Comments with ///
Lines that begin with /// are outer doc comments — they document the item that
immediately follows. You can place them on functions, structs, enums, traits, type
aliases, modules, and more.
/// Returns the sum of two integers.
///
/// Both values must fit within `i32`. For larger numbers use `i64`.
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
/// A point in two-dimensional space.
pub struct Point {
/// The horizontal position.
pub x: f64,
/// The vertical position.
pub y: f64,
}/// ... above a struct field) appear in the generated HTML alongside the field name and type. Document your public fields — users will thank you.Inner Doc Comments with //!
Lines that begin with //! are inner doc comments — they document the item they
are inside, rather than the item that follows. Place them at the very top of a file
to document the whole module or crate.
//! # my_crate //! //! A collection of math utilities for everyday arithmetic. //! //! ## Quick start //! //! ``` //! use my_crate::add; //! assert_eq!(add(1, 2), 3); //! ``` pub mod arithmetic; pub mod geometry;
//! comments at the top of lib.rs become the crate-level documentation visible on docs.rs — the first thing users read. Invest in a clear overview, a quick-start example, and links to the main types.Markdown in Doc Comments
rustdoc renders all doc comments as Markdown. You can use headings, code spans, bold, italic, bulleted lists, numbered lists, tables, and links — all the standard Markdown syntax.
/// Parses a configuration file and returns the settings.
///
/// ## Supported formats
///
/// - `TOML` (recommended)
/// - `JSON`
///
/// ## Format
///
/// The file must contain a `[server]` section with at least a `port` key.
///
/// | Key | Type | Default |
/// |--------|--------|---------|
/// | port | u16 | 8080 |
/// | host | String | "localhost" |
///
/// **Note:** unknown keys are silently ignored.
pub fn parse_config(path: &str) -> Config {
todo!()
}The # Examples Section
The # Examples heading is a widely recognised convention in the Rust ecosystem.
rustdoc renders it prominently near the top of the item's documentation page, and
code blocks inside it are automatically run as doc tests by cargo test.
/// Divides two numbers.
///
/// # Examples
///
/// ```
/// use my_crate::divide;
/// assert_eq!(divide(10, 2), 5.0);
/// ```
pub fn divide(a: f64, b: f64) -> f64 {
a / b
}# Examples is a live test. If you refactor the function signature later and forget to update the docs, the doc test will catch it immediately.The # Panics Section
Document every condition under which a function can panic. Users who call your code need to know what invariants to uphold so they can avoid unexpected runtime crashes.
/// Returns the element at the given index.
///
/// # Panics
///
/// Panics if `index` is out of bounds (greater than or equal to the slice length).
pub fn get_element(slice: &[i32], index: usize) -> i32 {
slice[index]
}The # Errors Section
For functions that return Result, document the error variants callers may encounter
and under what conditions each is returned.
use std::io;
/// Reads the entire contents of a file into a string.
///
/// # Errors
///
/// Returns `io::Error` if:
/// - The file does not exist (`ErrorKind::NotFound`)
/// - The process lacks read permission (`ErrorKind::PermissionDenied`)
/// - The file contains invalid UTF-8 bytes
pub fn read_file(path: &str) -> Result<String, io::Error> {
std::fs::read_to_string(path)
}The # Safety Section
Any function marked unsafe must include a # Safety section that describes
exactly what invariants the caller must uphold to avoid undefined behaviour.
/// Dereferences a raw pointer and returns the value.
///
/// # Safety
///
/// The caller must ensure that:
/// - `ptr` is non-null.
/// - `ptr` points to a valid, initialised `T`.
/// - No other code mutates the pointed-to value while this reference is live.
pub unsafe fn deref_raw<T>(ptr: *const T) -> &'static T {
&*ptr
}# Safety section on an unsafe fn is considered a serious documentation bug in the Rust community. Tools like Clippy can warn about missing safety documentation.Doc Tests
Code blocks inside /// comments that are fenced with triple backticks are
automatically compiled and executed by cargo test. This makes it impossible for
your examples to silently go stale.
/// ``` /// let x = my_crate::add(2, 3); /// assert_eq!(x, 5); /// ```
To hide a line from the rendered docs while still running it in the test, prefix
the line with # (hash followed by a space):
/// ``` /// # use my_crate::Config; // hidden setup — not shown in docs /// let cfg = Config::default(); /// assert_eq!(cfg.port, 8080); /// ```
no_run to compile it but not execute it — useful for examples that require a running database or network connection: ```rust,no_run. Use ```rust,ignoreto skip compilation entirely (last resort — the example may rot).Linking to Other Items
rustdoc supports intra-doc links: wrap an item name in square brackets and rustdoc generates a hyperlink to that item's documentation page automatically.
/// Converts a `Config` into a `Server`.
///
/// See also: [Config], [Server::run], [crate::utils::validate]
pub fn build_server(cfg: Config) -> Server {
todo!()
}[fn@name], [struct@name],[trait@name], and so on.Generating Docs with cargo doc
cargo doc # generate docs into target/doc/ cargo doc --open # generate and open in your browser cargo doc --no-deps # only document your crate (skip dependencies)
The generated HTML is placed in target/doc/<crate_name>/index.html. The
--no-deps flag is especially useful in large workspaces where generating docs for
every transitive dependency would take minutes.
docs.rs: Automatic Hosting
When you publish a crate to crates.io, docs.rs automatically builds and hosts the documentation for every version. The URL follows a predictable pattern:
https://docs.rs/<crate_name>/<version>
docs.rs also builds docs for all feature combinations and target platforms, and it retains docs for every published version of your crate.
The #[doc] Attribute
Under the hood, /// doc comments are syntactic sugar for the #[doc = "..."]
attribute. You rarely need this directly, but it is useful when generating doc strings
programmatically via macros.
#[doc = "Returns the absolute value of a number."]
#[doc = ""]
#[doc = "# Examples"]
#[doc = ""]
#[doc = "```"]
#[doc = "assert_eq!(my_crate::abs(-5), 5);"]
#[doc = "```"]
pub fn abs(n: i32) -> i32 {
n.abs()
}pub use Re-exports and Docs
When you re-export an item with pub use, rustdoc includes that item in the
documentation of the re-exporting module. This is a common technique for creating a
clean, flat public API from a deeply nested internal module structure.
// src/lib.rs //! This crate exposes `Server` and `Config` at the top level. mod server; mod config; pub use server::Server; // re-exported — appears in lib docs pub use config::Config; // re-exported — appears in lib docs