Documentation

Documentation Tests

Documentation tests (rustdoc --test, invoked via cargo test or cargo test --doc) verify that every Rust code block in your library's documentation compiles and passes its assertions.

Doc-Test Transformation Pipeline in `rustdoc`:

1. Extract fenced code block from `///` or `//!`
2. Strip leading `# ` prefixes (keeping those lines for compilation)
3. Insert `extern crate <my_crate>;`
4. If no `fn main` is present, wrap body inside `fn main() { ... }`
5. Compile and execute (merging compatible doc-tests into a single binary in Rust 2024!)

Rust 2024 Edition Merged Doc-Test Binaries

Prior to the Rust 2024 edition, rustdoc compiled every single documentation code block into its own separate executable binary—causing crates with hundreds of doc-tests to spend tens of seconds linking individual binaries.

In Rust 2024 edition, rustdoc automatically merges compatible doc-tests across the crate into a single combined test binary, cutting cargo test --doc build and execution times by an order of magnitude while still isolating tests that use compile_fail or global attributes (#![feature(...)]).

Controlling Doc-Test Execution with Fence Annotations

You can combine annotations on a triple-backtick fence using commas (for example, ```rust,no_run):

Fence Tag Compiled? Executed? Pass Condition
``` or ```rust Yes Yes Returns normally (or Ok(())) without panicking.
```should_panic Yes Yes Panics during execution.
```no_run Yes No Compiles cleanly without type or borrow errors.
```compile_fail Yes No Fails to compile (e.g., demonstrating borrow-checker safety).
```edition2024 Yes Yes Compiles using the specified Rust edition.
```ignore No No Skipped completely (displays a warning badge in cargo doc).
```text / ```sh / ```json No No Rendered as non-Rust code or plain text.

Writing compile_fail Doc-Tests for Type-State and Borrow Guarantees

When designing zero-cost abstractions—such as lifetimes tying an iterator to its parent buffer or a type-state builder that prevents calling .send() before .authenticate()—a compile_fail doc-test proves at test time that invalid code is rejected by the compiler:

/// A read-only view borrowed from a buffer.
///
/// The borrow checker prevents mutating the underlying buffer while `View` is alive:
///
/// ```compile_fail
/// use my_crate::View;
///
/// let mut buf = vec![1, 2, 3];
/// let view = View::new(&buf);
/// buf.push(4); // ❌ cannot borrow `buf` as mutable while `view` is alive
/// println!("{:?}", view.as_slice());
/// ```
pub struct View<'a> {
    slice: &'a [i32],
}

impl<'a> View<'a> {
    pub fn new(slice: &'a [i32]) -> Self {
        Self { slice }
    }

    pub fn as_slice(&self) -> &'a [i32] {
        self.slice
    }
}

fn main() {
    let buf = vec![1, 2, 3];
    let view = View::new(&buf);
    println!("View slice: {:?}", view.as_slice());
}
View slice: [1, 2, 3]

You can even specify an expected compiler error code on a compile_fail fence (such as ```compile_fail,E0502) so the doc-test only passes if compilation fails with that specific error code (E0502: mutable borrow while immutable borrow is active).