Skill: ivangdavila/rust (version 1.0.1)

--- name: Rust slug: rust version: 1.0.1 description: Write idiomatic Rust avoiding ownership pitfalls, lifetime confusion, and common borrow checker battles. metadata: {"clawdbot":{"emoji":"🦀","requires":{"bins":["rustc","cargo"]},"os":["linux","darwin","win32"]}} --- ## Quick Reference | Topic | File | Key Trap | |-------|------|----------| | Ownership & Borrowing | `ownership-borrowing.md` | Move semantics catch everyone | | Strings & Types | `types-strings.md` | `String` vs `&str`, UTF-8 indexing | | Errors & Iteration | `errors-iteration.md` | `unwrap()` in production, lazy iterators | | Concurrency & Memory | `concurrency-memory.md` | `Rc` not `Send`, `RefCell` panics | | Advanced Traps | `advanced-traps.md` | unsafe, macros, FFI, performance | --- ## Critical Traps (High-Frequency Failures) ### Ownership — #1 Source of Compiler Errors - **Variable moved after use** — clone explicitly or borrow with `&` - **`for item in vec` moves vec** — use `&vec` or `.iter()` to borrow - **`String` moved into function** — pass `&str` for read-only access ### Borrowing — The Borrow Checker Always Wins - **Can't have `&mut` and `&` simultaneously** — restructure or interior mutability - **Returning reference to local fails** — return owned value instead - **Mutable borrow through `&mut self` blocks all access** — split struct or `RefCell` ### Lifetimes — When Compiler Can't Infer - **`'static` means CAN live forever, not DOES** — `String` is 'static capable - **Struct with reference needs `<'a>`** — `struct Foo<'a> { bar: &'a str }` - **Function returning ref must tie to input** — `fn get<'a>(s: &'a str) -> &'a str` ### Strings — UTF-8 Surprises - **`s[0]` doesn't compile** — use `.chars().nth(0)` or `.bytes()` - **`.len()` returns bytes, not chars** — use `.chars().count()` - **`s1 + &s2` moves s1** — use `format!("{}{}", s1, s2)` to keep both ### Error Handling — Production Code - **`unwrap()` panics** — use `?` or `match` in production - **`?` needs `Result`/`Option` return type** — main needs `-> Result<()>` - **`expect("context")` > `unwrap()`** — shows why it panicked ### Iterators — Lazy Evaluation - **`.iter()` borrows, `.into_iter()` moves** — choose carefully - **`.collect()` needs type** — `collect::<Vec<_>>()` or typed binding - **Iterators are lazy** — nothing runs until consumed ### Concurrency — Thread Safety - **`Rc` is NOT `Send`** — use `Arc` for threads - **`Mutex` lock returns guard** — auto-unlocks on drop, don't hold across await - **`RwLock` deadlock** — reader upgrading to writer blocks forever ### Memory — Smart Pointers - **`RefCell` panics at runtime** — if borrow rules violated - **`Box` for recursive types** — compiler needs known size - **Avoid `Rc<RefCell<T>>` spaghetti** — rethink ownership --- ## Common Compiler Errors (NEW) | Error | Cause | Fix | |-------|-------|-----| | `value moved here` | Used after move | Clone or borrow | | `cannot borrow as mutable` | Already borrowed | Restructure or RefCell | | `missing lifetime specifier` | Ambiguous reference | Add `<'a>` | | `the trait bound X is not satisfied` | Missing impl | Check trait bounds | | `type annotations needed` | Can't infer | Turbofish or explicit type | | `cannot move out of borrowed content` | Deref moves | Clone or pattern match | --- ## Cargo Traps (NEW) - **`cargo update` updates Cargo.lock, not Cargo.toml** — manual version bump needed - **Features are additive** — can't disable a feature a dependency enables - **`[dev-dependencies]` not in release binary** — but in tests/examples - **`cargo build --release` much faster** — debug builds are slow intentionally

path: advanced-traps.md
content: # Advanced Traps — unsafe, macros, FFI, testing, performance

## Unsafe Code

- **`unsafe` doesn't disable borrow checker** — only allows 5 specific operations
- **Raw pointers `*const T` / `*mut T`** — can be null, dangling, or aliased
- **`unsafe impl` for Send/Sync** — you guarantee invariants compiler can't check
- **`transmute` is nuclear** — reinterprets bits, can cause UB easily
- **Undefined behavior is NEVER acceptable** — even if "it works on my machine"

## Macro Pitfalls

- **`macro_rules!` hygiene** — identifiers don't leak, but paths can be tricky
- **Macro expansion order** — can cause surprising errors
- **`$crate` for paths in macros** — ensures correct crate resolution
- **Proc macros need separate crate** — `proc-macro = true` in Cargo.toml
- **Debug macros with `cargo expand`** — see what code actually generates
- **`stringify!` and `concat!`** — compile-time string operations

## FFI Issues

- **`#[repr(C)]` for C-compatible layout** — Rust default layout is unspecified
- **Null-terminated strings** — `CString` / `CStr` not `String` / `&str`
- **`extern "C"` for C ABI** — Rust ABI is unstable
- **Ownership across FFI** — who frees what? Document clearly
- **Panics across FFI boundary** — undefined behavior, use `catch_unwind`
- **`Option<&T>` is nullable pointer** — FFI-safe optimization

## Testing Traps

- **`#[cfg(test)]` module not in release** — but dependencies still compile
- **`assert_eq!` shows both values** — better than `assert!(a == b)`
- **`#[should_panic]` for panic tests** — can specify `expected = "message"`
- **`Result<(), E>` return in tests** — use `?` in test functions
- **Integration tests in `tests/`** — separate compilation, external API only
- **`cargo test -- --nocapture`** — to see println! output

## Performance Traps

- **`.clone()` is not free** — deep copy for most types
- **String allocation on every `format!`** — reuse buffers with `write!`
- **`Vec` reallocation** — use `with_capacity()` if size known
- **Iterator vs loop** — usually same perf, but check with `cargo bench`
- **`Box<dyn Trait>` indirection** — generics are faster if possible
- **`#[inline]` across crates** — needed for cross-crate inlining
- **Debug vs Release** — 10-100x difference, always bench in release


path: concurrency-memory.md
content: # Concurrency & Memory Patterns

## Concurrency

- **Data shared between threads needs `Send` and `Sync`** — most types are, `Rc` is not
- **Use `Arc` for shared ownership across threads** — `Rc` is single-threaded only
- **`Mutex<T>` for mutable shared state** — lock returns guard, auto-unlocks on drop
- **`RwLock` allows multiple readers or one writer** — deadlock if reader tries to write
- **Async functions return `Future`** — must be awaited or spawned

## Memory Patterns

- **`Box<T>` for heap allocation** — also needed for recursive types
- **`Rc<T>` for shared ownership (single-thread)** — `Arc<T>` for multi-thread
- **`RefCell<T>` for interior mutability** — runtime borrow checking, panics on violation
- **`Cell<T>` for Copy types interior mutability** — no borrow, just get/set
- **Avoid `Rc<RefCell<T>>` spaghetti** — rethink ownership structure

## Async Traps (NEW)

- **`.await` only in async context** — can't call from sync code directly
- **Async traits need `async-trait` crate** — or `-> impl Future` (nightly/2024+)
- **`Mutex` guard across `.await`** — use `tokio::sync::Mutex` not `std::sync::Mutex`
- **`spawn` requires `'static`** — move data in or use `Arc`
- **Executor required** — `tokio`, `async-std`, or `smol` to actually run futures
- **`select!` cancellation** — dropped future may not run cleanup

## Additional Memory Traps (NEW)

- **`Weak<T>` for breaking cycles** — `Rc`/`Arc` cycles leak memory
- **`Pin<T>` for self-referential** — async futures are often pinned
- **`MaybeUninit` for uninitialized** — safe wrapper for unsafe init patterns
- **`std::mem::drop` vs `Drop` trait** — `drop(x)` just calls `x.drop()` early
- **`ManuallyDrop` skips destructor** — useful for FFI or unions
- **Stack overflow with deep recursion** — Box recursion or increase stack


path: errors-iteration.md
content: # Error Handling & Pattern Matching & Iterators

## Error Handling

- **`unwrap()` panics on None/Err** — use `?` operator or `match` in production
- **`?` requires function returns Result/Option** — can't use in main without `-> Result<()>`
- **Converting errors: `map_err()` or `From` trait implementation**
- **`expect("msg")` better than `unwrap()`** — shows context on panic
- **`Option` and `Result` don't mix** — use `.ok()` or `.ok_or()` to convert

## Pattern Matching

- **Match must be exhaustive** — use `_` wildcard for remaining cases
- **`if let` for single pattern** — avoids verbose match for one case
- **Guard conditions: `match x { n if n > 0 => ... }`** — guards don't create bindings
- **`@` bindings: `Some(val @ 1..=5)`** — binds matched value to name
- **`ref` keyword in patterns to borrow** — often unnecessary with match ergonomics

## Iterator Gotchas

- **`.iter()` borrows, `.into_iter()` moves, `.iter_mut()` borrows mutably**
- **`.collect()` needs type annotation** — `collect::<Vec<_>>()` or let binding with type
- **Iterators are lazy** — nothing happens until consumed
- **`.map()` returns iterator, not collection** — chain with `.collect()`
- **Modifying while iterating impossible** — collect indices first, then modify

## Additional Traps (NEW)

### Error Handling
- **`anyhow` vs `thiserror`** — anyhow for apps, thiserror for libraries
- **`?` in closures** — closure must also return Result/Option
- **`panic!` unwinds by default** — `panic = "abort"` in Cargo.toml for smaller binary

### Iterators
- **`.filter_map()` combines filter and map** — cleaner than chaining
- **`.flatten()` for nested iterators** — `Option` and `Result` are iterators too
- **`.cloned()` vs `.copied()`** — copied for Copy types, cloned calls clone
- **`Iterator` vs `IntoIterator`** — for loops call `into_iter()` automatically
- **`.enumerate()` gives `(index, value)`** — index is usize


path: ownership-borrowing.md
content: # Ownership & Borrowing & Lifetimes

## Ownership Traps

- **Variable moved after use** — clone explicitly or borrow with `&`
- **`for item in vec` moves vec** — use `&vec` or `.iter()` to borrow
- **Struct field access moves field if not Copy** — destructure or clone
- **Closure captures by move with `move ||`** — needed for threads and 'static
- **`String` moved into function** — pass `&str` for read-only access

## Borrowing Battles

- **Can't have mutable and immutable borrow simultaneously** — restructure code or use interior mutability
- **Borrow lasts until last use (NLL)** — not until scope end in modern Rust
- **Returning reference to local fails** — return owned value or use lifetime parameter
- **Mutable borrow through `&mut self` blocks all other access** — split struct or use `RefCell`

## Lifetime Gotchas

- **Missing lifetime annotation** — compiler usually infers, explicit when multiple references
- **`'static` means "can live forever", not "lives forever"** — `String` is 'static, `&str` may not be
- **Struct holding reference needs lifetime parameter** — `struct Foo<'a> { bar: &'a str }`
- **Function returning reference must tie to input lifetime** — `fn get<'a>(s: &'a str) -> &'a str`

## Additional Traps (NEW)

- **Partial moves in structs** — moving one field makes whole struct unusable (unless using remaining fields explicitly)
- **`Option<&T>` vs `&Option<T>`** — `.as_ref()` converts outer to inner reference
- **Reborrowing `&mut` through `&`** — auto-reborrow works but explicit sometimes needed
- **Lifetime elision rules** — `fn foo(x: &str) -> &str` implicitly ties output to input
- **`'a: 'b` means 'a outlives 'b** — covariance/contravariance matters in generics


path: types-strings.md
content: # Strings & Type System

## String Confusion

- **`String` is owned, `&str` is borrowed slice** — convert with `.as_str()` or `String::from()`
- **Indexing `s[0]` fails** — UTF-8 variable width, use `.chars().nth(0)` or `.bytes()`
- **Concatenation: `s1 + &s2` moves s1** — use `format!("{}{}", s1, s2)` to keep both
- **`.len()` returns bytes, not characters** — use `.chars().count()` for char count

## Type System Traps

- **Orphan rule: can't impl external trait on external type** — newtype pattern workaround
- **Trait objects `dyn Trait` have runtime cost** — generics monomorphize for performance
- **`Box<dyn Trait>` for heap-allocated trait object** — `&dyn Trait` for borrowed
- **Associated types vs generics** — use associated when one impl per type
- **`Self` vs `self`** — type vs value: `Self::new()` vs `&self`

## Additional String Traps (NEW)

- **`&String` auto-derefs to `&str`** — but prefer `&str` in function params
- **`str::from_utf8` can fail** — use `String::from_utf8_lossy` if uncertain
- **`char` is 4 bytes (Unicode scalar)** — not 1 byte like C
- **`.split()` returns iterator** — `collect()` to get `Vec<&str>`
- **`OsString` for paths** — not all paths are valid UTF-8

## Type System Advanced (NEW)

- **`impl Trait` vs `dyn Trait`** — static dispatch vs dynamic, different use cases
- **`Sized` bound implicit** — `?Sized` to accept unsized types
- **Coherence rules** — only one impl per type, foundational trait first
- **`PhantomData<T>`** — for unused type parameters (e.g., lifetime markers)
- **`Deref` coercion** — `&String` to `&str` automatic, but can be confusing


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)