Rust: Documenting your Code
Tags: rust, documentation, learning
Published: 2021-05-07 14:24:03

Hi.  
As with all projects. It's important to create documentation. This is, as we know, very important when creating code. When we come back to a project after a break, or if someone new takes over. Documentation will help you remember or learn what the code does. The thinking that was behind certain decisions.

Here I will be documenting some examples of what I have learned. This is not to be an extensive look.

## Resources
As with everything new. I started with some research. I found this really good [article](https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate). I strongly recommend you take a look at the article.   
There is also the standard [docs](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html)


I will only be concerning myself wth the `dns` module I have been creating.  

First let's generate the documentation with what I have already.
```bash
cargo doc && cargo doc --open
```
Then navigate to the `dns` module and then `spf`.
![dns spf 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k12md5phqj1tdrp6aee9.png)  

## Basic excluding of internal functions and modules
In the above image we can see a list of functions. These functions are internal implementation details. And users of the module do not need to be aware of these. Let's hide these functions from rust's documentation system.  

For this we use the `#[doc(hidden)]` instruction.

For each function we need to add this instruction just above the function declaration. This is done within `src/dns/spf/mod.rs`.

```rust
#[doc(hidden)]
// Check if the initial character in the string `record` matches `c`
// If they do no match then return the initial character
// if c matches first character of record, we can `+`, a blank modiifer equates to `+`
fn return_and_remove_qualifier(record: &str, c: char) -> (char, &str) {
```

```rust
#[doc(hidden)]
fn remove_qualifier(record: &str) -> &str {
```

```rust
#[doc(hidden)]
fn capture_matches(
    pattern: Regex,
```
We have to regenerate the documentation if we want to see the changes
```bash
cargo doc
```

Then we can reload the documentation page.  

We now have a cleaner page with the internal functions removed.
![dns spf 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evjkn3gs20b2j1khv3xz.png)

You can use the `#[doc(hidden)]` to also hide the test modules from documentation.  
```rust
#[doc(hidden)]
mod spf_a_mechanism_test;
#[doc(hidden)]
mod spf_mx_mechanism_test;
#[doc(hidden)]
mod spf_test;
```

## Adding module level documentation
If you look closely at the new page. You will notice there is no information about what this module does. We need to add some module level documentation.

At the the top of `mod.rs` I will add.
```rust
//! This module creates an object that contains a deconstructed SPF DNS record.
```
We then regenerate the documentation again. (skipped from here on out)
![dns spf 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9pmokujcwak45d3do93g.png)

## Documenting Functions and Methods

Let's move to documenting some of the functions associated with the `Spf struct`

Documenting the `Spf::new()` Method.
![spf-new-doc-sample](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lo7a1szuhackuyg2e3zo.png)  

An important thing to note here is that the code between the backticks is actually tested when you run `cargo test`.  

**Note:** The above example will not actually work. If you are looking for a real example checkout the next article {% link https://dev.to/basman/rust-move-from-binary-to-library-and-add-documentation-examples-that-are-tested-9da %}
Documenting the `parse()` Method.
```rust
/// Parse the contents of `source` and populate the internal structure of `Spf`
pub fn parse(&mut self) {
```

This now gives us.
![dns spf 4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f26f2y76k3ohi0b8gq6m.png)

## Linking within the documentation
I would refer you to this [stack overflow link](https://stackoverflow.com/questions/31582064/how-to-link-to-other-fns-structs-enums-traits-in-rustdoc) as a starter.  

Here is a small example.
```rust
#[derive(Debug, Clone)]
pub enum MechanismKind {
    /// Represents a Mechanism of type include:
    Include,
    /// Represents a Mechanism of type redirect=
    Redirect,
}

impl MechanismKind {
    /// Returns `true` if the mechanism is [`Include`](MechanismKind::Include).
    pub fn is_include(&self) -> bool {
        matches!(self, Self::Include)
    }
    /// Returns `true` if the mechanism is [`Redirect`](MechanismKind::Redirect).
    pub fn is_redirect(&self) -> bool {
        matches!(self, Self::Redirect)
    }
}
```
Like **Markdown** we use `[label](link)` the difference is that the *link* is written as if we are using it in actual rust code `MechanismKind::Include`  
![dns spf 5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zveujvk8gpf5ie8z119l.png)
Clicking on the **Include** for the *Returns 'true' if mechanism is Include* links you up to the definition of **Include** under **Variants**.


That's it for today. I will update this article if I find new interesting things.  
Hope this helps.