Stand rust
Rust coding standards. Use when writing Rust code. Covers edition, error handling with thiserror/anyhow, unsafe policy, type patterns, testing, documentation, and dependency management.From its SKILL.md
npx -y skills add lgtm-hq/ai-skills --skill stand-rustAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.0 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it
Rust Standards
Standards for Rust code.
Edition
- Use the latest stable edition (2021+)
- Set
editionexplicitly inCargo.toml
Toolchain
- Follow the
lintskill for formatting and linting — lintro runsrustfmt,clippy,cargo_audit, andcargo_denyas configured - Treat clippy warnings as errors in CI (
-D warnings) - Customize formatting via
rustfmt.tomlwhere needed
Error Handling
-
Use
thiserrorfor library error types — derive structured, typed errors -
Use
anyhowfor application-level error propagation -
No
.unwrap()in library code — use?or returnResult -
.expect()only with descriptive messages explaining the invariant:// Good let config = load_config().expect("config.toml must exist at startup"); // Bad let config = load_config().unwrap(); -
Implement
std::fmt::Displayfor all custom error types -
Non-panicking
.unwrap_or_default()/.unwrap_or()over trivial-arm matches:// Don't let count = match maybe_count { Some(n) => n, None => 0, }; // Do let count = maybe_count.unwrap_or(0);
Type Patterns
- Prefer newtypes for domain concepts —
struct UserId(u64)over bareu64 - Use
impl Traitin argument position for flexibility; explicit generics in return position for clarity - Derive
Debugon all public types - Derive
Clone,PartialEq,Eq,Hashwhere semantically appropriate - Prefer
&stroverStringin function arguments; returnStringwhen ownership transfers
Unsafe
-
unsafeblocks MUST include a// SAFETY:comment justifying soundness:// SAFETY: pointer is guaranteed non-null by the allocator contract, // and the lifetime is bounded by the enclosing scope. unsafe { ptr.as_ref() } -
Minimize unsafe surface area — encapsulate in safe abstractions
-
Prefer safe alternatives (e.g.,
std::sync::Mutexover raw atomics) unless performance demands otherwise
Documentation
-
///doc comments on all public items (functions, types, traits, modules) -
Include code examples in doc comments for non-trivial APIs:
/// Parse a duration string like "5s", "100ms", or "2m". /// /// # Examples /// /// ``` /// use mycrate::parse_duration; /// /// let d = parse_duration("5s").unwrap(); /// assert_eq!(d, std::time::Duration::from_secs(5)); /// ``` pub fn parse_duration(s: &str) -> Result<Duration> { ... } -
Use
#![deny(missing_docs)]for library crates -
Module-level
//!doc comments for crate and module overviews
Testing
- Unit tests in
#[cfg(test)] mod testswithin the same file - Integration tests in
tests/directory - Use
#[should_panic(expected = "...")]for expected panics - Consider
proptestorquickcheckfor property-based testing where valuable - Use
assert_eq!andassert_ne!over bareassert!for better error messages
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_duration_seconds() {
let d = parse_duration("5s").unwrap();
assert_eq!(d, Duration::from_secs(5));
}
#[test]
#[should_panic(expected = "invalid format")]
fn parse_duration_rejects_garbage() {
parse_duration("not_a_duration").unwrap();
}
}
Dependencies
- Keep the dependency tree minimal — every dependency is an audit and supply chain surface
- Run vulnerability scanning via lintro (
uv run lintro chkincludescargo_auditandcargo_deny) - Pin versions in workspace
Cargo.tomlfor multi-crate workspaces - Prefer well-maintained crates with active maintainers and good documentation
Patterns
-
Prefer
implblocks over free functions for associated behavior -
Use the builder pattern for types with many optional fields
-
Prefer iterators and combinators over manual loops where readability permits
-
let-elseover nestedif letpyramids:// Don't if let Some(user) = lookup(id) { if let Some(email) = user.email { send(email); } } // Do let Some(user) = lookup(id) else { return }; let Some(email) = user.email else { return }; send(email); -
.find()/.position()/.any()over manual index loops:// Don't let mut idx = None; for (i, item) in items.iter().enumerate() { if item.id == target { idx = Some(i); break; } } // Do let idx = items.iter().position(|item| item.id == target); -
matches!()for pattern booleans:// Don't let is_ready = match state { State::Ready => true, _ => false, }; // Do let is_ready = matches!(state, State::Ready); -
Use
#[must_use]on functions whose return value should not be ignored -
Prefer
From/Intoimplementations over ad-hoc conversion methods
Linting
Follow the lint skill for linting and formatting workflow.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.