Rust Style

We use rustfmt for formatting and Clippy for linting. Rust has one true style.

Source baseline: docs/src/style/rust.mdx. Source: docs/src/style/rust.mdx

Formatting

4 spaces, 100 characters, edition 2024, use_small_heuristics = "Max" (uses 100 characters for all width heuristics, preventing unnecessary line breaks).

File Header

Every source file opens with the copyright line, then module docs. For files implementing non-trivial algorithms, add a numbered step summary (algorithmic preamble) inside the module doc.

Reader-First Design

Optimize for local understanding. Public entrypoints first. Order helpers by call flow. Orchestration functions should read like verb chains. No compound function names ("and" = too much). Use let bindings to name intermediate results for scannability. Prefer concrete code until it is actually generic.

Error Handling

thiserror for libraries, anyhow for binaries. Each error variant names a single failure mode and carries diagnostic data. No String inside error variants; if you cannot match on it, redesign. Use ? with .map_err() for context.

No unwrap on runtime data (config files, external APIs, user input). Allowed in tests, compile-time provable cases, startup configuration, and poisoned mutexes. This is not paranoia; Cloudflare's November 2025 outage was caused by Result::unwrap on config data.

Naming

PascalCase for types/traits. snake_case for functions/variables. SCREAMING_SNAKE for constants. Conversion prefixes are contracts: as_* (borrowed, cheap), to_* (owned, allocates), into_* (consumes self), from_* (constructor). No get_ prefix for getters.

Systems Patterns

  • Fail fast at startup, fail closed on requests. No silent fallbacks.
  • Actor pattern via packages/rust/actor for shared mutable state (eliminates Mutex contention).
  • RAII for system resources. TAP devices, ZFS datasets, sockets: Drop impl cleans up.
  • Idempotent operations by default. DELETE returns 204 even if already gone.
  • Policy/state split with reconciliation loops.
  • Testability via injection. Parameterize side-effectful functions.
  • Surgical #[cfg] over wholesale stubs.
  • Unsafe isolated in dedicated FFI modules with // SAFETY: comments.
  • Prefer ecosystem crates (nix, rustix, vsock) over hand-rolled syscalls.

Testing

Inline #[cfg(test)] mod tests. Name tests by the invariant they verify, not the function they call. design_ prefix for intentional policy decisions. Use matches! for error variant assertions.

Clippy

Workspace-level lints: clippy::pedantic at warn, unwrap_used/expect_used/panic all warn. Lint suppressions always include justification comments. Enclave workspace bans filesystem access via clippy.toml.

Rust Contract

Concern Default Banned pattern Proof
Errors thiserror libraries, anyhow binaries, variant data is matchable String error variants and runtime unwrap Unit test matching error variants
Resource ownership RAII and explicit cleanup through Drop where needed Caller-managed cleanup scattered across paths Drop/cleanup test or integration trace
State Actor pattern or policy/state split for shared mutable work Ad hoc mutex contention and hidden polling Concurrency test or actor-level unit test
Unsafe Isolated FFI modules with // SAFETY: comments Inline unsafe in ordinary logic Code review plus clippy
Generics Concrete until the second real use Abstract traits without domain force Deletion/reuse review

Proof

Rust proof should make the failure mode matchable. Tests should assert error variants with matches!, resources should be observed through cleanup behavior, and unsafe code should have a local safety argument. A passing build with hidden unwrap on runtime data is not acceptable proof.

Style Rule Contract

This page follows Style Rule Contract: name the default pattern, banned pattern, reason, exception, proof, and codification path clearly enough that the next agent can apply the rule without asking Kevin again. If a local repo has a stricter rule, follow the local rule and update the wiki when the decision becomes durable.


Timeline