Communitygithub.com

rust-patterns

Padrões idiomáticos Rust, ownership, tratamento de erros, traits, concorrência e melhores práticas para construir aplicações seguras e eficientes. Use ao escrever ou revisar código Rust onde ownership, tratamento de erros, traits ou concorrência estejam em questão.

O que é rust-patterns?

Esta skill oferece um conjunto abrangente de padrões e práticas recomendadas para o desenvolvimento em Rust, focando em seis áreas principais: ownership e borrowing para prevenir condições de corrida em tempo de compilação, tratamento de erros com `Result`/`?` usando `thiserror` para bibliotecas e `anyhow` para aplicações, enums e pattern matching exaustivo para tornar estados ilegais não representáveis, traits e genéricos para abstração de custo zero, concorrência segura via `Arc<Mutex<T>>`, canais e async/await, e superfícies `pub` mínimas organizadas por domínio. É útil ao escrever código novo, revisar código existente, refatorar, ou projetar a estrutura de crates e módulos. A skill é compatível com qualquer ambiente onde Rust é usado, desde sistemas embarcados até aplicações web, e se baseia em convenções da comunidade como descritas no guia Rust API Guidelines e no Rust by Example. Ela reforça princípios como 'empreste, não clone', 'torne estados ilegais não representáveis' e 'use `?` em vez de `unwrap()`' para garantir código robusto e de alto desempenho.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/rust-patterns

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Padrões de Desenvolvimento Rust

Padrões idiomáticos Rust e melhores práticas para construir aplicações seguras, eficientes e fáceis de manter.

Quando Usar

  • Escrevendo código Rust novo
  • Revisando código Rust
  • Refatorando código Rust existente
  • Projetando estrutura de crate e layout de módulos

Como Funciona

Esta skill impõe convenções idiomáticas Rust em seis áreas principais: ownership e borrowing para prevenir condições de corrida em tempo de compilação, propagação de erros com Result/? usando thiserror para bibliotecas e anyhow para aplicações, enums e pattern matching exaustivo para tornar estados ilegais não representáveis, traits e genéricos para abstração de custo zero, concorrência segura via Arc<Mutex<T>>, canais e async/await, e superfícies pub mínimas organizadas por domínio.

Princípios Fundamentais

1. Ownership e Borrowing

O sistema de ownership do Rust previne condições de corrida e bugs de memória em tempo de compilação.

// Bom: Passe referências quando não precisar de ownership
fn process(data: &[u8]) -> usize {
    data.len()
}

// Bom: Assuma ownership apenas quando precisar armazenar ou consumir
fn store(data: Vec<u8>) -> Record {
    Record { payload: data }
}

// Ruim: Clonar desnecessariamente para evitar o borrow checker
fn process_bad(data: &Vec<u8>) -> usize {
    let cloned = data.clone(); // Desperdício — apenas empreste
    cloned.len()
}

Use Cow para Ownership Flexível

use std::borrow::Cow;

fn normalize(input: &str) -> Cow<'_, str> {
    if input.contains(' ') {
        Cow::Owned(input.replace(' ', "_"))
    } else {
        Cow::Borrowed(input) // Custo zero quando nenhuma mutação é necessária
    }
}

Tratamento de Erros

Use Result e ? — Nunca unwrap() em Produção

// Bom: Propague erros com contexto
use anyhow::{Context, Result};

fn load_config(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("falha ao ler config de {path}"))?;
    let config: Config = toml::from_str(&content)
        .with_context(|| format!("falha ao analisar config de {path}"))?;
    Ok(config)
}

// Ruim: Panic ao encontrar erro
fn load_config_bad(path: &str) -> Config {
    let content = std::fs::read_to_string(path).unwrap(); // Panic!
    toml::from_str(&content).unwrap()
}

Erros de Biblioteca com thiserror, Erros de Aplicação com anyhow

// Código de biblioteca: erros estruturados e tipados
use thiserror::Error;

#[derive(Debug, Error)]
pub enum StorageError {
    #[error("registro não encontrado: {id}")]
    NotFound { id: String },
    #[error("conexão falhou")]
    Connection(#[from] std::io::Error),
    #[error("dados inválidos: {0}")]
    InvalidData(String),
}

// Código de aplicação: tratamento de erros flexível
use anyhow::{bail, Result};

fn run() -> Result<()> {
    let config = load_config("app.toml")?;
    if config.workers == 0 {
        bail!("contagem de workers deve ser > 0");
    }
    Ok(())
}

Combinadores de Option em Vez de Match Aninhado

// Bom: Encadeamento de combinadores
fn find_user_email(users: &[User], id: u64) -> Option<String> {
    users.iter()
        .find(|u| u.id == id)
        .map(|u| u.email.clone())
}

// Ruim: Match profundamente aninhado
fn find_user_email_bad(users: &[User], id: u64) -> Option<String> {
    match users.iter().find(|u| u.id == id) {
        Some(user) => match &user.email {
            email => Some(email.clone()),
        },
        None => None,
    }
}

Enums e Pattern Matching

Modele Estados como Enums

// Bom: Estados impossíveis são não representáveis
enum ConnectionState {
    Disconnected,
    Connecting { attempt: u32 },
    Connected { session_id: String },
    Failed { reason: String, retries: u32 },
}

fn handle(state: &ConnectionState) {
    match state {
        ConnectionState::Disconnected => connect(),
        ConnectionState::Connecting { attempt } if *attempt > 3 => abort(),
        ConnectionState::Connecting { .. } => wait(),
        ConnectionState::Connected { session_id } => use_session(session_id),
        ConnectionState::Failed { retries, .. } if *retries < 5 => retry(),
        ConnectionState::Failed { reason, .. } => log_failure(reason),
    }
}

Matching Exaustivo — Sem Catch-All para Lógica de Negócio

// Bom: Trate cada variante explicitamente
match command {
    Command::Start => start_service(),
    Command::Stop => stop_service(),
    Command::Restart => restart_service(),
    // Adicionar uma nova variante força tratamento aqui
}

// Ruim: Wildcard esconde novas variantes
match command {
    Command::Start => start_service(),
    _ => {} // Ignora silenciosamente Stop, Restart e variantes futuras
}

Traits e Genéricos

Aceite Genéricos, Retorne Tipos Concretos

// Bom: Entrada genérica, saída concreta
fn read_all(reader: &mut impl Read) -> std::io::Result<Vec<u8>> {
    let mut buf = Vec::new();
    reader.read_to_end(&mut buf)?;
    Ok(buf)
}

// Bom: Bounds de trait para múltiplas restrições
fn process<T: Display + Send + 'static>(item: T) -> String {
    format!("processado: {item}")
}

Trait Objects para Dispatch Dinâmico

// Use quando precisar de coleções heterogêneas ou sistemas de plugin
trait Handler: Send + Sync {
    fn handle(&self, request: &Request) -> Response;
}

struct Router {
    handlers: Vec<Box<dyn Handler>>,
}

// Use genéricos quando precisar de desempenho (monomorfização)
fn fast_process<H: Handler>(handler: &H, request: &Request) -> Response {
    handler.handle(request)
}

Padrão Newtype para Segurança de Tipos

// Bom: Tipos distintos previnem troca de argumentos
struct UserId(u64);
struct OrderId(u64);

fn get_order(user: UserId, order: OrderId) -> Result<Order> {
    // Não é possível trocar acidentalmente IDs de usuário e pedido
    todo!()
}

// Ruim: Fácil de trocar argumentos
fn get_order_bad(user_id: u64, order_id: u64) -> Result<Order> {
    todo!()
}

Structs e Modelagem de Dados

Padrão Builder para Construção Complexa

struct ServerConfig {
    host: String,
    port: u16,
    max_connections: usize,
}

impl ServerConfig {
    fn builder(host: impl Into<String>, port: u16) -> ServerConfigBuilder {
        ServerConfigBuilder { host: host.into(), port, max_connections: 100 }
    }
}

struct ServerConfigBuilder { host: String, port: u16, max_connections: usize }

impl ServerConfigBuilder {
    fn max_connections(mut self, n: usize) -> Self { self.max_connections = n; self }
    fn build(self) -> ServerConfig {
        ServerConfig { host: self.host, port: self.port, max_connections: self.max_connections }
    }
}

// Uso: ServerConfig::builder("localhost", 8080).max_connections(200).build()

Iteradores e Closures

Prefira Cadeias de Iteradores a Loops Manuais

// Bom: Declarativo, lazy, composável
let active_emails: Vec<String> = users.iter()
    .filter(|u| u.is_active)
    .map(|u| u.email.clone())
    .collect();

// Ruim: Acumulação imperativa
let mut active_emails = Vec::new();
for user in &users {
    if user.is_active {
        active_emails.push(user.email.clone());
    }
}

Use collect() com Anotação de Tipo

// Colete em diferentes tipos
let names: Vec<_> = items.iter().map(|i| &i.name).collect();
let lookup: HashMap<_, _> = items.iter().map(|i| (i.id, i)).collect();
let combined: String = parts.iter().copied().collect();

// Colete Results — interrompe no primeiro erro
let parsed: Result<Vec<i32>, _> = strings.iter().map(|s| s.parse()).collect();

Concorrência

Arc<Mutex<T>> para Estado Mutável Compartilhado

use std::sync::{Arc, Mutex};

let counter = Arc::new(Mutex::new(0));
let handles: Vec<_> = (0..10).map(|_| {
    let counter = Arc::clone(&counter);
    std::thread::spawn(move || {
        let mut num = counter.lock().expect("mutex envenenado");
        *num += 1;
    })
}).collect();

for handle in handles {
    handle.join().expect("thread trabalhadora entrou em panic");
}

Canais para Passagem de Mensagens

use std::sync::mpsc;

let (tx, rx) = mpsc::sync_channel(16); // Canal limitado com backpressure

for i in 0..5 {
    let tx = tx.clone();
    std::thread::spawn(move || {
        tx.send(format!("mensagem {i}")).expect("receptor desconectado");
    });
}
drop(tx); // Feche o transmissor para que o iterador rx termine

for msg in rx {
    println!("{msg}");
}

Async com Tokio

use tokio::time::Duration;

async fn fetch_with_timeout(url: &str) -> Result<String> {
    let response = tokio::time::timeout(
        Duration::from_secs(5),
        reqwest::get(url),
    )
    .await
    .context("requisição expirou")?
    .context("requisição falhou")?;

    response.text().await.context("falha ao ler corpo")
}

// Lance tarefas concorrentes
async fn fetch_all(urls: Vec<String>) -> Vec<Result<String>> {
    let handles: Vec<_> = urls.into_iter()
        .map(|url| tokio::spawn(async move {
            fetch_with_timeout(&url).await
        }))
        .collect();

    let mut results = Vec::with_capacity(handles.len());
    for handle in handles {
        results.push(handle.await.unwrap_or_else(|e| panic!("tarefa lançada entrou em panic: {e}")));
    }
    results
}

Código Inseguro (Unsafe)

Quando Unsafe é Aceitável

// Aceitável: Fronteira FFI com invariantes documentados (Rust 2024+)
/// # Safety
/// `ptr` deve ser um ponteiro válido e alinhado para um `Widget` inicializado.
unsafe fn widget_from_raw<'a>(ptr: *const Widget) -> &'a Widget {
    // SAFETY: o chamador garante que ptr é válido e alinhado
    unsafe { &*ptr }
}

// Aceitável: Caminho crítico de desempenho com prova de correção
// SAFETY: index é sempre < len devido ao limite do loop
unsafe { slice.get_unchecked(index) }

Quando Unsafe NÃO é Aceitável

// Ruim: Usar unsafe para contornar o borrow checker
// Ruim: Usar unsafe por conveniência
// Ruim: Usar unsafe sem um comentário de Safety
// Ruim: Transmutar entre tipos não relacionados

Sistema de Módulos e Estrutura de Crate

Organize por Domínio, Não por Tipo

my_app/
├── src/
│   ├── main.rs
│   ├── lib.rs
│   ├── auth/          # Módulo de domínio
│   │   ├── mod.rs
│   │   ├── token.rs
│   │   └── middleware.rs
│   ├── orders/        # Módulo de domínio
│   │   ├── mod.rs
│   │   ├── model.rs
│   │   └── service.rs
│   └── db/            # Infraestrutura
│       ├── mod.rs
│       └── pool.rs
├── tests/             # Testes de integração
├── benches/           # Benchmarks
└── Cargo.toml

Visibilidade — Exponha Minimamente

// Bom: pub(crate) para compartilhamento interno
pub(crate) fn validate_input(input: &str) -> bool {
    !input.is_empty()
}

// Bom: Re-exporte API pública de lib.rs
pub mod auth;
pub use auth::AuthMiddleware;

// Ruim: Tornar tudo pub
pub fn internal_helper() {} // Deveria ser pub(crate) ou privado

Integração com Ferramentas

Comandos Essenciais

# Compilar e verificar
cargo build
cargo check              # Verificação de tipo rápida sem geração de código
cargo clippy             # Lints e sugestões
cargo fmt                # Formatador de código

# Testar
cargo test
cargo test -- --nocapture    # Mostrar saída de println
cargo test --lib             # Apenas testes unitários
cargo test --test integration # Apenas testes de integração

# Dependências
cargo audit              # Auditoria de segurança
cargo tree               # Árvore de dependências
cargo update             # Atualizar dependências

# Desempenho
cargo bench              # Executar benchmarks

Referência Rápida: Expressões Idiomáticas Rust

ExpressãoDescrição
Empreste, não clonePasse &T em vez de clonar, a menos que ownership seja necessária
Torne estados ilegais não representáveisUse enums para modelar apenas estados válidos
? em vez de unwrap()Propague erros, nunca entre em panic em código de biblioteca/produção
Parse, não valideConverta dados não estruturados em structs tipados na fronteira
Newtype para segurança de tiposEncapsule primitivos em newtypes para prevenir troca de argumentos
Prefira iteradores a loopsCadeias declarativas são mais claras e frequentemente mais rápidas
#[must_use] em ResultsGaranta que chamadores tratem valores de retorno
Cow para ownership flexívelEvite alocações quando emprestar é suficiente
Matching exaustivoSem wildcard _ para enums críticos de negócio
Superfície pub mínimaUse pub(crate) para APIs internas

Anti-Padrões a Evitar

// Ruim: .unwrap() em código de produção
let value = map.get("key").unwrap();

// Ruim: .clone() para satisfazer o borrow checker sem entender o porquê
let data = expensive_data.clone();
process(&original, &data);

// Ruim: Usar String quando &str é suficiente
fn greet(name: String) { /* deveria ser &str */ }

// Ruim: Box<dyn Error> em bibliotecas (use thiserror)
fn parse(input: &str) -> Result<Data, Box<dyn std::error::Error>> { todo!() }

// Ruim: Ignorar avisos de must_use
let _ = validate(input); // Descartando silenciosamente um Result

// Ruim: Bloquear em contexto async
async fn bad_async() {
    std::thread::sleep(Duration::from_secs(1)); // Bloqueia o executor!
    // Use: tokio::time::sleep(Duration::from_secs(1)).await;
}

Lembre-se: Se compila, provavelmente está correto — mas apenas se você evitar unwrap(), minimizar unsafe e deixar o sistema de tipos trabalhar para você.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Habilidades Relacionadas