Communitygithub.com

rust-patterns

Idiomatische Rust-Patterns, Ownership, Fehlerbehandlung, Traits, Nebenläufigkeit und bewährte Methoden für sichere, performante Anwendungen. Verwenden beim Schreiben oder Überprüfen von Rust-Code, wenn Ownership, Fehlerbehandlung, Traits oder Nebenläufigkeit eine Rolle spielen.

Was ist rust-patterns?

Diese Skill definiert idiomatische Rust-Entwicklungsmuster und Best Practices für die Erstellung sicherer, performanter und wartbarer Anwendungen. Sie deckt sechs Kernbereiche ab: Ownership und Borrowing zur Vermeidung von Datenrennen zur Compile-Zeit, Fehlerbehandlung mit `Result`/`?` sowie `thiserror` für Bibliotheken und `anyhow` für Anwendungen, Enums und erschöpfendes Pattern Matching, um ungültige Zustände unmöglich zu machen, Traits und Generics für Nullkosten-Abstraktion, sichere Nebenläufigkeit mit `Arc<Mutex <T>>`, Channels und Async/Await, sowie minimale öffentliche Oberflächen, organisiert nach Domänen. Die Skill ist plattformunabhängig und kann in jeder Rust-Umgebung eingesetzt werden. Sie bietet konkrete Codebeispiele, die falsche und korrekte Ansätze gegenüberstellen, sowie eine Kurzreferenz zu zentralen Idiomen und Anti-Patterns.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Rust-Entwicklungsmuster

Idiomatische Rust-Patterns und bewährte Verfahren für sichere, performante und wartbare Anwendungen.

Wann verwenden

  • Schreiben von neuem Rust-Code
  • Überprüfen von Rust-Code
  • Refactoring vorhandenen Rust-Codes
  • Entwerfen von Crate-Strukturen und Modul-Layouts

Funktionsweise

Diese Skill setzt idiomatische Rust-Konventionen in sechs Schlüsselbereichen durch: Ownership und Borrowing zur Vermeidung von Datenrennen zur Compile-Zeit, Fehlerweitergabe mit Result/? sowie thiserror für Bibliotheken und anyhow für Anwendungen, Enums und erschöpfendes Pattern Matching, um illegale Zustände nicht darstellbar zu machen, Traits und Generics für Nullkosten-Abstraktion, sichere Nebenläufigkeit via Arc<Mutex<T>>, Channels und async/await, sowie minimale pub-Oberflächen, die nach Domänen organisiert sind.

Kernprinzipien

1. Ownership und Borrowing

Rusts Ownership-System verhindert Datenrennen und Speicherfehler zur Compile-Zeit.

// Gut: Referenzen übergeben, wenn kein Ownership benötigt wird
fn process(data: &[u8]) -> usize {
    data.len()
}

// Gut: Ownership nur übernehmen, wenn gespeichert oder konsumiert werden muss
fn store(data: Vec<u8>) -> Record {
    Record { payload: data }
}

// Schlecht: Unnötiges Klonen, um den Borrow-Checker zu umgehen
fn process_bad(data: &Vec<u8>) -> usize {
    let cloned = data.clone(); // Verschwenderisch — einfach borrowen
    cloned.len()
}

Cow für flexibles Ownership

use std::borrow::Cow;

fn normalize(input: &str) -> Cow<'_, str> {
    if input.contains(' ') {
        Cow::Owned(input.replace(' ', "_"))
    } else {
        Cow::Borrowed(input) // Nullkosten, wenn keine Mutation nötig
    }
}

Fehlerbehandlung

Result und ? verwenden — niemals unwrap() in der Produktion

// Gut: Fehler mit Kontext weitergeben
use anyhow::{Context, Result};

fn load_config(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("Fehler beim Lesen der Konfiguration von {path}"))?;
    let config: Config = toml::from_str(&content)
        .with_context(|| format!("Fehler beim Parsen der Konfiguration von {path}"))?;
    Ok(config)
}

// Schlecht: Panic bei Fehlern
fn load_config_bad(path: &str) -> Config {
    let content = std::fs::read_to_string(path).unwrap(); // Panic!
    toml::from_str(&content).unwrap()
}

Bibliotheksfehler mit thiserror, Anwendungsfehler mit anyhow

// Bibliothekscode: strukturierte, typisierte Fehler
use thiserror::Error;

#[derive(Debug, Error)]
pub enum StorageError {
    #[error("Datensatz nicht gefunden: {id}")]
    NotFound { id: String },
    #[error("Verbindung fehlgeschlagen")]
    Connection(#[from] std::io::Error),
    #[error("Ungültige Daten: {0}")]
    InvalidData(String),
}

// Anwendungscode: flexible Fehlerbehandlung
use anyhow::{bail, Result};

fn run() -> Result<()> {
    let config = load_config("app.toml")?;
    if config.workers == 0 {
        bail!("Worker-Anzahl muss > 0 sein");
    }
    Ok(())
}

Option-Kombinatoren statt verschachteltem Matching

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

// Schlecht: Tief verschachteltes Matching
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 und Pattern Matching

Zustände als Enums modellieren

// Gut: Unmögliche Zustände sind nicht darstellbar
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),
    }
}

Erschöpfendes Matching — kein Catch-All für Geschäftslogik

// Gut: Jede Variante explizit behandeln
match command {
    Command::Start => start_service(),
    Command::Stop => stop_service(),
    Command::Restart => restart_service(),
    // Hinzufügen einer neuen Variante erzwingt Behandlung hier
}

// Schlecht: Wildcard übersieht neue Varianten
match command {
    Command::Start => start_service(),
    _ => {} // Übersieht stillschweigend Stop, Restart und zukünftige Varianten
}

Traits und Generics

Generics akzeptieren, konkrete Typen zurückgeben

// Gut: Generischer Input, konkreter Output
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)
}

// Gut: Trait-Bounds für mehrere Einschränkungen
fn process<T: Display + Send + 'static>(item: T) -> String {
    format!("verarbeitet: {item}")
}

Trait-Objekte für dynamischen Dispatch

// Verwenden, wenn heterogene Sammlungen oder Pluginsysteme benötigt werden
trait Handler: Send + Sync {
    fn handle(&self, request: &Request) -> Response;
}

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

// Generics verwenden, wenn Performance benötigt wird (Monomorphisierung)
fn fast_process<H: Handler>(handler: &H, request: &Request) -> Response {
    handler.handle(request)
}

Newtype-Pattern für Typsicherheit

// Gut: Unterschiedliche Typen verhindern Verwechslung von Argumenten
struct UserId(u64);
struct OrderId(u64);

fn get_order(user: UserId, order: OrderId) -> Result<Order> {
    // Kann nicht versehentlich User- und Order-ID vertauschen
    todo!()
}

// Schlecht: Leicht, Argumente zu vertauschen
fn get_order_bad(user_id: u64, order_id: u64) -> Result<Order> {
    todo!()
}

Structs und Datenmodellierung

Builder-Pattern für komplexe Konstruktion

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 }
    }
}

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

Iteratoren und Closures

Iterator-Ketten manuellen Schleifen vorziehen

// Gut: Deklarativ, faul, komponierbar
let active_emails: Vec<String> = users.iter()
    .filter(|u| u.is_active)
    .map(|u| u.email.clone())
    .collect();

// Schlecht: Imperative Akkumulation
let mut active_emails = Vec::new();
for user in &users {
    if user.is_active {
        active_emails.push(user.email.clone());
    }
}

collect() mit Typannotation verwenden

// In verschiedene Typen sammeln
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();

// Results sammeln – bricht beim ersten Fehler ab
let parsed: Result<Vec<i32>, _> = strings.iter().map(|s| s.parse()).collect();

Nebenläufigkeit

Arc<Mutex<T>> für gemeinsam genutzten, veränderbaren Zustand

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 vergiftet");
        *num += 1;
    })
}).collect();

for handle in handles {
    handle.join().expect("Worker-Thread panicked");
}

Channels für Nachrichtenaustausch

use std::sync::mpsc;

let (tx, rx) = mpsc::sync_channel(16); // Bounded Channel mit Backpressure

for i in 0..5 {
    let tx = tx.clone();
    std::thread::spawn(move || {
        tx.send(format!("Nachricht {i}")).expect("Empfänger getrennt");
    });
}
drop(tx); // Sender schließen, damit rx-Iterator terminiert

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

Async mit 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("Anfrage zeitüberschreitung")?
    .context("Anfrage fehlgeschlagen")?;

    response.text().await.context("Fehler beim Lesen des Bodys")
}

// Gleichzeitige Aufgaben starten
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!("Gestartete Aufgabe panicked: {e}")));
    }
    results
}

Unsicherer Code

Wann Unsafe akzeptabel ist

// Akzeptabel: FFI-Grenze mit dokumentierten Invarianten (Rust 2024+)
/// # Sicherheit
/// `ptr` muss ein gültiger, ausgerichteter Zeiger auf eine initialisierte `Widget`-Instanz sein.
unsafe fn widget_from_raw<'a>(ptr: *const Widget) -> &'a Widget {
    // SICHERHEIT: Aufrufer garantiert, dass ptr gültig und ausgerichtet ist
    unsafe { &*ptr }
}

// Akzeptabel: Performance-kritischer Pfad mit Korrektheitsnachweis
// SICHERHEIT: index ist aufgrund der Schleifenbegrenzung immer < len
unsafe { slice.get_unchecked(index) }

Wann Unsafe NICHT akzeptabel ist

// Schlecht: Unsafe verwenden, um den Borrow-Checker zu umgehen
// Schlecht: Unsafe aus Bequemlichkeit verwenden
// Schlecht: Unsafe ohne Sicherheitskommentar verwenden
// Schlecht: Zwischen nicht verwandten Typen transmuten

Modulsystem und Crate-Struktur

Nach Domäne organisieren, nicht nach Typ

my_app/
├── src/
│   ├── main.rs
│   ├── lib.rs
│   ├── auth/          # Domänenmodul
│   │   ├── mod.rs
│   │   ├── token.rs
│   │   └── middleware.rs
│   ├── orders/        # Domänenmodul
│   │   ├── mod.rs
│   │   ├── model.rs
│   │   └── service.rs
│   └── db/            # Infrastruktur
│       ├── mod.rs
│       └── pool.rs
├── tests/             # Integrationstests
├── benches/           # Benchmarks
└── Cargo.toml

Sichtbarkeit — Minimal exponieren

// Gut: pub(crate) für internes Teilen
pub(crate) fn validate_input(input: &str) -> bool {
    !input.is_empty()
}

// Gut: Öffentliche API aus lib.rs re-exportieren
pub mod auth;
pub use auth::AuthMiddleware;

// Schlecht: Alles pub machen
pub fn internal_helper() {} // Sollte pub(crate) oder privat sein

Tooling-Integration

Wichtige Befehle

# Bauen und Prüfen
cargo build
cargo check              # Schnelle Typprüfung ohne Codegenerierung
cargo clippy             # Lints und Vorschläge
cargo fmt                # Code formatieren

# Testen
cargo test
cargo test -- --nocapture    # println-Ausgabe anzeigen
cargo test --lib             # Nur Unit-Tests
cargo test --test integration # Nur Integrationstests

# Abhängigkeiten
cargo audit              # Sicherheitsaudit
cargo tree               # Abhängigkeitsbaum
cargo update             # Abhängigkeiten aktualisieren

# Performance
cargo bench              # Benchmarks ausführen

Kurzreferenz: Rust-Idiome

IdiomBeschreibung
Borrowen, nicht klonen&T übergeben statt zu klonen, es sei denn, Ownership wird benötigt
Illegale Zustände nicht darstellbar machenEnums verwenden, um nur gültige Zustände zu modellieren
? statt unwrap()Fehler weitergeben, niemals in Bibliotheks-/Produktionscode panicen
Parsen, nicht validierenUnstrukturierte Daten an der Grenze in typisierte Structs umwandeln
Newtype für TypsicherheitPrimitive in Newtypes verpacken, um Argumentvertauschungen zu verhindern
Iteratoren Schleifen vorziehenDeklarative Ketten sind klarer und oft schneller
#[must_use] auf ResultsSicherstellen, dass Aufrufer Rückgabewerte behandeln
Cow für flexibles OwnershipAllokationen vermeiden, wenn Borrowing ausreicht
Erschöpfendes MatchingKein Wildcard _ für geschäftskritische Enums
Minimale pub-Oberflächepub(crate) für interne APIs verwenden

Anti-Patterns, die vermieden werden sollten

// Schlecht: .unwrap() im Produktionscode
let value = map.get("key").unwrap();

// Schlecht: .clone(), um den Borrow-Checker zu besänftigen, ohne zu verstehen, warum
let data = expensive_data.clone();
process(&original, &data);

// Schlecht: String verwenden, wenn &str ausreicht
fn greet(name: String) { /* sollte &str sein */ }

// Schlecht: Box<dyn Error> in Bibliotheken (stattdessen thiserror verwenden)
fn parse(input: &str) -> Result<Data, Box<dyn std::error::Error>> { todo!() }

// Schlecht: must_use-Warnungen ignorieren
let _ = validate(input); // Ergebnis eines Result stillschweigend verwerfen

// Schlecht: Blockieren im Async-Kontext
async fn bad_async() {
    std::thread::sleep(Duration::from_secs(1)); // Blockiert den Executor!
    // Verwenden: tokio::time::sleep(Duration::from_secs(1)).await;
}

Denk daran: Wenn es compiliert, ist es wahrscheinlich korrekt — aber nur, wenn du unwrap() vermeidest, unsafe minimierst und das Typsystem für dich arbeiten lässt.

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.

Verwandte Skills