Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    eous

    rust-best-practices

    eous/rust-best-practices
    Coding

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Rust development best practices, patterns, and conventions. Use when writing Rust code, reviewing .rs files, discussing ownership, lifetimes, borrowing, or Cargo configuration.

    SKILL.md

    Rust Best Practices

    Ownership and Borrowing

    Prefer Borrowing Over Ownership

    // Bad - takes ownership unnecessarily
    fn print_name(name: String) {
        println!("{}", name);
    }
    
    // Good - borrows immutably
    fn print_name(name: &str) {
        println!("{}", name);
    }
    

    Use References Appropriately

    // Immutable borrow for reading
    fn calculate_length(s: &String) -> usize {
        s.len()
    }
    
    // Mutable borrow for modification
    fn push_char(s: &mut String, c: char) {
        s.push(c);
    }
    

    Error Handling

    Use Result and Option

    fn find_user(id: u32) -> Option<User> {
        users.get(&id).cloned()
    }
    
    fn parse_config(path: &str) -> Result<Config, ConfigError> {
        let content = fs::read_to_string(path)?;
        toml::from_str(&content).map_err(ConfigError::Parse)
    }
    

    Custom Error Types

    use thiserror::Error;
    
    #[derive(Error, Debug)]
    pub enum AppError {
        #[error("database error: {0}")]
        Database(#[from] sqlx::Error),
    
        #[error("not found: {0}")]
        NotFound(String),
    
        #[error("validation error: {field}")]
        Validation { field: String },
    }
    

    Propagate with ?

    fn process_file(path: &str) -> Result<Data, Error> {
        let content = fs::read_to_string(path)?;
        let parsed = serde_json::from_str(&content)?;
        let validated = validate(parsed)?;
        Ok(validated)
    }
    

    Structs and Enums

    Builder Pattern

    #[derive(Default)]
    pub struct ServerBuilder {
        port: Option<u16>,
        host: Option<String>,
    }
    
    impl ServerBuilder {
        pub fn port(mut self, port: u16) -> Self {
            self.port = Some(port);
            self
        }
    
        pub fn host(mut self, host: impl Into<String>) -> Self {
            self.host = Some(host.into());
            self
        }
    
        pub fn build(self) -> Result<Server, BuildError> {
            Ok(Server {
                port: self.port.unwrap_or(8080),
                host: self.host.unwrap_or_else(|| "localhost".into()),
            })
        }
    }
    

    Newtype Pattern

    pub struct UserId(u64);
    pub struct Email(String);
    
    impl Email {
        pub fn new(email: String) -> Result<Self, ValidationError> {
            if email.contains('@') {
                Ok(Self(email))
            } else {
                Err(ValidationError::InvalidEmail)
            }
        }
    }
    

    Enums for State

    enum ConnectionState {
        Disconnected,
        Connecting { attempt: u32 },
        Connected { session_id: String },
        Error { message: String },
    }
    

    Traits

    Implement Standard Traits

    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    pub struct User {
        pub id: u64,
        pub name: String,
    }
    

    Trait Objects vs Generics

    // Static dispatch (monomorphization)
    fn process<T: Handler>(handler: T) { ... }
    
    // Dynamic dispatch (trait object)
    fn process(handler: &dyn Handler) { ... }
    fn process(handler: Box<dyn Handler>) { ... }
    

    Extension Traits

    pub trait StringExt {
        fn truncate_ellipsis(&self, max_len: usize) -> String;
    }
    
    impl StringExt for str {
        fn truncate_ellipsis(&self, max_len: usize) -> String {
            if self.len() <= max_len {
                self.to_string()
            } else {
                format!("{}...", &self[..max_len - 3])
            }
        }
    }
    

    Lifetimes

    Elision Rules

    // Lifetimes elided - single input reference
    fn first_word(s: &str) -> &str { ... }
    
    // Explicit when multiple inputs
    fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { ... }
    

    Struct Lifetimes

    struct Parser<'a> {
        input: &'a str,
        position: usize,
    }
    
    impl<'a> Parser<'a> {
        fn new(input: &'a str) -> Self {
            Self { input, position: 0 }
        }
    }
    

    Async Rust

    Tokio Patterns

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        let result = fetch_data().await?;
        Ok(())
    }
    
    async fn fetch_data() -> Result<Data, Error> {
        let client = reqwest::Client::new();
        let response = client.get(URL).send().await?;
        response.json().await.map_err(Into::into)
    }
    

    Concurrent Operations

    use futures::future::join_all;
    
    async fn fetch_all(urls: Vec<String>) -> Vec<Result<Response, Error>> {
        let futures: Vec<_> = urls.into_iter()
            .map(|url| fetch_one(url))
            .collect();
    
        join_all(futures).await
    }
    

    Testing

    Unit Tests

    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_add() {
            assert_eq!(add(2, 2), 4);
        }
    
        #[test]
        #[should_panic(expected = "division by zero")]
        fn test_divide_by_zero() {
            divide(1, 0);
        }
    }
    

    Integration Tests

    // tests/integration_test.rs
    use mylib::process;
    
    #[test]
    fn test_full_workflow() {
        let result = process("input");
        assert!(result.is_ok());
    }
    

    Performance

    Avoid Unnecessary Allocations

    // Bad - allocates new String
    fn process(s: &str) -> String {
        s.to_uppercase()
    }
    
    // Good when possible - use Cow
    use std::borrow::Cow;
    fn process(s: &str) -> Cow<str> {
        if s.chars().any(|c| c.is_lowercase()) {
            Cow::Owned(s.to_uppercase())
        } else {
            Cow::Borrowed(s)
        }
    }
    

    Use Iterators

    // Good - lazy, zero-cost
    let sum: i32 = numbers.iter()
        .filter(|n| **n > 0)
        .map(|n| n * 2)
        .sum();
    

    Anti-Patterns to Avoid

    • .unwrap() in production code
    • Excessive .clone() to "fix" borrow checker
    • unsafe without clear justification
    • Ignoring compiler warnings
    • Not using clippy
    • Global mutable state (lazy_static with Mutex)
    Recommended Servers
    Vercel Grep
    Vercel Grep
    Repository
    eous/dotclaude
    Files