Writing Documentation for a Rust Project: From Basics to Advanced Techniques
Documenting code is an integral part of professional Rust development. Thanks to the built-in rustdoc tool, creating high-quality documentation becomes a simple and efficient process. In this article, we will break down how to properly write documentation for Rust projects, using all the capabilities of the ecosystem.
Basics of Documentation in Rust
Rust uses a special syntax for documentation, which is based on Markdown. Documentation is written using doc-comments, which start with /// (for external documentation) or //! (for internal module documentation).
Let's look at a basic example:
/// Computes the factorial of a number.////// This function takes a non-negative integer `n`/// and returns its factorial. If `n` is 0, it returns 1.////// # Examples////// ```/// let result = factorial(5);/// assert_eq!(result, 120);/// ```pub fn factorial(n: u64) -> u64 { (1..=n).product()}
//! # Math Functions Module//!//! This module contains basic mathematical operations,//! including factorial and binomial coefficient calculation.pub mod math;Generating Documentation with rustdoc
The rustdoc tool is part of the standard Rust toolset and automatically generates HTML documentation from doc-comments. To run it, simply execute the command:
cargo doc --openThis command will generate documentation for your project and all its dependencies, then open it in your browser. You can also specify additional flags:
--no-deps— do not include documentation for dependencies--document-private-items— document private items--target-dir— specify the directory for output files
The generated documentation automatically includes navigation, search, links to types and functions, as well as tests from code examples.
Structure of Doc-Comments and Special Sections
High-quality documentation in Rust follows a specific structure. It is recommended to use the following sections:
- Brief Description — the first line of the comment, displayed in lists and search results
- Detailed Description — explains how the function works, its features, and limitations
# Examples— one or more usage examples# Panics— situations in which the function may cause a panic# Errors— possible errors and their handling# Safety— for unsafe functions: explanation of safety preconditions
Example of a fully documented function:
/// Splits a string into parts by a specified delimiter.////// Returns a vector of strings obtained after splitting/// the source string `text` at each occurrence of `delimiter`./// Empty strings are not included in the result.////// # Examples////// ```/// let result = split_string("a,b,c", ',');/// assert_eq!(result, vec!["a", "b", "c"]);/// ```////// # Panics////// The function panics if `delimiter` is an empty string.////// # Errors////// This function does not return errors, but it may cause a panic.pub fn split_string(text: &str, delimiter: char) -> Vec<String> { assert!(delimiter != '\\0', "Delimiter cannot be a null character"); text.split(delimiter) .filter(|s| !s.is_empty()) .map(|s| s.to_string()) .collect()}Testing Documentation
One of Rust's strong points is the ability to test code examples directly in the documentation. The cargo test command automatically runs all examples from doc-comments.