rustdoc
Add or revise source-level Rustdoc for Shift Rust APIs. Use before writing or editing documentation comments in `.rs` files, especially for public or crate-visible APIs, domain structures, compiler ad
Files1
View on GitHubSKILL.md.claude/skills/rustdoc/SKILL.md
GitHubRustdoc — Source API Contracts
Write Rustdoc as the stable contract a caller or maintainer needs without reconstructing the implementation.
Use /// immediately before an item and //! at the start of a module or crate. Let Rust's types describe shape; document semantics the type system cannot express.
Runbook
- Identify the boundary and audience: caller, implementer, compiler adapter, persistence layer, or maintainer.
- Read the surrounding module, relevant callers, and behavior tests before describing the contract.
- Start with one short sentence stating what the item represents or does.
- Add only applicable details: ownership, snapshotting, mutation, I/O, units, coordinate domain, fallback, ordering, concurrency, performance, or invariants.
- Add conventional sections when required:
# Errorsfor observable failure conditions.# Panicsfor conditions that actually panic.# Safetyfor everyunsafeAPI, stating the caller's obligations.# Examplesonly when call order, conversion, or output is non-obvious.
- Link related APIs with intra-doc links such as [
Font] or [Self::export]. - Delete implementation trivia, current-caller anecdotes, migration history, and statements already obvious from the signature.
What To Document
Prioritize contracts that Rust cannot encode directly:
- Ownership and lifetime semantics — owned snapshot versus live view, aliasing, cloning, and who may mutate a result.
- Effects and atomicity — filesystem or database I/O, shared-state mutation, transaction boundaries, and partial-failure behavior.
- Units and coordinate domains — font units, user coordinates, design coordinates, normalized coordinates, and mapping direction.
- Resolution and sparsity — exact lookup versus fallback, missing layer versus empty layer, and default-source requirements.
- Ordering and identity — stable ordering, ID preservation, minted identity, and when a value becomes stale.
- Failures — error conditions, panic preconditions, cancellation, and unsupported input.
- Concurrency and performance — thread assumptions, blocking work, hot-path suitability, and important complexity.
Document pub(crate) and private items when they form an architectural seam or carry a non-obvious invariant. Do not document obvious constructors or mechanical work wrappers merely because they are visible within the crate.
Style Rules
- Open with a direct contract sentence; avoid “This function” and “This struct.”
- Prefer stable domain language over current implementation wiring.
- Do not restate parameter or field types in prose.
- Document fields individually only when their units, ownership, valid range, or meaning is not encoded by the field name and type.
- Use backticks for values and syntax; use intra-doc links for Rust items.
- Put module-wide invariants in one
//!comment instead of repeating them on every item. - Keep algorithmic rationale in ordinary
//comments near the algorithm, not in the public contract. - Do not copy documentation from an implemented trait. Describe Shift-specific adapter semantics on the implementing type or module.
- Do not use Rustdoc as a TODO list, changelog, ticket, or warning to future maintainers.
- Do not promise behavior more strongly than tests and implementation support.
Conventional Sections
Use headings exactly as Rust tooling and readers expect:
/// Writes a TTF compiled from an immutable snapshot of the supplied font.
///
/// The destination is replaced atomically after compilation succeeds.
///
/// # Errors
///
/// Returns [`ExportError`] when the source cannot be represented, compilation
/// fails, or the destination cannot be replaced.
pub fn export(/* ... */) -> Result<FontExportResult, ExportError> {
// ...
}
For panics, document the actual precondition rather than writing a generic disclaimer:
/// Returns the default source.
///
/// # Panics
///
/// Panics when the font has no default source.
Every unsafe item needs a precise caller obligation:
/// Reads a point from the packed geometry buffer.
///
/// # Safety
///
/// `index` must address a fully initialized point in `buffer`.
Examples and Links
Examples are executable contracts, not decoration.
- Prefer a compiling doctest with assertions.
- Use hidden
#lines for setup when that keeps the lesson focused. - Use
no_runfor filesystem or process examples; avoidignoreunless the example fundamentally cannot compile in docs. - Keep one concept per example and omit examples for trivial accessors.
- Run doc tests after adding an example.
Use links that Rustdoc can resolve:
/// Creates the snapshot consumed by [`FontExporter::export`].
///
/// See [`FontView`] for the borrowed authoring interface.
Validation
After editing Rustdoc:
- Run
cargo fmt --all -- --check. - Run the affected crate's tests, including doc tests when examples changed.
- Run
RUSTDOCFLAGS="-D rustdoc::broken_intra_doc_links" cargo doc --workspace --no-deps --document-private-itemsfor new or changed links. - Run Clippy for affected crates when documentation changes accompany Rust code changes.
Do not enable workspace-wide missing_docs as part of an unrelated change. Introduce lint policy separately after auditing the existing baseline.
Checklist
- The first sentence states a useful contract.
- The comment adds information not already encoded by the signature.
- Units, coordinate spaces, ownership, sparse behavior, and effects are explicit where relevant.
- Every documented failure, panic, and safety obligation matches reality.
- Intra-doc links resolve and examples compile.
- No caller name-drops, implementation history, TODOs, or duplicated trait docs.