Agent Skills: Rust Core

>

UncategorizedID: CodeAtCode/oss-ai-skills/rust-core

Install this agent skill to your local

pnpm dlx add-skill https://github.com/CodeAtCode/oss-ai-skills/tree/HEAD/languages/rust-core

Skill Files

Browse the full folder contents for rust-core.

Download Skill

Loading file tree…

languages/rust-core/SKILL.md

Skill Metadata

Name
rust-core
Description
>

Rust Core

Comprehensive guide for writing high-quality, idiomatic, and optimized Rust code. Targets Rust 1.80+ and Edition 2024.

When to Apply

  • Writing new Rust functions, structs, or modules
  • Implementing error handling or async code
  • Designing public APIs for libraries
  • Reviewing code for ownership/borrowing issues
  • Optimizing memory usage or reducing allocations
  • Tuning performance for hot paths
  • Refactoring existing Rust code
  • Fixing compiler errors (see references/compiler-errors.md)

Edition 2024 Changes (Rust 1.85+)

| Change | Impact | Action | |--------|--------|--------| | unsafe blocks required for extern blocks | extern "C" { ... } now needs unsafe { extern "C" { ... } } | Wrap extern blocks in unsafe | | unsafe_op_in_unsafe_fn lint | unsafe fn body requires explicit unsafe blocks for unsafe ops | Add unsafe { ... } inside unsafe fns | | if let temporary scope | Temporaries dropped at end of if let block | May extend borrow lifetimes | | gen keyword reserved | gen { ... } blocks for iterators | Use gen for lazy iterators | | #[diagnostic::on_unimplemented] | Better error messages for trait failures | Add to library traits | | Nested or-patterns | Some(1 \| 2) stabilized | Use in match arms |

Run cargo fix --edition to apply most changes automatically.

Rule Categories by Priority

| Priority | Category | Prefix | Rules | |----------|----------|--------|-------| | 1 | Ownership & Borrowing | own- | 12 | | 2 | Error Handling | err- | 12 | | 3 | Memory Optimization | mem- | 15 | | 4 | API Design | api- | 15 | | 5 | Async/Await | async- | 15 | | 6 | Compiler Optimization | opt- | 12 | | 7 | Naming Conventions | name- | 16 | | 8 | Type Safety | type- | 10 | | 9 | Testing | test- | 13 | | 10 | Documentation | doc- | 11 | | 11 | Performance Patterns | perf- | 11 | | 12 | Project Structure | proj- | 11 | | 13 | Clippy & Linting | lint- | 11 | | 14 | Anti-patterns | anti- | 15 |

Detailed rules live in rules/ — read on demand by prefix.

Rule Index

Ownership & Borrowing (own-)

| Rule | Description | |------|-------------| | own-borrow-over-clone | Prefer &T borrowing over .clone() | | own-slice-over-vec | Accept &[T] not &Vec<T>, &str not &String | | own-cow-conditional | Use Cow<'a, T> for conditional ownership | | own-arc-shared | Use Arc<T> for thread-safe shared ownership | | own-rc-single-thread | Use Rc<T> for single-threaded sharing | | own-refcell-interior | Use RefCell<T> for interior mutability (single-thread) | | own-mutex-interior | Use Mutex<T> for interior mutability (multi-thread) | | own-rwlock-readers | Use RwLock<T> when reads dominate writes | | own-copy-small | Derive Copy for small, trivial types | | own-clone-explicit | Make Clone explicit, avoid implicit copies | | own-move-large | Move large data instead of cloning | | own-lifetime-elision | Rely on lifetime elision when possible |

Error Handling (err-)

| Rule | Description | |------|-------------| | err-thiserror-lib | Use thiserror for library error types | | err-anyhow-app | Use anyhow for application error handling | | err-result-over-panic | Return Result, don't panic on expected errors | | err-context-chain | Add context with .context() or .with_context() | | err-no-unwrap-prod | Never use .unwrap() in production code | | err-expect-bugs-only | Use .expect() only for programming errors | | err-question-mark | Use ? operator for clean propagation | | err-from-impl | Use #[from] for automatic error conversion | | err-source-chain | Use #[source] to chain underlying errors | | err-lowercase-msg | Error messages: lowercase, no trailing punctuation | | err-doc-errors | Document errors with # Errors section | | err-custom-type | Create custom error types, not Box<dyn Error> |

Memory Optimization (mem-)

| Rule | Description | |------|-------------| | mem-with-capacity | Use with_capacity() when size is known | | mem-smallvec | Use SmallVec for usually-small collections | | mem-arrayvec | Use ArrayVec for bounded-size collections | | mem-box-large-variant | Box large enum variants to reduce type size | | mem-boxed-slice | Use Box<[T]> instead of Vec<T> when fixed | | mem-thinvec | Use ThinVec for often-empty vectors | | mem-clone-from | Use clone_from() to reuse allocations | | mem-reuse-collections | Reuse collections with clear() in loops | | mem-avoid-format | Avoid format!() when string literals work | | mem-write-over-format | Use write!() instead of format!() | | mem-arena-allocator | Use arena allocators for batch allocations | | mem-zero-copy | Use zero-copy patterns with slices and Bytes | | mem-compact-string | Use CompactString for small string optimization | | mem-smaller-integers | Use smallest integer type that fits | | mem-assert-type-size | Assert hot type sizes to prevent regressions |

API Design (api-)

| Rule | Description | |------|-------------| | api-builder-pattern | Use Builder pattern for complex construction | | api-builder-must-use | Add #[must_use] to builder types | | api-newtype-safety | Use newtypes for type-safe distinctions | | api-typestate | Use typestate for compile-time state machines | | api-sealed-trait | Seal traits to prevent external implementations | | api-extension-trait | Use extension traits to add methods to foreign types | | api-parse-dont-validate | Parse into validated types at boundaries | | api-impl-into | Accept impl Into<T> for flexible string inputs | | api-impl-asref | Accept impl AsRef<T> for borrowed inputs | | api-must-use | Add #[must_use] to Result-returning functions | | api-non-exhaustive | Use #[non_exhaustive] for future-proof enums/structs | | api-from-not-into | Implement From, not Into (auto-derived) | | api-default-impl | Implement Default for sensible defaults | | api-common-traits | Implement Debug, Clone, PartialEq eagerly | | api-serde-optional | Gate Serialize/Deserialize behind feature flag |

Async/Await (async-)

| Rule | Description | |------|-------------| | async-tokio-runtime | Use Tokio for production async runtime | | async-no-lock-await | Never hold Mutex/RwLock across .await | | async-spawn-blocking | Use spawn_blocking for CPU-intensive work | | async-tokio-fs | Use tokio::fs not std::fs in async code | | async-cancellation-token | Use CancellationToken for graceful shutdown | | async-join-parallel | Use tokio::join! for parallel operations | | async-try-join | Use tokio::try_join! for fallible parallel ops | | async-select-racing | Use tokio::select! for racing/timeouts | | async-bounded-channel | Use bounded channels for backpressure | | async-mpsc-queue | Use mpsc for work queues | | async-broadcast-pubsub | Use broadcast for pub/sub patterns | | async-watch-latest | Use watch for latest-value sharing | | async-oneshot-response | Use oneshot for request/response | | async-joinset-structured | Use JoinSet for dynamic task groups | | async-clone-before-await | Clone data before await, release locks |

Compiler Optimization (opt-)

| Rule | Description | |------|-------------| | opt-inline-small | Use #[inline] for small hot functions | | opt-inline-always-rare | Use #[inline(always)] sparingly | | opt-inline-never-cold | Use #[inline(never)] for cold paths | | opt-cold-unlikely | Use #[cold] for error/unlikely paths | | opt-likely-hint | Use likely()/unlikely() for branch hints | | opt-lto-release | Enable LTO in release builds | | opt-codegen-units | Use codegen-units = 1 for max optimization | | opt-pgo-profile | Use PGO for production builds | | opt-target-cpu | Set target-cpu=native for local builds | | opt-bounds-check | Use iterators to avoid bounds checks | | opt-simd-portable | Use portable SIMD for data-parallel ops | | opt-cache-friendly | Design cache-friendly data layouts (SoA) |

Naming Conventions (name-)

| Rule | Description | |------|-------------| | name-types-camel | Use UpperCamelCase for types, traits, enums | | name-variants-camel | Use UpperCamelCase for enum variants | | name-funcs-snake | Use snake_case for functions, methods, modules | | name-consts-screaming | Use SCREAMING_SNAKE_CASE for constants/statics | | name-lifetime-short | Use short lowercase lifetimes: 'a, 'de, 'src | | name-type-param-single | Use single uppercase for type params: T, E, K, V | | name-as-free | as_ prefix: free reference conversion | | name-to-expensive | to_ prefix: expensive conversion | | name-into-ownership | into_ prefix: ownership transfer | | name-no-get-prefix | No get_ prefix for simple getters | | name-is-has-bool | Use is_, has_, can_ for boolean methods | | name-iter-convention | Use iter/iter_mut/into_iter for iterators | | name-iter-method | Name iterator methods consistently | | name-iter-type-match | Iterator type names match method | | name-acronym-word | Treat acronyms as words: Uuid not UUID | | name-crate-no-rs | Crate names: no -rs suffix |

Type Safety (type-)

| Rule | Description | |------|-------------| | type-newtype-ids | Wrap IDs in newtypes: UserId(u64) | | type-newtype-validated | Newtypes for validated data: Email, Url | | type-enum-states | Use enums for mutually exclusive states | | type-option-nullable | Use Option<T> for nullable values | | type-result-fallible | Use Result<T, E> for fallible operations | | type-phantom-marker | Use PhantomData<T> for type-level markers | | type-never-diverge | Use ! type for functions that never return | | type-generic-bounds | Add trait bounds only where needed | | type-no-stringly | Avoid stringly-typed APIs, use enums/newtypes | | type-repr-transparent | Use #[repr(transparent)] for FFI newtypes |

Testing (test-)

| Rule | Description | |------|-------------| | test-cfg-test-module | Use #[cfg(test)] mod tests { } | | test-use-super | Use use super::*; in test modules | | test-integration-dir | Put integration tests in tests/ directory | | test-descriptive-names | Use descriptive test names | | test-arrange-act-assert | Structure tests as arrange/act/assert | | test-proptest-properties | Use proptest for property-based testing | | test-mockall-mocking | Use mockall for trait mocking | | test-mock-traits | Use traits for dependencies to enable mocking | | test-fixture-raii | Use RAII pattern (Drop) for test cleanup | | test-tokio-async | Use #[tokio::test] for async tests | | test-should-panic | Use #[should_panic] for panic tests | | test-criterion-bench | Use criterion for benchmarking | | test-doctest-examples | Keep doc examples as executable tests |

Documentation (doc-)

| Rule | Description | |------|-------------| | doc-all-public | Document all public items with /// | | doc-module-inner | Use //! for module-level documentation | | doc-examples-section | Include # Examples with runnable code | | doc-errors-section | Include # Errors for fallible functions | | doc-panics-section | Include # Panics for panicking functions | | doc-safety-section | Include # Safety for unsafe functions | | doc-question-mark | Use ? in examples, not .unwrap() | | doc-hidden-setup | Use # prefix to hide example setup code | | doc-intra-links | Use intra-doc links: [Vec] | | doc-link-types | Link related types and functions in docs | | doc-cargo-metadata | Fill Cargo.toml metadata |

Performance Patterns (perf-)

| Rule | Description | |------|-------------| | perf-iter-over-index | Prefer iterators over manual indexing | | perf-iter-lazy | Keep iterators lazy, collect() only when needed | | perf-collect-once | Don't collect() intermediate iterators | | perf-entry-api | Use entry() API for map insert-or-update | | perf-drain-reuse | Use drain() to reuse allocations | | perf-extend-batch | Use extend() for batch insertions | | perf-chain-avoid | Avoid chain() in hot loops | | perf-collect-into | Use collect_into() for reusing containers | | perf-black-box-bench | Use black_box() in benchmarks | | perf-release-profile | Optimize release profile settings | | perf-profile-first | Profile before optimizing |

Project Structure (proj-)

| Rule | Description | |------|-------------| | proj-lib-main-split | Keep main.rs minimal, logic in lib.rs | | proj-mod-by-feature | Organize modules by feature, not type | | proj-flat-small | Keep small projects flat | | proj-mod-rs-dir | Use mod.rs for multi-file modules | | proj-pub-crate-internal | Use pub(crate) for internal APIs | | proj-pub-super-parent | Use pub(super) for parent-only visibility | | proj-pub-use-reexport | Use pub use for clean public API | | proj-prelude-module | Create prelude module for common imports | | proj-bin-dir | Put multiple binaries in src/bin/ | | proj-workspace-large | Use workspaces for large projects | | proj-workspace-deps | Use workspace dependency inheritance |

Clippy & Linting (lint-)

| Rule | Description | |------|-------------| | lint-deny-correctness | #![deny(clippy::correctness)] | | lint-warn-suspicious | #![warn(clippy::suspicious)] | | lint-warn-style | #![warn(clippy::style)] | | lint-warn-complexity | #![warn(clippy::complexity)] | | lint-warn-perf | #![warn(clippy::perf)] | | lint-pedantic-selective | Enable clippy::pedantic selectively | | lint-missing-docs | #![warn(missing_docs)] | | lint-unsafe-doc | #![warn(clippy::undocumented_unsafe_blocks)] | | lint-cargo-metadata | #![warn(clippy::cargo)] for published crates | | lint-rustfmt-check | Run cargo fmt --check in CI | | lint-workspace-lints | Configure lints at workspace level |

Anti-patterns (anti-)

| Rule | Description | |------|-------------| | anti-unwrap-abuse | Don't use .unwrap() in production code | | anti-expect-lazy | Don't use .expect() for recoverable errors | | anti-clone-excessive | Don't clone when borrowing works | | anti-lock-across-await | Don't hold locks across .await | | anti-string-for-str | Don't accept &String when &str works | | anti-vec-for-slice | Don't accept &Vec<T> when &[T] works | | anti-index-over-iter | Don't use indexing when iterators work | | anti-panic-expected | Don't panic on expected/recoverable errors | | anti-empty-catch | Don't use empty if let Err(_) = ... blocks | | anti-over-abstraction | Don't over-abstract with excessive generics | | anti-premature-optimize | Don't optimize before profiling | | anti-type-erasure | Don't use Box<dyn Trait> when impl Trait works | | anti-format-hot-path | Don't use format!() in hot paths | | anti-collect-intermediate | Don't collect() intermediate iterators | | anti-stringly-typed | Don't use strings for structured data |

Ownership & Borrowing

  • Prefer &T borrowing over .clone()
  • Accept &[T] not &Vec<T>, &str not &String
  • Use Cow<'a, T> for conditional ownership
  • Use Arc<T> for thread-safe shared ownership, Rc<T> for single-threaded
  • Use RefCell<T> (single-thread) or Mutex<T>/RwLock<T> (multi-thread) for interior mutability
  • Derive Copy for small, trivial types
  • Move large data instead of cloning
  • Rely on lifetime elision when possible

Error Handling

  • Use thiserror for library error types, anyhow for application error handling
  • Return Result, don't panic on expected errors
  • Add context with .context() or .with_context()
  • Never use .unwrap() in production code
  • Use .expect() only for programming errors
  • Use ? operator for clean propagation
  • Use #[from] for automatic error conversion
  • Use #[source] to chain underlying errors
  • Error messages: lowercase, no trailing punctuation
  • Document errors with # Errors section
  • Create custom error types, not Box<dyn Error>

Memory Optimization

  • Use with_capacity() when size is known
  • Use SmallVec for usually-small collections, ArrayVec for bounded-size
  • Box large enum variants to reduce type size
  • Use Box<[T]> instead of Vec<T> when fixed size
  • Use clone_from() to reuse allocations
  • Reuse collections with clear() in loops
  • Avoid format!() when string literals work; use write!() instead
  • Use smallest integer type that fits
  • Assert hot type sizes to prevent regressions

API Design

  • Use Builder pattern for complex construction; add #[must_use] to builder types
  • Use newtypes for type-safe distinctions (UserId(u64), Email, Url)
  • Use typestate for compile-time state machines
  • Seal traits to prevent external implementations when appropriate
  • Use extension traits to add methods to foreign types
  • Parse into validated types at boundaries
  • Accept impl Into<T> for flexible string inputs, impl AsRef<T> for borrowed inputs
  • Add #[must_use] to Result-returning functions
  • Use #[non_exhaustive] for future-proof enums/structs
  • Implement From, not Into (auto-derived)
  • Implement Default for sensible defaults
  • Implement Debug, Clone, PartialEq eagerly
  • Gate Serialize/Deserialize behind feature flag

Async/Await

  • Use Tokio for production async runtime
  • Never hold Mutex/RwLock across .await
  • Use spawn_blocking for CPU-intensive work
  • Use tokio::fs not std::fs in async code
  • Use CancellationToken for graceful shutdown
  • Use tokio::join! for parallel operations, tokio::try_join! for fallible
  • Use tokio::select! for racing/timeouts
  • Use bounded channels for backpressure
  • Use JoinSet for dynamic task groups
  • Clone data before await, release locks

Testing

  • Use #[cfg(test)] mod tests { } with use super::*;
  • Put integration tests in tests/ directory
  • Structure tests as arrange/act/assert
  • Use #[tokio::test] for async tests
  • Use proptest for property-based testing
  • Use mockall for trait mocking; design dependencies as traits
  • Use RAII pattern (Drop) for test cleanup
  • Use criterion for benchmarking
  • Keep doc examples as executable tests
  • Use #[should_panic] for panic tests
  • Aim for 80%+ coverage; test edge cases and error paths

Anti-Patterns

  • Don't use .unwrap() in production code
  • Don't use .expect() for recoverable errors
  • Don't clone when borrowing works
  • Don't hold locks across .await
  • Don't accept &String when &str works, &Vec<T> when &[T] works
  • Don't use indexing when iterators work
  • Don't panic on expected/recoverable errors
  • Don't use empty if let Err(_) = ... blocks
  • Don't over-abstract with excessive generics
  • Don't optimize before profiling
  • Don't use Box<dyn Trait> when impl Trait works
  • Don't use format!() in hot paths
  • Don't collect() intermediate iterators
  • Don't use strings for structured data

Essential Commands

cargo build --release    # Build with optimizations
cargo test                # Run all tests
cargo test -- --nocapture # Run tests with output
cargo clippy -- -D warnings  # Lint with warnings as errors
cargo fmt --check         # Check formatting
cargo doc --no-deps       # Generate documentation
cargo bench               # Run benchmarks
cargo fix --edition       # Auto-fix edition migration

Cargo.toml Release Profile

[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true

[profile.dev.package."*"]
opt-level = 3

References

  • rules/ — 179 detailed rule files organized by prefix (read on demand)
  • references/compiler-errors.md — Compiler error quick reference (E0382, E0502, E0716, etc.)