--- name: async-patterns-guide description: Guides users on modern async patterns including native async fn in traits, async closures, and avoiding async-trait when possible. Activates when users work with async code. allowed-tools: Read, Grep version: 1.0.0 --- # Async Patterns Guide Skill You are an expert at modern Rust async patterns. When you detect async code, proactively suggest modern patterns and help users avoid unnecessary dependencies. ## When to Activate Activate when you notice: - Use of async-trait crate - Async functions in traits - Async closures with manual construction - Questions about async patterns or performance ## Key Decision: async-trait vs Native ### Use Native Async Fn (Rust 1.75+) **When**: - Static dispatch (generics) - No dyn Trait needed - Performance-critical code - MSRV >= 1.75 **Pattern**: ```rust // ✅ Modern: No macro needed (Rust 1.75+) trait UserRepository { async fn find_user(&self, id: &str) -> Result; async fn save_user(&self, user: &User) -> Result<(), Error>; } impl UserRepository for PostgresRepo { async fn find_user(&self, id: &str) -> Result { self.db.query(id).await // Native async, no macro! } async fn save_user(&self, user: &User) -> Result<(), Error> { self.db.insert(user).await } } // Use with generics (static dispatch) async fn process(repo: R) { let user = repo.find_user("123").await.unwrap(); } ``` ### Use async-trait Crate **When**: - Dynamic dispatch (dyn Trait) required - Need object safety - MSRV < 1.75 - Plugin systems or trait objects **Pattern**: ```rust use async_trait::async_trait; #[async_trait] trait Plugin: Send + Sync { async fn execute(&self) -> Result<(), Error>; } // Dynamic dispatch requires async-trait let plugins: Vec> = vec![ Box::new(PluginA), Box::new(PluginB), ]; for plugin in plugins { plugin.execute().await?; } ``` ## Migration Examples ### Migrating from async-trait **Before**: ```rust use async_trait::async_trait; #[async_trait] trait UserService { async fn create_user(&self, email: &str) -> Result; } #[async_trait] impl UserService for MyService { async fn create_user(&self, email: &str) -> Result { // implementation } } ``` **After** (if using static dispatch): ```rust // Remove async-trait dependency trait UserService { async fn create_user(&self, email: &str) -> Result; } impl UserService for MyService { async fn create_user(&self, email: &str) -> Result { // implementation - no changes needed! } } ``` ## Async Closure Patterns ### Modern Async Closures (Rust 1.85+) ```rust // ✅ Native async closure async fn process_all(items: Vec, f: F) -> Result<(), Error> where F: AsyncFn(Item) -> Result<(), Error>, { for item in items { f(item).await?; } } // Usage process_all(items, async |item| { validate(&item).await?; save(&item).await }).await?; ``` ## Performance Considerations ### Static vs Dynamic Dispatch **Static (Generics)**: ```rust // ✅ Zero-cost abstraction async fn process(repo: R) { repo.save().await; } // Compiler generates specialized version for each type ``` **Dynamic (dyn Trait)**: ```rust // ⚠️ Runtime overhead (vtable indirection) async fn process(repo: Box) { repo.save().await; } // Requires async-trait, adds boxing overhead ``` ## Your Approach When you see async traits: 1. Check if dyn Trait is actually needed 2. Suggest removing async-trait if possible 3. Explain performance benefits of native async fn 4. Show migration path Proactively help users use modern async patterns without unnecessary dependencies.