Writing documentation
bunsen has two kinds of documentation, rustdoc and this book, and each fact belongs in exactly one of them. This page covers the book’s side, for anyone writing it: how the book links into the API, how code in the book stays correct, and how to build the book. STYLE.md’s rustdoc chapter has the rules for rustdoc, including which facts belong there.
rustdoc is the reference
rustdoc documents every interface and every lifecycle; the book explains what rustdoc can’t hold, names each concept, and links to it. When a book page needs a fact that rustdoc doesn’t have, the fix is in rustdoc. STYLE.md’s rustdoc is the reference is the rule, including what the book never restates.
Module docs must render
A private module’s //! never reaches the API docs, so prose written there
is invisible. STYLE.md’s
Module docs must render
says where that prose goes instead, and CI enforces it with
tools/check_hidden_module_docs.py.
Linking into the API
API links in the book are rustdoc intra-doc paths, not URLs:
| To link | Write |
|---|---|
| an item | [`ShapeContract`](bunsen::contracts::ShapeContract) |
| a module | [`bunsen::ops`] |
| a section of a page | [the ops/blocks rule](bunsen::ops#ops-and-blocks) |
| a method | [`try_init`](bunsen::burner::module::ModuleInit::try_init) |
| a macro | [`shape_contract!`](bunsen::contracts#macros-and-methods), the section of its module’s page that lists it (see below) |
| another published crate | [`bunsen_firehose`] |
Macros are the one exception to linking the item itself. rustdoc can’t
resolve a path to a macro_rules! macro that another crate re-exports
(bunsen::contracts::shape_contract! reports “no item named bunsen in
scope”), so a book link to a bunsen macro goes to the module section that
documents it.
mdbook-rustdoc-links resolves them at build time with rustdoc’s own
resolver, so a link in the book is exactly as valid as the same link in a
doc comment. Renaming or moving an item, method or field leaves the link
unresolved, and that fails the book build in CI, in the same PR as the
rename.
Only what docs.rs shows resolves. bunsen is built with the feature list
in its [package.metadata.docs.rs], and the other published crates with
their defaults (docs.rs may build one with more), so an item behind a
feature that docs.rs doesn’t build can’t be linked. The crates/dev and
crates/validation crates and the examples are not in that build. Link
them, and other repository files, as GitHub URLs, and keep those few.
The base URL the links point at is chosen per build:
- Local builds link to
/api, a symlink frombook/src/apitotarget/doc, and include the API docs in the book’s output, so a local book reads against the API at HEAD, offline. - Release builds, selected when
CIis set, link to docs.rs, pinned to each crate’s version fromCargo.lock. That is why a book for readers is built only from a release (Releasing). MDBOOK_PREPROCESSOR__RUSTDOC_LINKS__BASE_URLoverrides both.
Links between chapters are relative .md paths. mdbook-linkcheck2 checks
that the file exists, but not the #anchor.
Square brackets in prose are read as links, and an unresolved one fails the
build. Escape a stray bracket (\[x\]) or put it in a code span.
Code in the book
Every Rust block in the book is compiled, or it is plainly a sketch:
- Runnable code that names bunsen items is pulled in from compiled code
with an mdbook include,
{{#include path:anchor}}, fromcrates/dev/book-snippetsor an example. The included region sits between// ANCHOR: nameand// ANCHOR_END: namein a test or amain, socargo testruns it, and CI builds, lints and formats it like any other workspace member. Prefer including code an example already has over writing a new snippet. - A sketch that names no bunsen items may use a
textorrust,ignorefence, and the prose around it says it is a sketch. - The book never copies a rustdoc example. It links to the doctest.
Shapes, math and diagrams
- Tensor shapes are one code span in square brackets, with the
dimension arithmetic inside, such as
[batch, h_wins*size, w_wins*size, channels]. This is STYLE.md’s shape notation, the same in rustdoc and the book, and it reads like the shape contract that checks the shape. The code span also keeps the brackets away from the link resolver. - Math is KaTeX, between dollar signs. Book-wide macros, such as
\RR,\NNand\ZZfor the number sets, are defined inbook/katex-macros.txt. Add a macro there rather than repeating a definition on a page. - Diagrams are mermaid, or
textfences. Prefer atextdiagram when the same picture may belong in rustdoc.
Building the book
The book’s tasks are in Makefile.toml. Each installs the pinned mdbook
tools on first use, at the versions CI uses:
| Task | What it does |
|---|---|
cargo make book | builds the book against the local API docs; an unresolved API link is a warning |
cargo make book-check | the same build CI runs: an unresolved API link is an error |
cargo make book-serve | serves the book locally, rebuilding as you edit |
cargo make book-release | the publishing build: API links pinned to this release on docs.rs |
Run book-check before pushing a change that touches the book or renames
anything public. The build runs cargo doc itself, so the first run is
slow. The release workflow makes the book-release build and publishes
it (Releasing); run it locally only to preview that.
Writing a page
Open each page with a sentence or two on what it covers. Say what a thing is for and when to reach for it, and stop when the why is told: one good paragraph and a link beat a list of features. Every API noun is a link.