agentic-team-templates 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,236 @@
1
+ # Rust Traits and Generics
2
+
3
+ Traits are Rust's mechanism for abstraction, polymorphism, and code reuse. Combined with generics, they enable zero-cost abstractions that rival hand-written specialized code.
4
+
5
+ ## Trait Design
6
+
7
+ ### Small, Focused Traits
8
+
9
+ ```rust
10
+ // Good: Single-purpose traits
11
+ pub trait Validate {
12
+ fn validate(&self) -> Result<(), ValidationError>;
13
+ }
14
+
15
+ pub trait Serialize {
16
+ fn serialize(&self, writer: &mut dyn Write) -> Result<(), SerializeError>;
17
+ }
18
+
19
+ // Bad: God trait
20
+ pub trait Entity {
21
+ fn validate(&self) -> Result<(), Error>;
22
+ fn serialize(&self) -> Vec<u8>;
23
+ fn save(&self, db: &Database) -> Result<(), Error>;
24
+ fn render(&self) -> Html;
25
+ // Too many responsibilities — split by concern
26
+ }
27
+ ```
28
+
29
+ ### Extension Traits
30
+
31
+ ```rust
32
+ // Add methods to existing types via extension traits
33
+ pub trait StrExt {
34
+ fn is_blank(&self) -> bool;
35
+ fn truncate_to(&self, max_len: usize) -> &str;
36
+ }
37
+
38
+ impl StrExt for str {
39
+ fn is_blank(&self) -> bool {
40
+ self.trim().is_empty()
41
+ }
42
+
43
+ fn truncate_to(&self, max_len: usize) -> &str {
44
+ if self.len() <= max_len {
45
+ self
46
+ } else {
47
+ // Find a char boundary to avoid panic
48
+ let mut end = max_len;
49
+ while !self.is_char_boundary(end) {
50
+ end -= 1;
51
+ }
52
+ &self[..end]
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### Sealed Traits
59
+
60
+ ```rust
61
+ // Prevent external implementations when your trait is part of an internal contract
62
+ mod private {
63
+ pub trait Sealed {}
64
+ }
65
+
66
+ pub trait Backend: private::Sealed {
67
+ fn execute(&self, query: &str) -> Result<Rows>;
68
+ }
69
+
70
+ // Only types in your crate can implement Sealed, so only they can implement Backend
71
+ impl private::Sealed for PostgresBackend {}
72
+ impl Backend for PostgresBackend { ... }
73
+ ```
74
+
75
+ ### The Newtype Pattern
76
+
77
+ ```rust
78
+ // Implement foreign traits on foreign types via newtype
79
+ struct Meters(f64);
80
+ struct Seconds(f64);
81
+
82
+ impl fmt::Display for Meters {
83
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84
+ write!(f, "{:.2}m", self.0)
85
+ }
86
+ }
87
+
88
+ // Also prevents mixing units at compile time
89
+ fn speed(distance: Meters, time: Seconds) -> f64 {
90
+ distance.0 / time.0
91
+ }
92
+ // speed(Seconds(1.0), Meters(5.0)) — compile error! Arguments are swapped.
93
+ ```
94
+
95
+ ## Generics
96
+
97
+ ### Trait Bounds
98
+
99
+ ```rust
100
+ // Prefer impl Trait for simple cases
101
+ fn print_all(items: &[impl Display]) {
102
+ for item in items {
103
+ println!("{item}");
104
+ }
105
+ }
106
+
107
+ // Use where clauses for complex bounds
108
+ fn merge<T, U>(left: T, right: U) -> Merged
109
+ where
110
+ T: IntoIterator<Item = Record>,
111
+ U: IntoIterator<Item = Record>,
112
+ T::IntoIter: ExactSizeIterator,
113
+ {
114
+ // ...
115
+ }
116
+
117
+ // Use explicit generic parameters when the caller needs to specify the type
118
+ fn parse<T: FromStr>(input: &str) -> Result<T, T::Err> {
119
+ input.parse()
120
+ }
121
+ let n: i32 = parse("42")?;
122
+ let f: f64 = parse("3.14")?;
123
+ ```
124
+
125
+ ### Associated Types vs Generic Parameters
126
+
127
+ ```rust
128
+ // Associated types: one implementation per type
129
+ trait Iterator {
130
+ type Item; // Each iterator has exactly one Item type
131
+ fn next(&mut self) -> Option<Self::Item>;
132
+ }
133
+
134
+ // Generic parameters: multiple implementations per type
135
+ trait Convert<T> {
136
+ fn convert(&self) -> T;
137
+ }
138
+ // A single type can implement Convert<String>, Convert<i32>, etc.
139
+
140
+ // Rule of thumb: If there should be only one implementation
141
+ // for a given Self type, use an associated type.
142
+ ```
143
+
144
+ ### Phantom Types
145
+
146
+ ```rust
147
+ use std::marker::PhantomData;
148
+
149
+ // Type-state pattern: encode state in the type system
150
+ struct Validated;
151
+ struct Unvalidated;
152
+
153
+ struct Form<State> {
154
+ data: FormData,
155
+ _state: PhantomData<State>,
156
+ }
157
+
158
+ impl Form<Unvalidated> {
159
+ fn new(data: FormData) -> Self {
160
+ Form { data, _state: PhantomData }
161
+ }
162
+
163
+ fn validate(self) -> Result<Form<Validated>, ValidationError> {
164
+ // validation logic...
165
+ Ok(Form { data: self.data, _state: PhantomData })
166
+ }
167
+ }
168
+
169
+ impl Form<Validated> {
170
+ fn submit(self) -> Result<(), SubmitError> {
171
+ // Only validated forms can be submitted
172
+ send(self.data)
173
+ }
174
+ }
175
+
176
+ // Form::new(data).submit() — compile error! Must validate first.
177
+ ```
178
+
179
+ ## Dynamic Dispatch
180
+
181
+ ```rust
182
+ // Static dispatch (monomorphization) — zero cost, larger binary
183
+ fn process(handler: impl Handler) { handler.handle(); }
184
+
185
+ // Dynamic dispatch (trait objects) — vtable indirection, smaller binary
186
+ fn process(handler: &dyn Handler) { handler.handle(); }
187
+
188
+ // Use trait objects when:
189
+ // - You need a heterogeneous collection
190
+ // - You want to reduce binary size (e.g., embedded)
191
+ // - The type is determined at runtime
192
+
193
+ // Trait object safety: a trait is object-safe if:
194
+ // - No methods return Self
195
+ // - No methods have generic type parameters
196
+ // - No associated functions (no &self receiver)
197
+ ```
198
+
199
+ ## Derive and Common Traits
200
+
201
+ ```rust
202
+ // Derive what you can — it's correct and free
203
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
204
+ pub struct UserId(String);
205
+
206
+ // Standard trait hierarchy to consider:
207
+ // Debug — always derive, essential for diagnostics
208
+ // Clone — when values need to be duplicated
209
+ // PartialEq/Eq — when values need comparison
210
+ // Hash — when used as map keys (requires Eq)
211
+ // Default — when a meaningful zero value exists
212
+ // Display — for user-facing output (implement manually)
213
+ // Serialize/Deserialize — for serde (derive with feature flag)
214
+
215
+ // Don't derive Copy unless the type is truly trivially copyable
216
+ // and you want implicit copies. Copy types can't have Drop.
217
+ ```
218
+
219
+ ## Anti-Patterns
220
+
221
+ ```rust
222
+ // Never: Trait objects everywhere when generics would work
223
+ // Box<dyn Fn()> is fine for callbacks stored in structs
224
+ // impl Fn() is better for function parameters
225
+
226
+ // Never: Overusing generics for types that will only ever have one concrete type
227
+ fn process<T: Into<String>>(name: T) { } // Just take String or &str
228
+
229
+ // Never: Unused type parameters
230
+ struct Wrapper<T> { // T is not used — won't compile without PhantomData
231
+ data: Vec<u8>,
232
+ }
233
+
234
+ // Never: Implementing traits for types you don't own without a newtype
235
+ // Orphan rule prevents this anyway — respect it
236
+ ```
@@ -0,0 +1,283 @@
1
+ # Rust Expert Development Guide
2
+
3
+ Principal-level guidelines for Rust engineering. Ownership, zero-cost abstractions, and fearless concurrency — wielded with precision.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ This guide applies to:
10
+ - Systems programming and embedded targets
11
+ - Web services and async runtimes (Tokio, async-std)
12
+ - CLI tools and developer utilities
13
+ - Libraries and crates published to crates.io
14
+ - WebAssembly targets
15
+ - FFI and interop with C/C++
16
+
17
+ ### Core Philosophy
18
+
19
+ Rust gives you power without sacrificing safety. The compiler is your closest collaborator.
20
+
21
+ - **If it compiles, it's probably correct.** The borrow checker catches bugs that would be CVEs elsewhere.
22
+ - **Zero-cost abstractions are the point.** Never choose between expressiveness and performance.
23
+ - **Make illegal states unrepresentable.** Encode invariants in the type system.
24
+ - **Explicit over implicit.** Lifetimes, ownership, error handling — surfaced, not hidden.
25
+ - **Unsafe is a scalpel, not a sledgehammer.** Every `unsafe` block is a proof obligation.
26
+ - **If you don't know, say so.** Admitting uncertainty is better than guessing about soundness.
27
+
28
+ ### Project Structure
29
+
30
+ ```
31
+ project/
32
+ ├── Cargo.toml
33
+ ├── src/
34
+ │ ├── main.rs / lib.rs
35
+ │ ├── error.rs
36
+ │ └── domain/
37
+ ├── tests/ # Integration tests
38
+ ├── benches/ # Benchmarks
39
+ └── examples/
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Ownership and Borrowing
45
+
46
+ ### The Three Rules
47
+
48
+ 1. Each value has exactly one owner
49
+ 2. When the owner goes out of scope, the value is dropped
50
+ 3. Either one `&mut T` OR any number of `&T` — never both
51
+
52
+ ### Lifetimes
53
+
54
+ ```rust
55
+ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
56
+ if x.len() > y.len() { x } else { y }
57
+ }
58
+ ```
59
+
60
+ ### Smart Pointers
61
+
62
+ - `Box<T>` — heap allocation, single owner
63
+ - `Rc<T>` — reference-counted, single-threaded
64
+ - `Arc<T>` — atomic reference-counted, thread-safe
65
+ - `Cow<'_, T>` — clone-on-write, avoid allocation when possible
66
+
67
+ ### Interior Mutability
68
+
69
+ - `Cell<T>` — Copy types, single-threaded, zero overhead
70
+ - `RefCell<T>` — runtime borrow checking, single-threaded
71
+ - `Mutex<T>` / `RwLock<T>` — thread-safe
72
+ - `Atomic*` — lock-free primitives
73
+
74
+ ---
75
+
76
+ ## Error Handling
77
+
78
+ ### thiserror (Libraries)
79
+
80
+ ```rust
81
+ #[derive(Debug, Error)]
82
+ pub enum AppError {
83
+ #[error("database query failed")]
84
+ Database(#[from] sqlx::Error),
85
+ #[error("record not found: {entity} with id {id}")]
86
+ NotFound { entity: &'static str, id: String },
87
+ }
88
+ ```
89
+
90
+ ### anyhow (Applications)
91
+
92
+ ```rust
93
+ fn load_config(path: &Path) -> Result<Config> {
94
+ let contents = fs::read_to_string(path)
95
+ .with_context(|| format!("reading config from {}", path.display()))?;
96
+ Ok(toml::from_str(&contents).context("parsing config")?)
97
+ }
98
+ ```
99
+
100
+ ### Panic Policy
101
+
102
+ Panics are for bugs, not expected errors. No `unwrap()` in library code without justification. `todo!()` never ships.
103
+
104
+ ---
105
+
106
+ ## Traits and Generics
107
+
108
+ ### Small, Focused Traits
109
+
110
+ ```rust
111
+ pub trait Validate {
112
+ fn validate(&self) -> Result<(), ValidationError>;
113
+ }
114
+ ```
115
+
116
+ ### Define Interfaces at the Consumer
117
+
118
+ The consumer decides what it needs — don't force a God-trait on callers.
119
+
120
+ ### Phantom Types for State Machines
121
+
122
+ ```rust
123
+ struct Form<State> { data: FormData, _state: PhantomData<State> }
124
+ // Form<Unvalidated> can't call submit() — only Form<Validated> can
125
+ ```
126
+
127
+ ### Generics Rules
128
+
129
+ - `impl Trait` for simple bounds in function parameters
130
+ - `where` clauses for complex bounds
131
+ - Associated types when there's one implementation per Self type
132
+ - Generic parameters when multiple implementations per Self type
133
+
134
+ ---
135
+
136
+ ## Concurrency
137
+
138
+ ### Threads
139
+
140
+ ```rust
141
+ // Scoped threads (1.63+) — safe borrows from parent stack
142
+ thread::scope(|s| {
143
+ s.spawn(|| process(&data));
144
+ });
145
+ ```
146
+
147
+ ### Async/Await
148
+
149
+ ```rust
150
+ // Concurrent execution
151
+ let (users, posts) = tokio::join!(fetch_users(), fetch_posts());
152
+
153
+ // Timeout
154
+ tokio::select! {
155
+ result = fetch_data() => handle(result),
156
+ _ = tokio::time::sleep(Duration::from_secs(5)) => bail!("timeout"),
157
+ }
158
+ ```
159
+
160
+ ### Key Rules
161
+
162
+ - Never hold a `MutexGuard` across an `.await` point
163
+ - Never block in async context — use `spawn_blocking` for CPU work
164
+ - Use `tokio::sync::Mutex` when you must hold across awaits
165
+ - Every spawned task needs a cancellation/shutdown strategy
166
+
167
+ ---
168
+
169
+ ## Testing
170
+
171
+ ### Table-Style Tests
172
+
173
+ ```rust
174
+ #[test]
175
+ fn test_parse_age() {
176
+ let cases = [("25", Ok(25)), ("-1", Err(..)), ("abc", Err(..))];
177
+ for (input, expected) in cases {
178
+ assert_eq!(parse_age(input), expected, "input: {input}");
179
+ }
180
+ }
181
+ ```
182
+
183
+ ### Trait-Based Dependency Injection
184
+
185
+ ```rust
186
+ trait Clock { fn now(&self) -> DateTime<Utc>; }
187
+ struct FakeClock(DateTime<Utc>);
188
+ impl Clock for FakeClock { fn now(&self) -> DateTime<Utc> { self.0 } }
189
+ ```
190
+
191
+ ### Property-Based Testing
192
+
193
+ ```rust
194
+ proptest! {
195
+ #[test]
196
+ fn round_trips(name in "[a-z]{1,50}", age in 0u32..150) {
197
+ let user = User { name, age };
198
+ let json = serde_json::to_string(&user)?;
199
+ let decoded: User = serde_json::from_str(&json)?;
200
+ assert_eq!(user, decoded);
201
+ }
202
+ }
203
+ ```
204
+
205
+ ### Always Run
206
+
207
+ ```bash
208
+ cargo test --all-features
209
+ cargo clippy -- -D warnings
210
+ cargo +nightly miri test # For crates with unsafe
211
+ ```
212
+
213
+ ---
214
+
215
+ ## Performance and Unsafe
216
+
217
+ ### Measure First
218
+
219
+ ```bash
220
+ cargo bench
221
+ cargo flamegraph
222
+ cargo build --timings
223
+ ```
224
+
225
+ ### Key Patterns
226
+
227
+ - Preallocate with `Vec::with_capacity`
228
+ - Iterators over collect-then-iterate
229
+ - `Cow` for conditional allocation
230
+ - `SmallVec` for small stack-allocated collections
231
+ - `String::with_capacity` and `std::fmt::Write`
232
+
233
+ ### Unsafe Rules
234
+
235
+ - Every `unsafe` block gets a `// SAFETY:` comment
236
+ - Wrap unsafe in safe abstractions with narrow interfaces
237
+ - Run Miri in CI for any crate with unsafe code
238
+ - `unsafe` doesn't fix design problems — it hides them
239
+
240
+ ---
241
+
242
+ ## Ecosystem and Tooling
243
+
244
+ ### Essential Crates
245
+
246
+ | Domain | Crate |
247
+ |--------|-------|
248
+ | Serialization | serde, serde_json |
249
+ | Async | tokio |
250
+ | Web | axum, reqwest, tonic |
251
+ | Database | sqlx, diesel |
252
+ | Errors | thiserror, anyhow |
253
+ | CLI | clap |
254
+ | Observability | tracing, metrics |
255
+ | Testing | proptest, criterion, mockall, insta |
256
+
257
+ ### CI Essentials
258
+
259
+ ```bash
260
+ cargo fmt -- --check
261
+ cargo clippy --all-targets --all-features -- -D warnings
262
+ cargo test --all-features
263
+ cargo audit
264
+ cargo deny check
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Definition of Done
270
+
271
+ A Rust feature is complete when:
272
+
273
+ - [ ] `cargo build` compiles with zero warnings
274
+ - [ ] `cargo clippy -- -D warnings` passes
275
+ - [ ] `cargo test` passes (including doc tests)
276
+ - [ ] `cargo fmt -- --check` passes
277
+ - [ ] No `unwrap()` in library code without justification
278
+ - [ ] All `unsafe` blocks have `// SAFETY:` comments
279
+ - [ ] Error types implement `std::error::Error`
280
+ - [ ] Public API has doc comments with examples
281
+ - [ ] No unnecessary allocations in hot paths
282
+ - [ ] `cargo deny check` passes
283
+ - [ ] Code reviewed and approved