rust-programming-expert ยท diff
git:20260612.8b09a53 to git:20260614.78a2809
76 added, 373 removed. Audit A to A.
---
name: rust-programming-expert
- description: "Expert-level skill for Rust programming (Rust 2024 / v1.85+). Covers memory safety (ownership/lifetimes), async programming (Tokio, async closures), API backends (Axum, SQLx), CLI development (Clap, Serde), unsafe safety, optimization, and Cargo profiling."
+ description: "Expert-level skill for Rust programming (Rust 2024 / v1.85+). Covers memory safety, async, Axum/SQLx, CLI, and optimization in Indonesian and English."
author: "Roedy Rustam"
---
# Rust Programming Expert
- ## Deskripsi
- Expert-level guidance for writing high-performance, robust, and memory-safe systems applications using **Rust 2024 (v1.85+)**. This skill outlines advanced practices in ownership, lifetimes, error design, async architectures, backend development, performance tuning, and idiomatic ecosystem patterns.
-
- ---
-
- ## Kondisi Pemicu
-
- - Use when bootstrapping or maintaining a production Rust crate, application, or workspace.
- - Use when designing data models involving complex lifetimes, smart pointers (`Arc`, `Rc`, `RefCell`), or zero-copy abstractions (`Cow`).
- - Use when building high-concurrency async services with **Tokio** and **Axum**.
- - Use when interacting with databases safely using compile-time checked SQL with **SQLx**.
- - Use when crafting modern CLI utilities using **Clap** and **Serde**.
- - Use when migrating or upgrading an existing Rust codebase to the **Rust 2024 Edition**.
- - Use when profiling, optimizing, or debugging compile times, memory footprints, or runtime performance.
-
- ---
-
- ## Core Architecture & Rust 2024 Edition
-
- Rust 2024 (stabilized in Rust v1.85) enhances language ergonomics, strengthens safety invariants, and introduces native async enhancements:
-
- | Feature Area | Rust 2024 Upgrade | Best Practice / Modern Pattern |
- |---|---|---|
- | **Async Closures** | Stable `async || {}` & `AsyncFn` traits | Use for async stream adapters or direct closure-based async event handlers. |
- | **RPIT Lifetimes** | RPIT (`impl Trait` in return position) captures all in-scope lifetimes by default | Use explicit `use<'a, T>` syntax if you want to restrict lifetime capturing. |
- | **Unsafe Extern** | `extern` blocks and specific attributes (`no_mangle`) now require the `unsafe` keyword | Explicitly document safety invariants of external dynamic library interfaces. |
- | **Prelude Additions** | `Future` and `IntoFuture` are now imported automatically | Stop importing `std::future::Future` manually. |
- | **Temporary Scopes** | Improved scopes for temporaries in `if let` blocks | Avoid manual block bindings to extend temporary value lifetimes. |
+ [Bahasa Indonesia](#bahasa-indonesia) | [English](#english)
---
- ## Language Essentials & Memory Safety
-
- Memory safety in Rust is guaranteed at compile time through the ownership system. Implement these structural guidelines:
+ <a name="bahasa-indonesia"></a>
+ ## Bahasa Indonesia
- ### 1. The Ownership & Borrowing Mental Model
- - **Ownership**: Each value has a single owner. When the owner goes out of scope, the value is dropped.
- - **Borrowing**:
- - You can have any number of immutable references (`&T`) *OR*
- - Exactly one active mutable reference (`&mut T`) to a value at any given time.
- - **Lifetimes**: Ensure that references do not outlive the data they point to.
+ ### Deskripsi
+ Panduan tingkat ahli untuk menulis aplikasi sistem yang berkinerja tinggi, tangguh, dan aman secara memori menggunakan **Rust 2024 (v1.85+)**. Skill ini menguraikan praktik-praktik lanjutan dalam kepemilikan (ownership), masa hidup (lifetimes), desain error, arsitektur asinkron, pengembangan backend, optimasi performa, dan pola ekosistem yang idiomatis.
- ### 2. Lifetimes & Smart Pointers
- - Avoid placing references (`&T`) in struct definitions unless the struct is a short-lived view or helper. Prefer owned types (`String`, `Vec<T>`) or smart pointers (`Arc<T>`) for shared ownership.
- - Use `Arc<T>` (Thread-Safe Shared Reference) and `Mutex<T>` (Mutual Exclusion) or `RwLock<T>` (Read-Write Lock) for multi-threaded state sharing.
- - Use `Rc<T>` and `RefCell<T>` only for single-threaded graph nodes or interior mutability where thread safety is not required.
+ ### Kondisi Pemicu
+ - Gunakan saat merancang atau memelihara crate, aplikasi, atau workspace Rust tingkat produksi.
+ - Gunakan saat mendesain model data dengan lifetime yang kompleks, smart pointers (`Arc`, `Rc`, `RefCell`), atau abstraksi zero-copy (`Cow`).
+ - Gunakan saat membangun layanan asinkron konkurensi tinggi dengan **Tokio** dan **Axum**.
+ - Gunakan saat berinteraksi dengan database secara aman menggunakan SQL yang diverifikasi saat kompilasi dengan **SQLx**.
+ - Gunakan saat merancang utilitas CLI modern menggunakan **Clap** dan **Serde**.
+ - Gunakan saat memigrasikan atau meningkatkan codebase Rust yang ada ke **Edisi Rust 2024**.
+ - Gunakan saat melakukan profiling, mengoptimalkan, atau men-debug waktu kompilasi, penggunaan memori, atau kinerja runtime.
- #### Example: Idiomatic Safe State Management
- ```rust
- use std::sync::{Arc, RwLock};
+ ### Edisi Rust 2024 & Arsitektur Inti
+ Edisi Rust 2024 meningkatkan ergonomi bahasa, memperkuat invariant keamanan, dan memperkenalkan peningkatan asinkron bawaan:
+ - **Async Closures**: Traits `AsyncFn` dan penulisan closure `async || {}` sekarang stabil. Gunakan untuk adapter stream asinkron atau event handler langsung.
+ - **RPIT Lifetimes**: RPIT (`impl Trait` pada posisi return) menangkap semua lifetime dalam scope secara default. Gunakan sintaksis eksplisit `use<'a, T>` untuk membatasi penangkapan lifetime.
+ - **Unsafe Extern**: Blok `extern` dan atribut tertentu (`no_mangle`) sekarang memerlukan kata kunci `unsafe`.
+ - **Tambahan Prelude**: `Future` dan `IntoFuture` sekarang diimpor secara otomatis.
- #[derive(Debug, Clone)]
- pub struct AppState {
- inner: Arc<RwLock<SharedData>>,
- }
+ ### Dasar Bahasa & Keamanan Memori
+ Keamanan memori dijamin saat kompilasi melalui sistem kepemilikan (ownership). Ikuti panduan berikut:
+ 1. **Kepemilikan & Peminjaman**: Setiap nilai memiliki satu pemilik. Ketika pemilik keluar dari scope, nilai tersebut dihapus. Anda dapat memiliki banyak referensi immutable (`&T`) *ATAU* tepat satu referensi mutable (`&mut T`) aktif pada satu waktu.
+ 2. **Lifetimes & Smart Pointers**: Hindari meletakkan referensi (`&T`) di dalam definisi struct kecuali untuk struct pembantu berumur pendek. Gunakan `Arc<T>` (Thread-Safe Shared Reference) dan `Mutex<T>` (Mutual Exclusion) untuk berbagi state antar thread.
- #[derive(Debug)]
- struct SharedData {
- pub connections_count: u32,
- pub active_users: Vec<String>,
- }
+ ### Penanganan Error yang Idiomatis
+ Rust menggunakan monad `Result<T, E>` dan `Option<T>` alih-alih exception tradisional.
+ - **Tingkat Aplikasi**: Gunakan `anyhow` untuk pembuatan skrip cepat atau konteks aplikasi tingkat tinggi di mana pelacakan stack dan pembungkusan error acak diperlukan.
+ - **Tingkat Library**: Gunakan `thiserror` untuk mendefinisikan enum error domain yang tepat, terstruktur, dan deskriptif.
- impl AppState {
- pub fn new() -> Self {
- Self {
- inner: Arc::new(RwLock::new(SharedData {
- connections_count: 0,
- active_users: Vec::new(),
- })),
- }
- }
+ ### Pemrograman Asinkron (Rust 2024 + Tokio)
+ - **Gunakan Tugas Tokio untuk I/O**: Gunakan `tokio::spawn` untuk menjalankan tugas-tugas ringan dan konkuren.
+ - **JANGAN Blokir Runtime Asinkron**: Jangan pernah menjalankan pekerjaan berat CPU atau I/O sinkron secara langsung di dalam thread pekerja asinkron. Gunakan `tokio::task::spawn_blocking` jika diperlukan.
- pub fn add_user(&self, username: String) -> Result<(), &'static str> {
- let mut data = self.inner.write().map_err(|_| "poisoned_lock")?;
- data.connections_count += 1;
- data.active_users.push(username);
- Ok(())
- }
+ ### Integrasi Ekosistem Produksi
+ - **Axum + SQLx (Web API Stack)**: Axum menyediakan framework web asinkron terkemuka, sementara SQLx menyediakan lapisan interaksi database dengan pemeriksaan keamanan SQL pada saat kompilasi.
+ - **Clap + Serde (CLI Stack)**: Clap v4 menyediakan parser argumen baris perintah deklaratif berbasis makro. Serde menangani serialisasi/deserialisasi dengan lancar.
- pub fn get_user_count(&self) -> Result<u32, &'static str> {
- let data = self.inner.read().map_err(|_| "poisoned_lock")?;
- Ok(data.connections_count)
- }
- }
- ```
+ ### Optimasi & Kode Unsafe
+ - **Hindari Alokasi Heap**: Gunakan `&str` alih-alih `String` untuk variabel read-only. Gunakan `Cow<'a, str>` ketika variabel hanya sesekali dimutasi.
+ - **Konfigurasi Profil Release (`Cargo.toml`)**: Gunakan `opt-level = 3`, `lto = true`, dan `codegen-units = 1` untuk kinerja maksimal.
+ - **Kode Unsafe yang Aman**: Hanya gunakan `unsafe` untuk memanggil binding C atau struktur data lockless kustom. Selalu sertakan blok `// SAFETY:` untuk menjelaskan validitas invariant.
---
- ## Idiomatic Error Handling
-
- Rust does not have traditional exceptions. Instead, it utilizes the `Result<T, E>` and `Option<T>` monads.
-
- ### Guidelines for Error Design
- 1. **Application-level Errors**: Use `anyhow` for rapid scripting or high-level application contexts where stack traces and arbitrary error wrapping are needed.
- 2. **Library-level Errors**: Use `thiserror` to define precise, structured, and descriptive domain error enums that users can match against.
- 3. **The `?` Operator**: Use the `?` operator to propagate errors up the call stack.
-
- #### Example: library-level errors with `thiserror`
- ```rust
- use thiserror::Error;
-
- #[derive(Error, Debug)]
- pub enum DatabaseError {
- #[error("Database connection failed: {0}")]
- ConnectionFailed(String),
-
- #[error("Entity '{0}' not found with ID: {1}")]
- NotFound(String, i64),
-
- #[error("Unique constraint violation on field: {0}")]
- ConstraintViolation(String),
-
- #[error("Unknown database error occurred")]
- Unknown(#[from] sqlx::Error),
- }
- ```
+ <a name="english"></a>
+ ## English
- #### Example: application-level errors with `anyhow`
- ```rust
- use anyhow::{Context, Result};
- use std::fs::File;
- use std::io::Read;
+ ### Description
+ Expert-level guidance for writing high-performance, robust, and memory-safe systems applications using **Rust 2024 (v1.85+)**. This skill outlines advanced practices in ownership, lifetimes, error design, async architectures, backend development, performance tuning, and idiomatic ecosystem patterns.
- fn read_config_file(path: &str) -> Result<String> {
- let mut file = File::open(path)
- .with_context(|| format!("Failed to open config file at: {}", path))?;
-
- let mut contents = String::new();
- file.read_to_string(&mut contents)
- .with_context(|| "Failed to read config file contents into memory")?;
-
- Ok(contents)
- }
- ```
+ ### Trigger Conditions
+ - Use when bootstrapping or maintaining a production Rust crate, application, or workspace.
+ - Use when designing data models involving complex lifetimes, smart pointers (`Arc`, `Rc`, `RefCell`), or zero-copy abstractions (`Cow`).
+ - Use when building high-concurrency async services with **Tokio** and **Axum**.
+ - Use when interacting with databases safely using compile-time checked SQL with **SQLx**.
+ - Use when crafting modern CLI utilities using **Clap** and **Serde**.
+ - Use when migrating or upgrading an existing Rust codebase to the **Rust 2024 Edition**.
+ - Use when profiling, optimizing, or debugging compile times, memory footprints, or runtime performance.
- ---
+ ### Rust 2024 Edition & Core Architecture
+ Rust 2024 (stabilized in Rust v1.85) enhances language ergonomics, strengthens safety invariants, and introduces native async enhancements:
+ - **Async Closures**: Stable `async || {}` & `AsyncFn` traits.
+ - **RPIT Lifetimes**: RPIT (`impl Trait` in return position) captures all in-scope lifetimes by default. Use explicit `use<'a, T>` syntax if you want to restrict lifetime capturing.
+ - **Unsafe Extern**: `extern` blocks and specific attributes (`no_mangle`) now require the `unsafe` keyword.
+ - **Prelude Additions**: `Future` and `IntoFuture` are now imported automatically.
- ## Asynchronous Programming (Rust 2024 + Tokio)
+ ### Language Essentials & Memory Safety
+ Memory safety in Rust is guaranteed at compile time through the ownership system:
+ 1. **Ownership & Borrowing**: Each value has a single owner. You can have any number of immutable references (`&T`) *OR* exactly one active mutable reference (`&mut T`) to a value at any given time.
+ 2. **Lifetimes & Smart Pointers**: Avoid references (`&T`) in struct definitions unless short-lived. Use `Arc<T>` and `Mutex<T>` or `RwLock<T>` for thread-safe state sharing.
- Asynchronous Rust is powered by external runtimes. The production standard is **Tokio**.
+ ### Idiomatic Error Handling
+ Rust utilizes the `Result<T, E>` and `Option<T>` monads:
+ - **Application-level Errors**: Use `anyhow` for high-level application contexts where stack traces and arbitrary error wrapping are needed.
+ - **Library-level Errors**: Use `thiserror` to define precise, structured, and descriptive domain error enums.
- ### Best Practices in Async Rust
+ ### Asynchronous Programming (Rust 2024 + Tokio)
- **Prefer Tokio Tasks for I/O**: Use `tokio::spawn` to run light, concurrent tasks that perform asynchronous I/O.
- - **Do NOT Block the Async Runtime**: Never run CPU-bound work or synchronous block-I/O (like `std::fs::File` or synchronous locks) directly inside an async worker thread.
- - For long CPU-heavy processing, use `tokio::task::spawn_blocking`.
- - **Use Async Closures (Rust 2024)**: Define dynamic async mappings cleanly using the native `async ||` closure syntax.
-
- #### Example: Non-Blocking Task Spawning
- ```rust
- use tokio::task;
-
- async fn process_incoming_job(job_id: u64) {
- // 1. Asynchronous I/O (safe for the reactor thread)
- tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
-
- // 2. Heavy CPU calculation (must offload to avoid starving the executor)
- let computation_result = task::spawn_blocking(move || {
- // Perform heavy cryptography or matrix math here
- let mut sum: u64 = 0;
- for i in 0..10_000_000 {
- sum = sum.wrapping_add(i ^ job_id);
- }
- sum
- })
- .await
- .expect("Worker thread panicked");
-
- println!("Job {} computed result: {}", job_id, computation_result);
- }
- ```
-
- ---
-
- ## Production Ecosystem Integrations
-
- ### 1. Axum + SQLx (Web API Stack)
- **Axum** is the leading async web framework from the Tokio team. Combined with **SQLx**, it provides a type-safe, compile-time checked database interaction layer.
-
- #### Example: Production API Core (`src/main.rs`)
- ```rust
- use axum::{
- extract::{Path, State},
- http::StatusCode,
- routing::{get, post},
- Json, Router,
- };
- use serde::{Deserialize, Serialize};
- use sqlx::postgres::{PgPool, PgPoolOptions};
- use std::net::SocketAddr;
- use std::sync::Arc;
-
- #[derive(Serialize, Deserialize, Debug)]
- pub struct User {
- id: i32,
- username: String,
- email: String,
- }
-
- #[derive(Deserialize)]
- pub struct CreateUserDto {
- username: String,
- email: String,
- }
-
- pub struct ApiState {
- db_pool: PgPool,
- }
-
- #[tokio::main]
- async fn main() -> Result<(), anyhow::Error> {
- // Connect to PostgreSQL database using SQLx pooler
- let db_url = std::env::var("DATABASE_URL")
- .unwrap_or_else(|_| "postgres://postgres:password@localhost/my_db".to_string());
-
- let pool = PgPoolOptions::new()
- .max_connections(20)
- .connect(&db_url)
- .await?;
-
- let state = Arc::new(ApiState { db_pool: pool });
-
- // Scaffolding standard router with state
- let app = Router::new()
- .route("/users/:id", get(get_user_handler))
- .route("/users", post(create_user_handler))
- .with_state(state);
-
- let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
- println!("๐ Axum server running at http://{}", addr);
-
- let listener = tokio::net::TcpListener::bind(&addr).await?;
- axum::serve(listener, app).await?;
-
- Ok(())
- }
-
- // Extractor Pattern
- async fn get_user_handler(
- State(state): State<Arc<ApiState>>,
- Path(id): Path<i32>,
- ) -> Result<Json<User>, (StatusCode, String)> {
- // Compile-time verified query!
- let user = sqlx::query_as!(
- User,
- "SELECT id, username, email FROM users WHERE id = $1",
- id
- )
- .fetch_optional(&state.db_pool)
- .await
- .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
- .ok_or_else(|| (StatusCode::NOT_FOUND, "User not found".to_string()))?;
-
- Ok(Json(user))
- }
-
- async fn create_user_handler(
- State(state): State<Arc<ApiState>>,
- Json(payload): Json<CreateUserDto>,
- ) -> Result<(StatusCode, Json<User>), (StatusCode, String)> {
- let user = sqlx::query_as!(
- User,
- "INSERT INTO users (username, email) VALUES ($1, $2) RETURNING id, username, email",
- payload.username,
- payload.email
- )
- .fetch_one(&state.db_pool)
- .await
- .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
-
- Ok((StatusCode::CREATED, Json(user)))
- }
- ```
-
- ---
-
- ### 2. Clap + Serde (CLI Stack)
- **Clap v4** provides a declarative macro-based parser for command-line arguments. **Serde** handles seamless serialization/deserialization.
-
- #### Example: CLI Setup
- ```rust
- use clap::{Parser, Subcommand};
- use serde::{Deserialize, Serialize};
-
- #[derive(Parser, Debug)]
- #[command(name = "vibes-cli", author = "Roedy", version = "1.0", about = "CLI Tool")]
- pub struct Cli {
- #[arg(short, long, global = true, help = "Path to config file")]
- pub config: Option<String>,
-
- #[arg(short, long, action = clap::ArgAction::SetTrue, help = "Enable verbose logs")]
- pub verbose: bool,
-
- #[command(subcommand)]
- pub command: Commands,
- }
-
- #[derive(Subcommand, Debug)]
- pub enum Commands {
- #[command(about = "Analyze code file for bugs")]
- Analyze {
- #[arg(short, long, help = "Absolute target path")]
- path: String,
-
- #[arg(long, default_value = "json")]
- format: String,
- },
- #[command(about = "Initialize workspace config")]
- Init,
- }
- ```
-
- ---
-
- ## Optimization & Unsafe Code
-
- Rust is chosen for predictable, raw hardware performance. Ensure you implement performance best practices:
-
- ### 1. Avoid Heap Allocations where possible
- - Use `&str` instead of `String` for read-only variables.
- - Use `Cow<'a, str>` (Copy-On-Write) when a variable is occasionally mutated but is usually read-only.
- - Use slices `&[T]` instead of vectors `&Vec<T>` as function arguments to enable the compiler to perform bounds-check optimizations.
-
- ### 2. Configure Cargo Release Profile (`Cargo.toml`)
- Optimize compilation artifacts for production deployment:
- ```toml
- [profile.release]
- opt-level = 3 # Max optimization
- lto = true # Enable Link-Time Optimization
- codegen-units = 1 # Maximize compiler optimization passes
- panic = "abort" # Strip panic unwinding machinery to reduce binary size
- strip = true # Automatically strip symbols/debug info
- ```
-
- ### 3. Sound Unsafe Practices
- - **Rules of Unsafe**: Only use `unsafe` to call C bindings, write custom lockless data structures, or interact directly with raw pointers.
- - Always include a `// SAFETY:` block explaining exactly why the invariant is soundly guaranteed.
-
- ```rust
- // SAFETY: We must guarantee that `ptr` points to a valid, initialized u32
- // memory address and is aligned properly.
- unsafe {
- let value = std::ptr::read_volatile(ptr);
- // ...
- }
- ```
-
- ---
-
- ## Testing & Quality Control
-
- Verify code validity using Rust's integrated test runner.
-
- ### 1. Structure Tests Correctly
- - Keep **unit tests** in the same file as the production code using the `#[cfg(test)]` module pattern.
- - Keep **integration tests** in the `/tests` root subdirectory, referencing only public crate APIs.
-
- #### Example: Idiomatic Test Block
- ```rust
- pub fn calculate_sum(a: i32, b: i32) -> i32 {
- a + b
- }
-
- #[cfg(test)]
- mod tests {
- use super::*;
-
- #[test]
- fn test_calculate_sum() {
- assert_eq!(calculate_sum(2, 2), 4);
- }
- }
- ```
+ - **Do NOT Block the Async Runtime**: Never run CPU-bound work or synchronous block-I/O directly inside an async worker thread. Use `tokio::task::spawn_blocking` to offload heavy calculations.
- ### 2. Linting & Formatting Quality Checks
- Run these tools routinely before staging code:
- ```bash
- # Verify formatting consistency
- cargo fmt --all -- --check
+ ### Production Ecosystem Integrations
+ - **Axum + SQLx**: High performance async routing combined with compile-time checked PostgreSQL database queries.
+ - **Clap + Serde**: Declarative command-line argument parser and serialization/deserialization.
- # Run rigorous compiler linting with Clippy
- cargo clippy --all-targets --all-features -- -D warnings
- ```
+ ### Optimization & Unsafe Code
+ - **Avoid Heap Allocations**: Use slices `&[T]` and zero-copy `Cow<'a, str>` wrappers where possible.
+ - **Release Profile (`Cargo.toml`)**: Use `opt-level = 3`, `lto = true`, and `codegen-units = 1` for production.
+ - **Sound Unsafe**: Only use `unsafe` when absolutely required. Always document with a `// SAFETY:` block.
---
- ## Troubleshooting & Common Gotchas
-
- ### 1. Lifetimes Mismatch (Borrow Checker)
- - **Problem**: Compiler complains that "borrowed value does not live long enough".
- - **Solution**: Check if you are returning a reference to a local variable created inside the function. Always return owned data (`String`, `Vec<T>`) or adjust the function bounds so the output lifetime matches the input borrow lifetime (`fn parse<'a>(&'a self) -> &'a str`).
-
- ### 2. Send / Sync Boundary Failures
- - **Problem**: In async functions, compiler throws `std::marker::Send` or `std::marker::Sync` compile errors on a spawn block.
- - **Solution**: An async block across an `.await` boundary must be thread-safe. Ensure that all variables alive across `.await` points are `Send`. Avoid holding standard `std::sync::MutexGuard` across an `.await` call; use `tokio::sync::Mutex` instead, or drop the guard beforehand.
-
- ### 3. Cargo Workspace Locking
- - **Problem**: `blocking waiting for file lock on package cache` or target directory lock.
- - **Solution**: Make sure no parallel build or IDE task is locked. Run `rm -f target/.rustc_info.json` or clear lock files if a zombie task was terminated abruptly.
+ ### Troubleshooting & Common Gotchas / Pemecahan Masalah
+ - **Lifetimes Mismatch**: Ensure returned references don't point to local variables. Use owned types or bind output lifetimes to input lifetimes.
+ - **Send / Sync Boundary Failures**: Async block elements across `.await` must implement `Send`. Avoid holding synchronous mutex guards across `.await` points.