rust-review

star 285

Expert Rust code review focused on correctness, testing, and idiomatic code. Use when reviewing a diff, file, or change for bugs, test gaps, and non-idiomatic Rust.

thin-edge By thin-edge schedule Updated 6/9/2026

name: rust-review description: Expert Rust code review focused on correctness, testing, and idiomatic code. Use when reviewing a diff, file, or change for bugs, test gaps, and non-idiomatic Rust.

Perform an expert Rust code review focusing on correctness, testing quality, and idiomatic style.

Input: Optionally specify a file path, glob, or description (e.g., src/mapper.rs, the auth changes). If omitted, review the current working diff.

Steps

  1. Determine what to review

    • If a file or path is given: read that file (or files matching the glob)

    • If a description is given: use it to locate the relevant code by searching the repository, then read it

    • If nothing is given: ask the user which diff scope they want to review, defaulting to the full branch diff against main:

      • Full branch vs main (default) — git diff $(git merge-base main HEAD). Reviews everything the branch introduces, whether committed or not. This is the right default for reviewing a PR.
      • Working changes onlygit diff HEAD. Uncommitted work in the working tree.
      • Staged onlygit diff --staged.

      If the merge-base cannot be resolved (e.g. the branch was not cut from main), fall back to git diff HEAD. If the chosen diff is empty, ask the user what they would like reviewed.

  2. Read the Cargo.toml files

    Always read the root Cargo.toml of the workspace to determine:

    • rust-version (MSRV) — the minimum Rust version guaranteed to compile this code
    • edition — which Rust edition features are available

    Also read the Cargo.toml for any crates directly involved in the code being reviewed, to understand:

    • Which dependencies are available (e.g. thiserror, tokio, async-trait, mockall)
    • Any relevant feature flags

    Do NOT hardcode assumptions about MSRV or edition — always read them fresh.

  3. Review the code

    Analyse the code across three dimensions, in priority order:

    Correctness

    Look for real bugs and logic errors. Flag anything where:

    • Panics in non-test code: unwrap() without justification, direct array/slice indexing without bounds checks. Prefer expect("reason") for invariants, ? for recoverable errors.
    • Silent error swallowing: let _ = result, ignoring Result arms, or .ok() without explanation
    • Off-by-one / overflow: integer arithmetic, iterator ranges, index calculations
    • Incorrect Option/Result handling: returning None/Err where a value should always exist, or vice versa
    • Shared state issues: incorrect use of Arc<Mutex<_>>, potential deadlocks, missing synchronisation
    • Lifetime issues: returned references with incorrect lifetimes, self-referential patterns that are unsound
    • Logic errors that are hard to reason about: even if possibly correct, flag code where correctness is non-obvious and suggest simplifying or adding a comment
    • Blocking code in async context: synchronous operations inside async fn can starve the tokio executor. Flag:
      • std::fs calls — use tokio::fs instead
      • std::net blocking I/O — use tokio::net
      • camino::Utf8Path methods like .exists(), .read_dir(), .metadata() — these are thin wrappers over std::fs and block the thread; use tokio::fs equivalents (e.g. tokio::fs::metadata())
      • Any other syscalls or long-running CPU work that should be moved to tokio::task::spawn_blocking

    Project-specific (thin-edge.io):

    • MQTT topics should go through the typed schema, not hand-built strings. The canonical API lives in crates/core/tedge_api/src/mqtt_topics.rs:

      • Build publish topics with MqttSchema::topic_for(&entity, &channel), using an EntityTopicId and a Channel variant.
      • Build subscription filters with MqttSchema::topics(EntityFilter, ChannelFilter).
      • Parse an incoming topic back with MqttSchema::entity_channel_of(&topic).

      Flag raw string-literal or format!("te/device/...") topics in non-test code: they bypass the schema, are easy to mistype, and don't track the configurable root prefix (MqttSchema::root, default te). When a raw topic is genuinely unavoidable, check its structure against the scheme — the entity identifier is a fixed 4-segment group (device/<name>/<service-kind>/<service>) followed by a channel group (e.g. m/<type>, e/<type>, a/<type>, cmd/<op>/<id>, status/health). The Channel/ChannelFilter enums and the parse method are the authoritative grammar; the doctests on topic_for and topics show worked examples.

    • Actor message ordering assumptions — verify senders and receivers are correctly wired

    • Entity store mutations — check that registration/deregistration is symmetric

    Testing

    • Are there tests covering the changed or added behaviour? If not, note what's missing.
    • Test names should describe the behaviour being tested, not the implementation (e.g. returns_error_when_topic_is_empty not test_parse)
    • Focus: each test should verify one behaviour; split tests that verify multiple things
    • Speed and determinism: flag sleeps (tokio::time::sleep, std::thread::sleep) in tests, flaky network usage, or non-deterministic ordering
    • Edge cases: empty inputs, maximum values, error paths, concurrent access — check they're covered
    • Project conventions:
      • Use #[tokio::test] for async tests
      • Inline #[cfg(test)] modules for unit tests in the same file
      • Separate tests.rs (in the same directory) for larger test suites
      • Use pretty_assertions for readable diffs, test-case for parameterised tests

    Idiomatic Rust

    Based on the MSRV and edition read from Cargo.toml:

    • Prefer ? over explicit match/if let on Result/Option where the intent is clear
    • Iterator adapters over manual loops: .map(), .filter(), .flat_map(), .collect() etc. — but only where it improves readability
    • Unnecessary clones/allocations: .clone() on Copy types, redundant to_string(), avoidable Vec allocations
    • #[derive] everything that can be derived: Clone, Debug, PartialEq, Default, etc.
    • Error types: prefer thiserror in library crates, where errors are part of the public API and callers may need to match on individual variants (project convention). anyhow is acceptable in the binary/application crates that power the shipped executables — where errors are typically propagated to the top level and displayed rather than matched on — as well as in tests and examples.
    • Naming: follow Rust conventions — snake_case for functions/variables, CamelCase for types, SCREAMING_SNAKE_CASE for constants
    • unsafe: flag any usage — it is forbidden in this project
    • Edition idioms: use let-else (1.65+), if let chains, or other features available given the actual MSRV
  4. Write the review

    Structure the output as follows:

    ## Code Review
    
    **Summary**: <1-2 sentence overall assessment>
    
    ---
    
    ### Correctness
    
    1. [critical/warning/note] <finding> — <file>:<line if known>
       > <explanation and suggested fix, with code snippet if helpful>
    
    (repeat for each finding, or write "No issues found." if clean)
    
    ---
    
    ### Testing
    
    - <observation or suggestion>
    - ...
    
    (or "Test coverage looks good." if nothing to add)
    
    ---
    
    ### Idiomatic Rust
    
    - <observation or suggestion>
    - ...
    
    (or "Code is idiomatic." if nothing to add)
    
    ---
    
    **Verdict**: Approve / Request Changes / Needs Discussion
    

    Severity tags:

    • [critical] — likely bug, data loss, panic, or soundness issue
    • [warning] — likely to cause problems, should be fixed
    • [note] — improvement suggestion, not blocking

Guardrails

  • Always read MSRV and edition from Cargo.toml before reviewing — never assume
  • Only flag real problems with clear explanations — do not invent issues
  • Provide concrete suggestions and code snippets, not vague advice
  • Do not re-review code that is not in scope of the diff/file specified
  • If the code under review is a test file, apply correctness and clarity checks but relax the "no unwrap()" rule — panicking tests are acceptable
  • If unsafe appears anywhere, always flag it as [critical] regardless of apparent correctness
  • Formatting: run just format before reviewing so that formatting issues are fixed automatically rather than flagged. If just format is not available, note that the reviewer should run it before treating line-length or formatting observations as blocking.
Install via CLI
npx skills add https://github.com/thin-edge/thin-edge.io --skill rust-review
Repository Details
star Stars 285
call_split Forks 75
navigation Branch main
article Path SKILL.md
More from Creator