Skip to content

docs: rust: documentation review #580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Documentation/rust/arch-support.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Arch Support
============

Currently, the Rust compiler (``rustc``) uses LLVM for code generation,
which limits the supported architectures we can target. In addition, support
for building the kernel with LLVM/Clang varies (see :ref:`kbuild_llvm`),
which ``bindgen`` relies on through ``libclang``.
which limits the supported architectures that can be targeted. In addition,
support for building the kernel with LLVM/Clang varies (see :ref:`kbuild_llvm`).
This support is needed for ``bindgen`` which uses ``libclang``.

Below is a general summary of architectures that currently work. Level of
support corresponds to ``S`` values in the ``MAINTAINERS`` file.
Expand Down
71 changes: 35 additions & 36 deletions Documentation/rust/coding.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,29 @@ This document describes how to write Rust code in the kernel.
Coding style
------------

The code is automatically formatted using the ``rustfmt`` tool. This is very
good news!

- If you contribute from time to time to the kernel, you do not need to learn
and remember one more style guide. You will also need less patch roundtrips
to land a change.

- If you are a reviewer or a maintainer, you will not need to spend time on
pointing out style issues anymore.
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 we still need to take care of those: please see
``rustfmt``. Thus those are still needed to be taken care of: please see
:ref:`Documentation/rust/docs.rst <rust_docs>`.

We use the tool's default settings. This means we are following the idiomatic
Rust style. For instance, we use 4 spaces for indentation rather than tabs.
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.

Typically, you will want to instruct your editor/IDE to format while you type,
when you save or at commit time. However, if for some reason you want
to reformat the entire kernel Rust sources at some point, you may run::
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

To check if everything is formatted (printing a diff otherwise), e.g. if you
have configured a CI for a tree as a maintainer, you may run::
It is also possible to check if everything is formatted (printing a diff
otherwise), for instance for a CI, with::

make LLVM=1 rustfmtcheck

Expand All @@ -45,31 +43,32 @@ even work with broken code.
Extra lints
-----------

While ``rustc`` is a very helpful compiler, some extra lints and analysis are
While ``rustc`` is a very helpful compiler, some extra lints and analyses are
available via ``clippy``, a Rust linter. To enable it, pass ``CLIPPY=1`` to
the same invocation you use for compilation, e.g.::
the same invocation used for compilation, e.g.::

make LLVM=1 CLIPPY=1

At the moment, we do not enforce a "clippy-free" compilation, so you can treat
the output the same way as the extra warning levels for C, e.g. like ``W=2``.
Still, we use the default configuration, which is relatively conservative, so
it is a good idea to read any output it may produce from time to time and fix
the pointed out issues. The list of enabled lists will be likely tweaked over
time, and extra levels may end up being introduced, e.g. ``CLIPPY=2``.
Please note that Clippy may change code generation, thus it should not be
enabled while building a production kernel.


Abstractions vs. bindings
-------------------------

We don't have abstractions for all the kernel internal APIs and concepts,
but we would like to expand coverage as time goes on. Unless there is
a good reason not to, always use the abstractions instead of calling
the C bindings directly.
Abstractions are Rust code wrapping kernel functionality from the C side.

In order to use functions and types from the C side, bindings are created.
Bindings are the declarations for Rust of those functions and types from
the C side.

For instance, one may write a ``Mutex`` abstraction in Rust which wraps
a ``struct mutex`` from the C side and calls its functions through the bindings.

If you are writing some code that requires a call to an internal kernel API
or concept that isn't abstracted yet, consider providing an (ideally safe)
abstraction for everyone to use.
Abstractions are not available for all the kernel internal APIs and concepts,
but it is intended that coverage is expanded as time goes on. "Leaf" modules
(e.g. drivers) should not use the C bindings directly. Instead, subsystems
should provide as-safe-as-possible abstractions as needed.


Conditional compilation
Expand All @@ -80,10 +79,10 @@ configuration:

.. code-block:: rust

#[cfg(CONFIG_X)] // `CONFIG_X` is enabled (`y` or `m`)
#[cfg(CONFIG_X="y")] // `CONFIG_X` is enabled as a built-in (`y`)
#[cfg(CONFIG_X="m")] // `CONFIG_X` is enabled as a module (`m`)
#[cfg(not(CONFIG_X))] // `CONFIG_X` is disabled
#[cfg(CONFIG_X)] // Enabled (`y` or `m`)
#[cfg(CONFIG_X="y")] // Enabled as a built-in (`y`)
#[cfg(CONFIG_X="m")] // Enabled as a module (`m`)
#[cfg(not(CONFIG_X))] // Disabled


Documentation
Expand Down
93 changes: 42 additions & 51 deletions Documentation/rust/docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,43 @@
Docs
====

Rust kernel code is not documented like C kernel code (i.e. via kernel-doc).
Instead, we use the usual system for documenting Rust code: the ``rustdoc``
tool, which uses Markdown (a *very* lightweight markup language).

This document describes how to make the most out of the kernel documentation
for Rust.

Rust kernel code is not documented like C kernel code (i.e. via kernel-doc).
Instead, the usual system for documenting Rust code is used: the ``rustdoc``
tool, which uses Markdown (a lightweight markup language).

To learn Markdown, there are many guides available out there. For instance,
the one at:

https://commonmark.org/help/


Reading the docs
----------------

An advantage of using Markdown is that it attempts to make text look almost as
you would have written it in plain text. This makes the documentation quite
pleasant to read even in its source form.

However, the generated HTML docs produced by ``rustdoc`` provide a *very* nice
experience, including integrated instant search, clickable items (types,
functions, constants, etc. -- including to all the standard Rust library ones
that we use in the kernel, e.g. ``core``), categorization, links to the source
code, etc.
The generated HTML docs produced by ``rustdoc`` include integrated search,
linked items (e.g. types, functions, constants), source code, etc.

Like for the rest of the kernel documentation, pregenerated HTML docs for
the libraries (crates) inside ``rust/`` that are used by the rest of the kernel
are available at `kernel.org`_ (TODO: link when in mainline and generated
alongside the rest of the documentation).
The generated docs may be read at (TODO: link when in mainline and generated
alongside the rest of the documentation):

.. _kernel.org: http://kernel.org/
http://kernel.org/

Otherwise, you can generate them locally. This is quite fast (same order as
compiling the code itself) and you do not need any special tools or environment.
This has the added advantage that they will be tailored to your particular
kernel configuration. To generate them, simply use the ``rustdoc`` target with
the same invocation you use for compilation, e.g.::
The docs can also be easily generated and read locally. This is quite fast
(same order as compiling the code itself) and no special tools or environment
are needed. This has the added advantage that they will be tailored to
the particular kernel configuration used. To generate them, use the ``rustdoc``
target with the same invocation used for compilation, e.g.::

make LLVM=1 rustdoc


Writing the docs
----------------

If you already know Markdown, learning how to write Rust documentation will be
a breeze. If not, understanding the basics is a matter of minutes reading other
code. There are also many guides available out there, a particularly nice one
is at `GitHub`_.

.. _GitHub: https://guides.github.com/features/mastering-markdown/#syntax

This is how a well-documented Rust function may look like (derived from the Rust
standard library)::
This is how a well-documented Rust function may look like::

/// Returns the contained [`Some`] value, consuming the `self` value,
/// without checking that the value is not [`None`].
Expand All @@ -77,32 +65,35 @@ standard library)::
}
}

This example showcases a few ``rustdoc`` features and some common conventions
(that we also follow in the kernel):
This example showcases a few ``rustdoc`` features and some conventions followed
in the kernel:

- The first paragraph must be a single sentence briefly describing what
the documented item does. Further explanations must go in extra paragraphs.

* The first paragraph must be a single sentence briefly describing what
the documented item does. Further explanations must go in extra paragraphs.
- Unsafe functions must document their safety preconditions under
a ``# Safety`` section.

* ``unsafe`` functions must document the preconditions needed for a call to be
safe under a ``Safety`` section.
- While not shown here, if a function may panic, the conditions under which
that happens must be described under a ``# Panics`` section.

* While not shown here, if a function may panic, the conditions under which
that happens must be described under a ``Panics`` section. Please note that
panicking should be very rare and used only with a good reason. In almost
all cases, you should use a fallible approach, returning a `Result`.
Please note that panicking should be very rare and used only with a good
reason. In almost all cases, a fallible approach should be used, typically
returning a ``Result``.

* If providing examples of usage would help readers, they must be written in
a section called ``Examples``.
- If providing examples of usage would help readers, they must be written in
a section called ``# Examples``.

* Rust items (functions, types, constants...) will be automatically linked
(``rustdoc`` will find out the URL for you).
- Rust items (functions, types, constants...) must be linked appropriately
(``rustdoc`` will create a link automatically).

* Following the Rust standard library conventions, any ``unsafe`` block must be
preceded by a ``SAFETY`` comment describing why the code inside is sound.
- Any ``unsafe`` block must be preceded by a ``// SAFETY:`` comment
describing why the code inside is sound.

While sometimes the reason might look trivial and therefore unneeded, writing
these comments is not just a good way of documenting what has been taken into
account, but also that there are no *extra* implicit constraints.
While sometimes the reason might look trivial and therefore unneeded, writing
these comments is not just a good way of documenting what has been taken into
account, but most importantly, it provides a way to know that there are
no *extra* implicit constraints.

To learn more about how to write documentation for Rust and extra features,
please take a look at the ``rustdoc`` `book`_.
Expand Down
5 changes: 3 additions & 2 deletions Documentation/rust/index.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
Rust
====

Documentation related to Rust within the kernel. If you are starting out,
read the :ref:`Documentation/rust/quick-start.rst <rust_quick_start>` guide.
Documentation related to Rust within the kernel. To start using Rust
in the kernel, please read the
:ref:`Documentation/rust/quick-start.rst <rust_quick_start>` guide.

.. toctree::
:maxdepth: 1
Expand Down
Loading