Writing Documentation in Rust

Documentation is important. It’s also easy to do. Rust ships with tools to help developers create documentation for their libraries.

Code Comments

The main way that many developers write documentation is through source code comments. A single-line comment in Rust is started with //. Many programming languages should already use this construct, so it’s probably not surprising to you. Equally unsurprising, multi-line comments start with /* and end with */. Many Rustaceans (that’s what Rust developers call themselves) prefer single-line comments. Do whatever you want, it’s fun to argue about inconsequential things after the fact.

I use code comments to document code for myself and my co-workers. I use code comments for explaining something to whoever is looking at the code after me. Mainly code comments are for walking through a design decision or piece of logic that might not be clear at a casual glance. In flaker, code comments are used to walk through the construct_id function. With the code removed, it reads like:

fn construct_id(&mut self) -> BigUint {
    // Create a new vec of bytes
    // push the counter into bytes
    // next 6 bytes are the worker id
    // fill the rest of the buffer with the current time, as bytes
    // create a BigUint from the buffer
}

The problem is that code comments aren’t visible to the rest of the world in a meaningful way. Other developers need to read the source code in order to view the code comments. That’s not the friendliest way to introduce your code to the world. Thankfully, there’s a better way!

Document Comments

Document comments make it easy to document as you write code. This also makes it easier to keep your documentation up to date as you’re modifying code. It is, after all, right next to the code you’re changing.

Just like code comments, there are two ways to write document comments for functions and methods. A single-line document comment looks like ///. A multi-line document comment starts with /** on the first line, all by itself, and ends with */. These are referred to as outer comments – outer line doc comments and outer block doc comments, if you want to get specific about it.

We put the comments outside of the code that we’re documenting. Pulling from my flaker library again:

/// Returns a new Flaker based on the specified identifier
///
/// # Arguments
///
/// * `identifier` - A 6 byte vec that provides some arbitrary identification.
///
/// # Remarks
///
/// This is a convenience function that converts the `identifier` `vec` into
/// a 6 byte array. Where possible, prefer the array and use `new`.
///
/// *Note*: This also assumes the `flaker` is being created on a little endian
/// CPU. 
pub fn new_from_identifier(identifier: Vec) -> Flaker {
    // magic
}

We can use Markdown in our documentation comments! That’s exciting. Now we can create good looking documentation that has structure. We’ll see more about what this looks like in a little bit. There are a few conventions to use while documenting your code. These are # Examples, # Panics, # Errors, and # Safety. You can read more about the documentation conventions in Documentation – Special Sections and in RFC 505.

Module Comments

We can also use documentation comments to write docs for our modules. These use what’s called inner doc comments. An inner line doc comment looks like //! – note the bang. An inner block doc comment starts with /*! and ends with, you guessed it, */.

These are called inner doc comments because they go inside the thing being documented. Outer doc comments go outside the thing being documented.

Sadly, flaker doesn’t have any module documentation. If it did, though, it would look like:

//! This is the documentation for `flaker`
//!
//! # Examples

This documentation will get generated later when we run cargo doc, which I promise we’ll talk about in a second.

Documentation Tests

It’s possible to add code samples to a documentation comment using three backticks:

//! ```
//! assert_eq!(4, 2 + 2);
//! ```

When we run cargo test – this code will be executed with all of our tests. But we’ll still see the code when we generate documentation. This also works for function and method level documentation – just replace the //! with ///.

Just remember, your documentation tests will only be run if your crate is a library, not if it’s an application.

Building Documentation

Building documentation is relatively simple – you can execute cargo doc to build your documentation. This command will build documentation for your library and all of its dependencies. That may not be desirable (it’s probably not).

If you only want to build the documentation for your own library, you can execute: cargo doc --no-deps. Using --no-deps will only build documentation for your code, not for any third party dependencies. You can even add a --open flag to open the newly built documentation in your web browser. It should look something like this:

2016-05-03_12-00-10

If I click through to the Flaker struct itself, we can see the documentation that we wrote! That’s exciting.

Auto-generated documentation for the flaker struct.

Auto-generated documentation for the flaker struct.

Writing docs should always be this easy. Right now, cargo doc won’t put your documentation anywhere apart from the local file system. Many developers use tools to publish documentation to a GitHub static site.

Documentation for Everyone!

At this point, we know enough to write documentation for our methods and functions using doc comments – ///. We can also write module level documentation with doc comments – //!. We can even format our documentation using markdown and its many features. And, finally, we can even include tests in our documentation. How’s that for a documentation feature?

There are a few more tricks available to you with Rust’s documentation (like using external Markdown files), you can learn more in the documentation chapter of the Rust Book.

3 Comments. Leave new

  • the tset you write is a simple assert_eq on numbers,

    I’m trying to test a type I have created and the test is in the same module

    9 /// “`
    8 /// let a = SArg::new().arg(“f”,7).style(“p”,”rt”);
    7 /// assert_eq!(r#”f=”6″ style=”p:rt;””#,&format!(“{}”,a));
    6 /// “`
    5 impl SArg {
    4 pub fn new()->SArg{
    3 SArg{
    2 items:Vec::new(),
    1 }
    0 }

    but I get the following error

    error[E0433]: failed to resolve. Use of undeclared type or module `SArg`
    –> src/args.rs:2:13

    Any ideas?

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Menu