Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Prompt Patterns for Rust

The prompts used in this course, collected. Each one delivers a design decision. Make the decision first; the prompt is the delivery.

Setting the contract

Fill in the todo!() bodies without changing any public signature or type definition. If an implementation seems to require a signature change, stop and explain why instead of changing it.

Treat the doc comments as requirements. Ordering, threading, and failure semantics stated there are contracts, not suggestions.

Ownership and lifetimes

Remove clones that exist only to satisfy the borrow checker. Prefer borrowing; move where transfer is the intent. Each remaining clone gets a one-line comment justifying two independent owners.

Remove lifetime parameters from this module’s public API. Exported types own their data; borrows stay internal and short-lived. If the hot path needs zero-copy, provide a borrowed view type alongside an owned type, following the Path and PathBuf pattern.

Restructure to avoid shared mutable state: single owner with borrowed access, channel-passed ownership for the pipeline, Arc without a lock for immutable configuration. Any remaining Mutex documents the invariant it protects.

Types

status is a closed set. Model it as an enum with data on the variants, and let match be exhaustive, with no _ arm.

Introduce CanId as a newtype with a fallible constructor. Raw u16 must not appear past the parse boundary.

These states have costly wrong-state calls. Use the typestate pattern: one type per state, transitions consume self.

begin_maintenance and end_maintenance are a paired-call hazard. Return a guard from begin whose Drop performs end, and remove the manual end.

Errors

Define one DecodeError enum for this module, implementing std::error::Error with a source() chain. Convert all String and Box<dyn Error> returns to it, and attach context at each ? crossing a module boundary.

This function handles external input and must not panic. expect() only for invariants no input can violate, and each use must state in its message why it’s unreachable.

Abstraction

Remove speculative abstraction: inline single-implementation traits unless they are a test seam or a documented extension point. The strategy objects become an enum, since the variant set is closed. Collapse layers that only forward.

Tests

Produce a three-layer suite: (1) golden example tests with noise disabled, pinning the deterministic core; (2) property tests for invariants, starting with severity monotonicity and no-panic-on-any- input; (3) probabilistic tests for each acceptance-table row, with samples, threshold, and threshold origin stated. Use the property and probabilistic testing libraries this project already depends on. Do not seed or disable randomness in layer 3.