Coding Guidelines

This document describes how to write Rust code in the kernel.

Style & formatting

The code should be formatted using rustfmt. In this way, a person contributing from time to time to the kernel does not need to learn and remember one more style guide. More importantly, reviewers and maintainers do not need to spend time pointing out style issues anymore, and thus less patch roundtrips may be needed to land a change.

Note

Conventions on comments and documentation are not checked by rustfmt. Thus those are still needed to be taken care of.

The default settings of rustfmt are used. This means the idiomatic Rust style is followed. For instance, 4 spaces are used for indentation rather than tabs.

It is convenient to instruct editors/IDEs to format while typing, when saving or at commit time. However, if for some reason reformatting the entire kernel Rust sources is needed at some point, the following can be run:

make LLVM=1 rustfmt

It is also possible to check if everything is formatted (printing a diff otherwise), for instance for a CI, with:

make LLVM=1 rustfmtcheck

Like clang-format for the rest of the kernel, rustfmt works on individual files, and does not require a kernel configuration. Sometimes it may even work with broken code.

Imports

rustfmt, by default, formats imports in a way that is prone to conflicts while merging and rebasing, since in some cases it condenses several items into the same line. For instance:

// Do not use this style.
use crate::{
    example1,
    example2::{example3, example4, example5},
    example6, example7,
    example8::example9,
};

Instead, the kernel uses a vertical layout that looks like this:

use crate::{
    example1,
    example2::{
        example3,
        example4,
        example5, //
    },
    example6,
    example7,
    example8::example9, //
};

That is, each item goes into its own line, and braces are used as soon as there is more than one item in a list.

The trailing empty comment allows to preserve this formatting. Not only that, rustfmt will actually reformat imports vertically when the empty comment is added. That is, it is possible to easily reformat the original example into the expected style by running rustfmt on an input like:

// Do not use this style.
use crate::{
    example1,
    example2::{example3, example4, example5, //
    },
    example6, example7,
    example8::example9, //
};

The trailing empty comment works for nested imports, as shown above, as well as for single item imports -- this can be useful to minimize diffs within patch series:

use crate::{
    example1, //
};

The trailing empty comment works in any of the lines within the braces, but it is preferred to keep it in the last item, since it is reminiscent of the trailing comma in other formatters. Sometimes it may be simpler to avoid moving the comment several times within a patch series due to changes in the list.

There may be cases where exceptions may need to be made, i.e. none of this is a hard rule. There is also code that is not migrated to this style yet, but please do not introduce code in other styles.

Eventually, the goal is to get rustfmt to support this formatting style (or a similar one) automatically in a stable release without requiring the trailing empty comment. Thus, at some point, the goal is to remove those comments.

Comments

“Normal” comments (i.e. //, rather than code documentation which starts with /// or //!) are written in Markdown the same way as documentation comments are, even though they will not be rendered. This improves consistency, simplifies the rules and allows to move content between the two kinds of comments more easily. For instance:

// `object` is ready to be handled now.
f(object);

Furthermore, just like documentation, comments are capitalized at the beginning of a sentence and ended with a period (even if it is a single sentence). This includes // SAFETY:, // TODO: and other “tagged” comments, e.g.:

// FIXME: The error should be handled properly.

Comments should not be used for documentation purposes: comments are intended for implementation details, not users. This distinction is useful even if the reader of the source file is both an implementor and a user of an API. In fact, sometimes it is useful to use both comments and documentation at the same time. For instance, for a TODO list or to comment on the documentation itself. For the latter case, comments can be inserted in the middle; that is, closer to the line of documentation to be commented. For any other case, comments are written after the documentation, e.g.:

/// Returns a new [`Foo`].
///
/// # Examples
///
// TODO: Find a better example.
/// ```
/// let foo = f(42);
/// ```
// FIXME: Use fallible approach.
pub fn f(x: i32) -> Foo {
    // ...
}

This applies to both public and private items. This increases consistency with public items, allows changes to visibility with less changes involved and will allow us to potentially generate the documentation for private items as well. In other words, if documentation is written for a private item, then /// should still be used. For instance:

/// My private function.
// TODO: ...
fn f() {}

One special kind of comments are the // SAFETY: comments. These mu