en un clic
async-trait
Expert knowledge for the Rust async-trait crate — the
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Menu
Expert knowledge for the Rust async-trait crate — the
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Basé sur la classification professionnelle SOC
Use when working in the claudine/ package area or with the Claudine library/CLI — normalizing agentic-CLI lifecycle events and hooks, wrapping providers (Claude Code, Codex, Gemini, Goose, Kimi, OpenCode, Qwen, Kilo, Pi, Antigravity), composing Markdown prompts (compose/inline-compose/sequence), managing the MCP catalog, linking skills/commands/agents across providers, or researching agentic CLI platform behavior.
Expert knowledge for building and managing monorepos across JavaScript, TypeScript, Rust, Go, and JVM — workspace standards (npm, pnpm, Yarn, Cargo, Go workspaces, Gradle, Maven), task-orchestration tools (Nx, Turborepo, Bazel, Pants, Rush, Lerna, moon), and versioning (Changesets). Use when structuring a monorepo, choosing task-orchestration tooling, or setting up workspace versioning and release flows.
Use when deploying a Rust project to package managers (cargo, brew, apt, nixos, uv, npm), speeding up Rust builds with compilation caching (kache, RUSTC_WRAPPER, local/remote S3 caches, CI build cache), or interacting with Git from Rust (git2/libgit2 bindings, gitoxide/gix pure-Rust). Covers release distribution, build-time tooling, and programmatic Git access for Rust projects.
Expert knowledge for Rust systems programming — ownership, borrowing, type safety, error handling, async patterns, performance optimization, and 2024-edition improvements. Use when writing or reviewing idiomatic Rust, resolving borrow-checker or lifetime issues, structuring error handling, or optimizing performance.
Monorepo testing guide: L1/L2/L3 taxonomy, canonical just recipes, `require_level!` gating, nextest filtersets, and fuzzing. Load this before writing or reviewing tests in the rusty-biscuit workspace.
Expert guidance for the cross-platform `sniff` Rust library and CLI. Use when discovering host hardware, OS, network, programs, services, filesystems, Git repositories, worktrees, monorepo packages, remote providers, or when changing Sniff request tiers, observation reuse, work counters, CLI output, and macOS/Linux/Windows behavior.
| name | async-trait |
| description | Expert knowledge for the Rust async-trait crate — the |
| hash | async-trait-skill-v1 |
A procedural macro by David Tolnay that enables async functions in traits to work with dynamic dispatch (dyn Trait). Essential when you need trait objects with async methods.
Version: 0.1.89 (latest as of 2025) Use for: Dynamic dispatch with async traits, plugin systems, dependency injection with async interfaces.
| Scenario | Solution |
|---|---|
| Static dispatch only (generics) | Native async fn in traits (Rust 1.75+) |
Need dyn Trait / trait objects | #[async_trait] required |
| Pre-Rust 1.75 compatibility | #[async_trait] required |
| Performance-critical tight loops | Consider avoiding trait objects entirely |
Key insight: Native async traits (Rust 1.75+) do NOT support dyn Trait. If you need trait objects with async methods, async-trait is still required.
Apply #[async_trait] to both trait definition AND all implementations:
use async_trait::async_trait;
#[async_trait]
pub trait ModelScanner: Send + Sync {
async fn scan(&self) -> Result<Vec<Model>, ScanError>;
async fn is_available(&self) -> bool;
fn name(&self) -> &'static str; // Non-async methods work normally
}
#[async_trait]
impl ModelScanner for OllamaScanner {
async fn scan(&self) -> Result<Vec<Model>, ScanError> {
// Implementation
}
async fn is_available(&self) -> bool {
self.client.health_check().await.is_ok()
}
fn name(&self) -> &'static str {
"ollama"
}
}
The macro transforms async methods into boxed futures:
// Your code:
async fn scan(&self) -> Vec<Model>;
// Expands to:
fn scan<'async_trait>(&'async_trait self)
-> Pin<Box<dyn Future<Output = Vec<Model>> + Send + 'async_trait>>
where
Self: Sync + 'async_trait
{
Box::pin(async move { /* your implementation */ })
}
Default behavior: Futures are Send (can move between threads).
// Default: Send bound on future
#[async_trait]
trait MyTrait {
async fn method(&self); // Future: Pin<Box<dyn Future + Send>>
}
For single-threaded contexts (e.g., !Send types, Rc, RefCell):
// Remove Send bound - use on BOTH trait and impl
#[async_trait(?Send)]
trait LocalTrait {
async fn method(&self); // Future: Pin<Box<dyn Future>> (no Send)
}
#[async_trait(?Send)]
impl LocalTrait for MyType {
async fn method(&self) { /* ... */ }
}
use async_trait::async_trait;
#[async_trait]
pub trait Scanner: Send + Sync {
async fn scan(&self) -> Vec<Item>;
}
// Registry holding boxed trait objects
pub struct Registry {
scanners: Vec<Box<dyn Scanner>>,
}
impl Registry {
pub fn add(&mut self, scanner: impl Scanner + 'static) {
self.scanners.push(Box::new(scanner));
}
pub async fn scan_all(&self) -> Vec<Item> {
let futures: Vec<_> = self.scanners.iter().map(|s| s.scan()).collect();
futures::future::join_all(futures).await.into_iter().flatten().collect()
}
}
Overhead per call: ~20 nanoseconds (heap allocation for boxed future)
When it matters:
When it doesn't matter (most cases):
Benchmark perspective: 100K calls = ~2ms overhead. Usually negligible compared to actual I/O.
#[async_trait]
trait MyTrait { async fn method(&self); }
// WRONG: Missing #[async_trait]
impl MyTrait for MyType {
async fn method(&self) { } // Compile error!
}
// CORRECT:
#[async_trait]
impl MyTrait for MyType {
async fn method(&self) { }
}
#[async_trait] // Send bound
trait MyTrait { ... }
#[async_trait(?Send)] // No Send bound - MISMATCH!
impl MyTrait for MyType { ... } // Compile error
// Won't work as dyn Trait:
#[async_trait]
trait BadTrait {
async fn method(&self);
}
// Works as dyn Trait:
#[async_trait]
trait GoodTrait: Send + Sync {
async fn method(&self);
}
let scanner: Box<dyn GoodTrait> = Box::new(MyImpl); // Works!
Async-trait supports lifetime elision in & and &mut references only:
#[async_trait]
trait Valid {
async fn process(&self, data: &str); // OK: elision works
}
#[async_trait]
trait NeedsExplicit {
// Must use explicit lifetime or '_ for non-reference types
async fn process(&self, data: Cow<'_, str>);
}
For native async traits that need Send bounds without full boxing:
use trait_variant::make;
#[trait_variant::make(SendScanner: Send)]
trait LocalScanner {
async fn scan(&self) -> Vec<Model>;
}
// Generates two traits:
// - LocalScanner: no Send bound
// - SendScanner: with Send bound on futures
Limitation: Still no dyn Trait support - use async-trait for that.