# Rust documentation guidelines

The documentation for the Glean SDK Rust crates is automatically generated by the [`rustdoc`](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html) tool. That means the documentation for our Rust code is written as doc comments throughout the code.

Here we outline some guidelines to be followed when writing these doc comments.

## Module level documentation

Every module's index file must have a [module level doc comment](https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#commenting-contained-items).

The module level documentation must start with a one-liner summary of the purpose of the module,
the rest of the text is free form and optional.

## Function and constants level documentation

Every public function / constant must have a dedicated [doc comment](https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments).

Non public functions / constants are not required to, but may have doc comments. These comments should follow
the same structure as public functions.

> **Note** Private functions are not added to the generated documentation by default, but may be by using the [`--document-private-items`](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) option.

### Structure

Below is an example of the structure of a doc comment in one of the Glean SDK's public functions.


```rust
/// Collects and submits a ping for eventual uploading.
///
/// The ping content is assembled as soon as possible, but upload is not
/// guaranteed to happen immediately, as that depends on the upload policies.
///
/// If the ping currently contains no content, it will not be sent,
/// unless it is configured to be sent if empty.
///
/// # Arguments
///
/// * `ping` - The ping to submit
/// * `reason` - A reason code to include in the ping
///
/// # Returns
///
/// Whether the ping was succesfully assembled and queued.
///
/// # Errors
///
/// If collecting or writing the ping to disk failed.
pub fn submit_ping(&self, ping: &PingType, reason: Option<&str>) -> Result<bool> {
    ...
}
```

#### Every doc comment must start with a one-liner summary of what that function is about

The text of this section should always be in the third person and describe an action.

If any additional information is necessary, that can be added following a new line after the summary.

#### Depending on the signature and behavior of the function, additional sections can be added to its doc comment

These sections are:

1. `# Arguments` - A list of the functions arguments and a short description of what they are. Note that there is no need to point out the type of the given argument on the doc comment since it is already outlined in the code.
2. `# Returns` - A short summary of what this function returns. Note that there is no need to start this summary with "Returns..." since that is already the title of the section.
3. `# Errors` - The possible paths that will or won't lead this function to return an error. It is at the discretion of the programmer to decide which cases are worth pointing out here.
4. `# Panics` - The possible paths that will or won't lead this function to `panic!`. It is at the discretion of the programmer to decide which cases are worth pointing out here.
4. `# Safety` - In case there are any safety concerns or guarantees, this is the section to point them out. It is at the discretion of the programmer to decide which cases are worth pointing out here.
5. `# Examples` - If necessary, this section holds examples of usage of the function.

These sections should only be added to a doc comment when necessary, e.g. we only add an `# Arguments` section when a function has arguments.

> **Note** The titles of these sections must be level-1 headers. Additional sections not listed here can be level-2 or below.

### Link to all the things

If the doc comment refers to some external structure, either from the Glean SDK's code base or external, make sure to link to it.

Example:

```rust
/// Gets a [`PingType`] by name.
///
/// # Returns
///
/// The [`PingType`] of a ping if the given name was registered before, `None` otherwise.
///
/// [`PingType`]: metrics/struct.PingType.html
pub fn get_ping_by_name(&self, ping_name: &str) -> Option<&PingType> {
    ...
}
```

> **Note** To avoid polluting the text with multiple links, prefer using [reference links](https://spec.commonmark.org/0.27/#reference-link) which allow for adding the actual links at the end of the text block.

### Warnings

Important warnings about a function should be added, when necessary, before the one-liner summary in bold text.

Example:

```rust
/// **Test-only API (exported for FFI purposes).**
///
/// Deletes all stored metrics.
///
/// Note that this also includes the ping sequence numbers, so it has
/// the effect of resetting those to their initial values.
pub fn test_clear_all_stores(&self) {
    ...
}
```

### Semantic line breaks

Prefer using [semantic line breaks](https://sembr.org/) when breaking lines in any doc or non-doc comment.

## References

These guidelines are largely based on the Rust API documentation guidelines.

* [RFC 1574 - More API Documentation Conventions](https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md)
* [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/documentation.html)

