Agent Skills: Use default config

Rust coding conventions expert covering naming, formatting, comments, clippy, rustfmt, lints, code style, best practices, and idiomatic patterns.

UncategorizedID: huiali/rust-skills/rust-coding

Install this agent skill to your local

pnpm dlx add-skill https://github.com/huiali/rust-skills/tree/HEAD/.codex/skills/rust-coding

Skill Files

Browse the full folder contents for rust-coding.

Download Skill

Loading file tree…

.codex/skills/rust-coding/SKILL.md

Skill Metadata

Name
rust-coding
Description
Rust coding conventions expert covering naming, formatting, comments, clippy, rustfmt, lints, code style, best practices, and idiomatic patterns.

Naming Conventions (Rust-Specific)

| Rule | Correct | Incorrect | |------|---------|-----------| | No get_ prefix for methods | fn name(&self) | fn get_name(&self) | | Iterator methods | iter() / iter_mut() / into_iter() | get_iter() | | Conversion naming | as_ (cheap), to_ (expensive), into_ (ownership) | Mixed usage | | static variables uppercase | static CONFIG: Config | static config: Config | | const variables | const BUFFER_SIZE: usize = 1024 | No restriction |

General Naming

// Variables and functions: snake_case
let max_connections = 100;
fn process_data() { ... }

// Types and traits: CamelCase
struct UserSession;
trait Cacheable {}

// Constants: SCREAMING_SNAKE_CASE
const MAX_CONNECTIONS: usize = 100;
static CONFIG: once_cell::sync::Lazy<Config> = ...

Solution Patterns

Pattern 1: Conversion Methods

impl Buffer {
    // as_ - cheap, view conversion
    pub fn as_slice(&self) -> &[u8] {
        &self.data
    }

    // to_ - expensive, allocating conversion
    pub fn to_vec(&self) -> Vec<u8> {
        self.data.clone()
    }

    // into_ - consuming, ownership transfer
    pub fn into_vec(self) -> Vec<u8> {
        self.data
    }
}

Pattern 2: Newtype Pattern

// ✅ Domain semantics with newtypes
struct Email(String);
struct UserId(u64);
struct Meters(f64);

impl Email {
    pub fn new(s: impl Into<String>) -> Result<Self, EmailError> {
        let email = s.into();
        if email.contains('@') {
            Ok(Self(email))
        } else {
            Err(EmailError::Invalid)
        }
    }
}

Pattern 3: Error Handling

// ✅ Good: propagate errors
fn read_config() -> Result<Config, ConfigError> {
    let content = std::fs::read_to_string("config.toml")
        .map_err(ConfigError::from)?;
    toml::from_str(&content)
        .map_err(ConfigError::Parse)
}

// ❌ Avoid: panic in library code
fn read_config() -> Config {
    std::fs::read_to_string("config.toml").unwrap()  // panic!
}

// ✅ Use expect when invariant guaranteed
fn get_user(&self) -> &User {
    self.user.as_ref()
        .expect("user always initialized in constructor")
}

Pattern 4: String Handling

// ✅ Accept &str in APIs
fn greet(name: &str) {
    println!("Hello, {}", name);
}

// ✅ Use Cow when might need owned
use std::borrow::Cow;

fn process(input: &str) -> Cow<str> {
    if input.contains("special") {
        Cow::Owned(input.replace("special", "normal"))
    } else {
        Cow::Borrowed(input)
    }
}

// ✅ Pre-allocate when size known
let mut s = String::with_capacity(100);

Data Type Guidelines

| Rule | Description | Example | |------|-------------|---------| | Use newtype | Domain semantics | struct Email(String) | | Use slice patterns | Pattern matching | if let [first, .., last] = slice | | Pre-allocate | Avoid reallocations | Vec::with_capacity() | | Avoid Vec abuse | Fixed size → array | let arr: [u8; 256] |

String Guidelines

| Rule | Description | |------|-------------| | ASCII data use bytes() | s.bytes() faster than s.chars() | | Might modify → Cow<str> | Borrow or owned | | Use format! for concat | Better than + operator | | Avoid nested contains() | O(n*m) complexity |

Error Handling Guidelines

| Rule | Description | |------|-------------| | Use ? to propagate | Don't use try!() macro | | expect() over unwrap() | When value guaranteed | | Use assert! for invariants | At function entry |

Memory and Lifetimes

| Rule | Description | |------|-------------| | Meaningful lifetime names | 'src, 'ctx not just 'a | | RefCell use try_borrow | Avoid panics | | Use shadowing for conversions | let x = x.parse()? |

Concurrency Guidelines

| Rule | Description | |------|-------------| | Define lock ordering | Prevent deadlocks | | Atomics for primitives | Not Mutex<bool> | | Choose memory ordering carefully | Relaxed/Acquire/Release/SeqCst |

Async Guidelines

| Rule | Description | |------|-------------| | CPU-bound → sync | Async for I/O | | Don't hold locks across await | Use scoped guards |

Macro Guidelines

| Rule | Description | |------|-------------| | Avoid macros (unless necessary) | Prefer functions/generics | | Macro input like Rust | Readability first |

Deprecated Patterns → Modern

| Deprecated | Modern | Version | |-----------|---------|---------| | lazy_static! | std::sync::OnceLock | 1.70 | | once_cell::Lazy | std::sync::LazyLock | 1.80 | | std::sync::mpsc | crossbeam::channel | - | | std::sync::Mutex | parking_lot::Mutex | - | | failure/error-chain | thiserror/anyhow | - | | try!() | ? operator | 2018 |

Clippy Configuration

[package]
edition = "2024"
rust-version = "1.85"

[lints.rust]
unsafe_code = "warn"

[lints.clippy]
all = "warn"
pedantic = "warn"

Common Clippy Lints

| Lint | Description | |------|-------------| | clippy::all | Enable all warnings | | clippy::pedantic | Stricter checks | | clippy::unwrap_used | Avoid unwrap | | clippy::expect_used | Prefer expect | | clippy::clone_on_ref_ptr | Avoid cloning Arc |

Formatting (rustfmt)

# Use default config
rustfmt src/lib.rs

# Check formatting
rustfmt --check src/lib.rs

# Config file: .rustfmt.toml
max_width = 100
tab_spaces = 4
edition = "2024"

Documentation Guidelines

/// Module documentation
//! This module handles user authentication...

/// Struct documentation
///
/// # Examples
/// ```
/// let user = User::new("name");
/// ```
pub struct User { ... }

/// Method documentation
///
/// # Arguments
///
/// * `name` - User name
///
/// # Returns
///
/// Initialized user instance
///
/// # Panics
///
/// Panics when name is empty
pub fn new(name: &str) -> Self { ... }

Workflow

Step 1: Name Things Properly

Choosing a name?
  → Function/variable? snake_case
  → Type/trait? CamelCase
  → Constant? SCREAMING_SNAKE_CASE
  → Conversion method?
    - Cheap view? as_foo()
    - Expensive? to_foo()
    - Consuming? into_foo()

Step 2: Format Code

# Run rustfmt
cargo fmt

# Check formatting in CI
cargo fmt --check

# Fix clippy warnings
cargo clippy --fix

Step 3: Review Idioms

Check:
  → No unnecessary clone()
  → Use ? not unwrap()
  → &str in function parameters
  → Iterator methods not index loops
  → Meaningful error types

Quick Reference

Naming: snake_case (fn/var), CamelCase (type), SCREAMING_SNAKE_CASE (const)
Format: rustfmt (just use it)
Docs: /// for public items, //! for module docs
Lint: #![warn(clippy::all)]

Review Checklist

When reviewing code:

  • [ ] Naming follows Rust conventions
  • [ ] Using ? instead of unwrap()
  • [ ] Avoiding unnecessary clone()
  • [ ] unsafe blocks have SAFETY comments
  • [ ] Public APIs have doc comments
  • [ ] Ran cargo clippy
  • [ ] Ran cargo fmt
  • [ ] No get_ prefix on accessor methods
  • [ ] Conversion methods named correctly (as/to/into)
  • [ ] String parameters use &str when possible

Verification Commands

# Format check
cargo fmt --check

# Lint check
cargo clippy -- -D warnings

# Documentation check
cargo doc --no-deps --open

# Run tests
cargo test

# Check naming conventions
cargo clippy -- -W clippy::wrong_self_convention

Common Pitfalls

1. Wrong Method Naming

Symptom: Clippy warning wrong_self_convention

// ❌ Bad: unnecessary get_ prefix
impl User {
    fn get_name(&self) -> &str { &self.name }
}

// ✅ Good: direct accessor
impl User {
    fn name(&self) -> &str { &self.name }
}

2. String Type Misuse

Symptom: Unnecessary allocations

// ❌ Bad: forces allocation
fn greet(name: String) {
    println!("Hello, {}", name);
}

// ✅ Good: accepts borrowed or owned
fn greet(name: &str) {
    println!("Hello, {}", name);
}

// Both work now:
greet("Alice");  // &str
greet(&owned_string);  // &String → &str

3. Index Loops

Symptom: Less idiomatic, error-prone

// ❌ Bad: manual indexing
for i in 0..items.len() {
    println!("{}: {}", i, items[i]);
}

// ✅ Good: iterator
for item in &items {
    println!("{}", item);
}

// ✅ Good: with index
for (i, item) in items.iter().enumerate() {
    println!("{}: {}", i, item);
}

Related Skills

  • rust-anti-pattern - What not to do
  • rust-error - Error handling patterns
  • rust-performance - Performance idioms
  • rust-async - Async conventions
  • rust-unsafe - SAFETY comment style

Localized Reference

  • Chinese version: SKILL_ZH.md - 完整中文版本,包含所有内容