coding-rustlisted
Install: claude install-skill bitranox/bitranox-skills
# coding-rust
Idioms and review checks for Rust, distilled from real review findings. Apply when writing or
reviewing Rust; each rule states the failure it prevents.
## Errors
- **Never use `std::io::Error::new(...)` / `std::io::Error::other(...)` for a non-IO condition.** A
synthetic IO error erases the type, so callers cannot pattern-match on what went wrong. Add a
dedicated variant to the crate's own error enum instead, with `thiserror`:
```rust
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("frobnicator {0} is out of range")]
OutOfRange(u32),
#[error(transparent)]
Io(#[from] std::io::Error), // real IO stays IO
}
```
- **Preserve the error chain.** Wrap with context (`anyhow::Context::context`, or a `#[from]`/`#[source]`
on a typed variant) rather than discarding the cause behind a fresh generic message. The source chain
is what makes a failure debuggable.
## Secrets and credentials
- **Constant-time comparison for secrets** (passwords, tokens, HMAC/auth responses). A short-circuiting
`iter.zip(other).all(|(a, b)| a == b)` leaks length/prefix timing. Use an XOR-fold (or a vetted
constant-time crate such as `subtle`):
```rust
let equal = expected.iter().zip(response)
.fold(0u8, |acc, (a, b)| acc | (a ^ b)) == 0
&& expected.len() == response.len();
```
- **`--password-file PATH` is the primary CLI interface for a secret, `--password VALUE` only a
convenience fallback.** An inline value is