@booklib/skills 1.3.2 → 1.4.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.
Files changed (31) hide show
  1. package/AGENTS.md +108 -0
  2. package/CLAUDE.md +57 -0
  3. package/CODE_OF_CONDUCT.md +31 -0
  4. package/CONTRIBUTING.md +13 -0
  5. package/README.md +68 -45
  6. package/SECURITY.md +9 -0
  7. package/assets/logo.svg +36 -0
  8. package/demo.gif +0 -0
  9. package/demo.tape +40 -0
  10. package/docs/index.html +187 -0
  11. package/package.json +2 -2
  12. package/skills/effective-typescript/SKILL.md +166 -0
  13. package/skills/effective-typescript/evals/evals.json +36 -0
  14. package/skills/effective-typescript/examples/after.md +70 -0
  15. package/skills/effective-typescript/examples/before.md +47 -0
  16. package/skills/effective-typescript/references/api_reference.md +118 -0
  17. package/skills/effective-typescript/references/practices-catalog.md +371 -0
  18. package/skills/programming-with-rust/SKILL.md +194 -0
  19. package/skills/programming-with-rust/evals/evals.json +37 -0
  20. package/skills/programming-with-rust/examples/after.md +107 -0
  21. package/skills/programming-with-rust/examples/before.md +59 -0
  22. package/skills/programming-with-rust/references/api_reference.md +152 -0
  23. package/skills/programming-with-rust/references/practices-catalog.md +335 -0
  24. package/skills/rust-in-action/SKILL.md +290 -0
  25. package/skills/rust-in-action/evals/evals.json +38 -0
  26. package/skills/rust-in-action/examples/after.md +156 -0
  27. package/skills/rust-in-action/examples/before.md +56 -0
  28. package/skills/rust-in-action/references/practices-catalog.md +346 -0
  29. package/skills/rust-in-action/scripts/review.py +147 -0
  30. package/skills/skill-router/SKILL.md +16 -13
  31. package/skills/skill-router/references/skill-catalog.md +19 -1
@@ -0,0 +1,107 @@
1
+ # After: Programming with Rust
2
+
3
+ The same service rewritten with idiomatic Rust — proper ownership, Result-based error handling, borrowing over cloning, iterator adapters, and trait bounds.
4
+
5
+ ```rust
6
+ use std::collections::HashMap;
7
+ use std::fmt;
8
+ use std::sync::{Arc, Mutex};
9
+
10
+ // Custom error type — callers can match on variants (Ch 12)
11
+ #[derive(Debug)]
12
+ pub enum ConfigError {
13
+ Io(std::io::Error),
14
+ UserNotFound(String),
15
+ }
16
+
17
+ impl fmt::Display for ConfigError {
18
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19
+ match self {
20
+ ConfigError::Io(e) => write!(f, "I/O error: {e}"),
21
+ ConfigError::UserNotFound(name) => write!(f, "user not found: {name}"),
22
+ }
23
+ }
24
+ }
25
+
26
+ impl std::error::Error for ConfigError {}
27
+
28
+ impl From<std::io::Error> for ConfigError {
29
+ fn from(e: std::io::Error) -> Self {
30
+ ConfigError::Io(e)
31
+ }
32
+ }
33
+
34
+ // &str instead of String — works with both literals and String via deref coercion (Ch 4)
35
+ // Returns Result — caller decides how to handle failure (Ch 12)
36
+ fn load_config(path: &str) -> Result<String, ConfigError> {
37
+ let content = std::fs::read_to_string(path)?; // ? propagates I/O error (Ch 12)
38
+ Ok(content)
39
+ }
40
+
41
+ // Borrows the map — no clone, caller retains ownership (Ch 8, 10)
42
+ fn get_user<'a>(users: &'a HashMap<String, String>, name: &str) -> Result<&'a str, ConfigError> {
43
+ users
44
+ .get(name)
45
+ .map(|s| s.as_str())
46
+ .ok_or_else(|| ConfigError::UserNotFound(name.to_string()))
47
+ }
48
+
49
+ // Iterator adapters replace manual index loop (Ch 6)
50
+ fn active_names(users: &[(String, bool)]) -> Vec<&str> {
51
+ users
52
+ .iter()
53
+ .filter(|(_, active)| *active)
54
+ .map(|(name, _)| name.as_str())
55
+ .collect()
56
+ }
57
+
58
+ // Safe shared counter with Arc<Mutex<T>> (Ch 19)
59
+ fn make_counter() -> Arc<Mutex<u32>> {
60
+ Arc::new(Mutex::new(0))
61
+ }
62
+
63
+ fn increment(counter: &Arc<Mutex<u32>>) {
64
+ let mut count = counter.lock().expect("mutex poisoned");
65
+ *count += 1;
66
+ }
67
+
68
+ // Trait bound instead of concrete type — accepts anything Display (Ch 14, 17)
69
+ fn print_item(item: &impl fmt::Display) {
70
+ println!("{item}");
71
+ }
72
+
73
+ fn main() -> Result<(), ConfigError> {
74
+ let config = load_config("config.toml")?; // ? instead of unwrap (Ch 12)
75
+ println!("{config}");
76
+
77
+ let mut users = HashMap::new();
78
+ users.insert(String::from("alice"), String::from("admin"));
79
+
80
+ // Borrow users — still usable after the call (Ch 8)
81
+ let role = get_user(&users, "alice")?;
82
+ println!("{role}");
83
+ println!("{users:?}"); // still valid — was only borrowed
84
+
85
+ let items = vec![
86
+ (String::from("alice"), true),
87
+ (String::from("bob"), false),
88
+ ];
89
+ let names = active_names(&items);
90
+ println!("{names:?}");
91
+
92
+ let counter = make_counter();
93
+ increment(&counter);
94
+ println!("count: {}", counter.lock().unwrap());
95
+
96
+ Ok(())
97
+ }
98
+ ```
99
+
100
+ **Key improvements:**
101
+ - `ConfigError` gives callers structured, matchable errors (Ch 12)
102
+ - `?` replaces `.unwrap()` for clean error propagation (Ch 12)
103
+ - `&str` / `&HashMap` parameters borrow instead of consuming (Ch 4, 8, 10)
104
+ - Iterator adapters replace manual index loops (Ch 6)
105
+ - `Arc<Mutex<T>>` replaces `unsafe static mut` for safe shared state (Ch 19)
106
+ - `impl fmt::Display` trait bound instead of concrete `String` parameter (Ch 14, 17)
107
+ - `main()` returns `Result` so errors surface cleanly (Ch 12)
@@ -0,0 +1,59 @@
1
+ # Before: Programming with Rust
2
+
3
+ A user service with common Rust anti-patterns — ownership misuse, panic-prone error handling, unnecessary cloning, and poor trait design.
4
+
5
+ ```rust
6
+ use std::collections::HashMap;
7
+
8
+ // No custom error type — callers can't match on failures
9
+ fn load_config(path: String) -> String { // takes owned String unnecessarily
10
+ std::fs::read_to_string(path).unwrap() // panics on any I/O error
11
+ }
12
+
13
+ // Clones entire map just to read it
14
+ fn get_user(users: HashMap<String, String>, name: String) -> String {
15
+ let users_copy = users.clone(); // unnecessary clone of the whole map
16
+ match users_copy.get(&name) {
17
+ Some(user) => user.clone(),
18
+ None => String::from("unknown"), // silently returns fallback — hides missing users
19
+ }
20
+ }
21
+
22
+ // Accumulates with a manual loop instead of iterator adapters
23
+ fn active_names(users: Vec<(String, bool)>) -> Vec<String> {
24
+ let mut result = Vec::new();
25
+ for i in 0..users.len() {
26
+ if users[i].1 == true {
27
+ result.push(users[i].0.clone());
28
+ }
29
+ }
30
+ result
31
+ }
32
+
33
+ // Shared state with no synchronization
34
+ static mut COUNTER: u32 = 0;
35
+
36
+ fn increment() {
37
+ unsafe {
38
+ COUNTER += 1; // data race — undefined behavior in concurrent code
39
+ }
40
+ }
41
+
42
+ // Concrete type parameter instead of trait bound
43
+ fn print_user(user: String) {
44
+ println!("{}", user);
45
+ }
46
+
47
+ fn main() {
48
+ let config = load_config(String::from("config.toml"));
49
+ println!("{}", config);
50
+
51
+ let mut users = HashMap::new();
52
+ users.insert(String::from("alice"), String::from("admin"));
53
+
54
+ // Moves users into get_user — can't use it after
55
+ let name = get_user(users, String::from("alice"));
56
+ println!("{}", name);
57
+ // println!("{:?}", users); // would fail: users was moved
58
+ }
59
+ ```
@@ -0,0 +1,152 @@
1
+ # Programming with Rust — Chapter Reference
2
+
3
+ All 23 chapters from Donis Marshall's "Programming with Rust" with key topics and priority levels.
4
+
5
+ ## Ch 1: Introduction to Rust
6
+ **Key topics:** Functional programming, expression-oriented, pattern-oriented, safeness, ownership, lifetimes, fearless concurrency, zero-cost abstraction, Rust terminology, tools
7
+ **Priority:** Foundation
8
+
9
+ ## Ch 2: Getting Started
10
+ **Key topics:** Cargo, crates, library vs binary, `main` function, command-line arguments, comments, `rustup`
11
+ **Priority:** Foundation
12
+
13
+ ## Ch 3: Variables
14
+ **Key topics:** Immutability by default (`let` vs `let mut`), integer types, overflow behavior, floating point, boolean, char, pointers, references, operators
15
+ **Priority:** Important — immutability by default is a key Rust safety idiom
16
+
17
+ ## Ch 4: Strings
18
+ **Key topics:** `&str` (string slice, stack) vs `String` (heap-allocated, owned), deref coercion, `format!`, helpful string functions
19
+ **Idiom:** Accept `&str` in function parameters — `String` derefs to `&str` automatically
20
+ **Priority:** Important
21
+
22
+ ## Ch 5: Console
23
+ **Key topics:** `println!`, positional/variable/named arguments, padding/alignment, `Display` trait, `Debug` trait, `format!`, `write!`
24
+ **Priority:** Suggestion
25
+
26
+ ## Ch 6: Control Flow
27
+ **Key topics:** `if` as expression, `while`, `for`/`in` (iterator-based), `loop`, `break`/`continue`, loop labels, `Iterator` trait
28
+ **Idiom:** Use `for item in collection` over manual indexing; use iterator adapters over manual loops
29
+ **Priority:** Important
30
+
31
+ ## Ch 7: Collections
32
+ **Key topics:** Arrays (fixed-size, stack), slices, Vecs (heap, growable), multidimensional, `HashMap` (entry API, iteration, update)
33
+ **Priority:** Important
34
+
35
+ ## Ch 8: Ownership
36
+ **Key topics:** Stack vs heap, shallow vs deep copy, move semantics, borrow, copy semantics, `Clone` trait, `Copy` trait
37
+ **Critical rules:**
38
+ - Each value has exactly one owner
39
+ - When owner goes out of scope, value is dropped
40
+ - Move transfers ownership — old binding is invalid
41
+ - `Copy` types (primitives) are copied instead of moved
42
+ **Priority:** Critical
43
+
44
+ ## Ch 9: Lifetimes
45
+ **Key topics:** Lifetime annotation syntax (`'a`), lifetime elision rules, function headers, complex lifetimes, `'static`, structs/methods with lifetimes, subtyping, anonymous lifetimes, generics and lifetimes
46
+ **Idiom:** Rely on elision; annotate only when compiler cannot infer (multiple reference params with ambiguous output lifetime)
47
+ **Priority:** Critical
48
+
49
+ ## Ch 10: References
50
+ **Key topics:** Declaration, borrowing, dereferencing, comparing references, reference notation, mutability, limits to multiple borrowers
51
+ **Critical rules:**
52
+ - At any time: one `&mut T` OR any number of `&T` — never both
53
+ - References must not outlive the referent
54
+ **Priority:** Critical
55
+
56
+ ## Ch 11: Functions
57
+ **Key topics:** Function definition, parameters, return values, `const fn`, nested functions, function pointers, function aliases
58
+ **Priority:** Important
59
+
60
+ ## Ch 12: Error Handling
61
+ **Key topics:** `Result<T, E>`, `Option<T>`, panics, `panic!` macro, handling panics, `.unwrap()`, `.expect()`, `?` operator, `match` on Result/Option, `.map()`, rich errors, custom error types
62
+ **Critical rules:**
63
+ - Library code: always `Result`, never panic
64
+ - Use `?` for propagation, not `.unwrap()`
65
+ - Define custom error types implementing `std::error::Error`
66
+ - Implement `From<E>` for automatic `?` conversion
67
+ **Priority:** Critical
68
+
69
+ ## Ch 13: Structures
70
+ **Key topics:** Struct definition, alternate initialization, move semantics with structs, mutability, methods (`&self`, `&mut self`, `self`), associated functions (`new`), `impl` blocks, operator overloading, tuple structs, unit-like structs
71
+ **Priority:** Important
72
+
73
+ ## Ch 14: Generics
74
+ **Key topics:** Generic functions, trait bounds, `where` clause, generic structs, associated functions, generic enums, generic traits, explicit specialization
75
+ **Idiom:** Use `where` clause for complex bounds; prefer narrowest possible bounds
76
+ **Priority:** Important
77
+
78
+ ## Ch 15: Patterns
79
+ **Key topics:** `let` destructuring, wildcards (`_`), complex patterns, ownership in patterns, irrefutable patterns, ranges, multiple patterns (`|`), control flow patterns, struct destructuring, function parameter patterns, `match` expressions, match guards
80
+ **Idiom:** `match` is exhaustive — let the compiler enforce all cases; use `if let` for single-variant matches
81
+ **Priority:** Important
82
+
83
+ ## Ch 16: Closures
84
+ **Key topics:** Closure syntax, captured variables, closures as arguments/return values, `Fn` (immutable borrow), `FnMut` (mutable borrow), `FnOnce` (move/consume), `move` keyword, `impl` keyword for return types
85
+ **Idiom:** Use `move` closures when passing to threads to transfer ownership of captured values
86
+ **Priority:** Important
87
+
88
+ ## Ch 17: Traits
89
+ **Key topics:** Trait definition, default functions, marker traits (`Send`, `Sync`), associated functions, associated types, extension methods, fully qualified syntax, supertraits, static dispatch (`impl Trait`), dynamic dispatch (`dyn Trait`), enums and traits
90
+ **Critical rules:**
91
+ - Prefer `impl Trait` (static, zero-cost) over `dyn Trait` (runtime overhead via vtable)
92
+ - Use `dyn Trait` only when returning heterogeneous types or building plugin systems
93
+ **Priority:** Critical
94
+
95
+ ## Ch 18: Threads 1
96
+ **Key topics:** Synchronous vs asynchronous calls, `std::thread::spawn`, thread type, `Builder`, CSP (Communicating Sequential Process), async/sync/rendezvous channels (`mpsc`), `try_recv`, store example
97
+ **Idiom:** Prefer message passing (channels) over shared state when possible
98
+ **Priority:** Important
99
+
100
+ ## Ch 19: Threads 2
101
+ **Key topics:** `Mutex<T>`, nonscoped mutex, mutex poisoning, `RwLock<T>`, condition variables (`Condvar`), atomic operations (`AtomicUsize`, etc.), store/load, fetch-and-modify, compare-and-exchange
102
+ **Idiom:** Use `Arc<Mutex<T>>` for shared mutable state; `Arc<RwLock<T>>` for read-heavy workloads
103
+ **Priority:** Critical
104
+
105
+ ## Ch 20: Memory
106
+ **Key topics:** Stack vs heap allocation, static values, `Box<T>` (heap allocation), interior mutability pattern, `RefCell<T>` (runtime borrow checking, single-threaded), `OnceCell<T>` (lazy initialization)
107
+ **Idiom:** Stack-allocate by default; use `Box` only when size is unknown at compile time or for recursive types
108
+ **Priority:** Important
109
+
110
+ ## Ch 21: Macros
111
+ **Key topics:** Tokens, declarative macros (`macro_rules!`), repetition, multiple matchers, procedural macros (derive, attribute, function-like), `#[derive(...)]`
112
+ **Idiom:** Use `#[derive]` before writing manual `impl` blocks; write `macro_rules!` for repeated patterns
113
+ **Priority:** Suggestion
114
+
115
+ ## Ch 22: Interoperability
116
+ **Key topics:** FFI, `extern "C"`, `unsafe` blocks, `libc` crate, structs across FFI, `bindgen` (C → Rust), `cbindgen` (Rust → C)
117
+ **Priority:** Suggestion (only when needed)
118
+
119
+ ## Ch 23: Modules
120
+ **Key topics:** Module items, `pub` visibility, module files, `path` attribute, functions and modules, `crate`/`super`/`self` keywords, legacy module model
121
+ **Idiom:** Organize by domain, not by type; keep `pub` surface minimal; use `pub(crate)` for internal-only APIs
122
+ **Priority:** Important
123
+
124
+ ---
125
+
126
+ ## Priority Summary
127
+
128
+ **Critical (understand deeply before writing any Rust)**
129
+ - Ch 8: Ownership and move semantics
130
+ - Ch 9: Lifetimes and elision
131
+ - Ch 10: Borrowing rules (one `&mut` OR many `&`)
132
+ - Ch 12: Error handling with Result, ?, custom errors
133
+ - Ch 17: Trait dispatch (impl vs dyn)
134
+ - Ch 19: Thread safety with Mutex/RwLock/Arc
135
+
136
+ **Important (apply consistently)**
137
+ - Ch 3: Immutability by default
138
+ - Ch 4: `&str` vs `String`
139
+ - Ch 6: Iterator-based loops
140
+ - Ch 11: Function design
141
+ - Ch 13: Structs and impl blocks
142
+ - Ch 14: Generics and bounds
143
+ - Ch 15: Exhaustive pattern matching
144
+ - Ch 16: Closures and move semantics
145
+ - Ch 18: Channels for concurrency
146
+ - Ch 20: Stack vs heap, RefCell
147
+ - Ch 23: Module visibility
148
+
149
+ **Suggestion (apply when relevant)**
150
+ - Ch 5: Formatting and Display/Debug
151
+ - Ch 21: Macros and derive
152
+ - Ch 22: FFI/interop
@@ -0,0 +1,335 @@
1
+ # Programming with Rust — Practices Catalog
2
+
3
+ Deep before/after examples for the most critical Rust idioms from each chapter group.
4
+
5
+ ---
6
+
7
+ ## Ownership: Borrow Instead of Clone (Ch 8)
8
+
9
+ **Before:**
10
+ ```rust
11
+ fn print_names(names: Vec<String>) { // consumes the Vec
12
+ for name in names {
13
+ println!("{name}");
14
+ }
15
+ }
16
+ // names is gone after this call
17
+ ```
18
+ **After:**
19
+ ```rust
20
+ fn print_names(names: &[String]) { // borrows a slice — Vec<String> derefs to &[String]
21
+ for name in names {
22
+ println!("{name}");
23
+ }
24
+ }
25
+ // caller keeps ownership
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Ownership: Move Semantics (Ch 8)
31
+
32
+ **Before:**
33
+ ```rust
34
+ let s1 = String::from("hello");
35
+ let s2 = s1; // s1 is MOVED into s2
36
+ println!("{s1}"); // compile error: s1 was moved
37
+ ```
38
+ **After:**
39
+ ```rust
40
+ let s1 = String::from("hello");
41
+ let s2 = s1.clone(); // explicit deep copy — both valid
42
+ println!("{s1} {s2}"); // both valid
43
+
44
+ // Or: borrow instead of cloning
45
+ let s3 = &s1; // borrow — s1 still owns the data
46
+ println!("{s1} {s3}");
47
+ ```
48
+
49
+ ---
50
+
51
+ ## References: Borrow Rules (Ch 10)
52
+
53
+ ```rust
54
+ let mut data = vec![1, 2, 3];
55
+
56
+ // OK: multiple immutable borrows
57
+ let a = &data;
58
+ let b = &data;
59
+ println!("{a:?} {b:?}");
60
+
61
+ // OK: one mutable borrow (after immutable borrows end)
62
+ let c = &mut data;
63
+ c.push(4);
64
+
65
+ // COMPILE ERROR: can't have mutable + immutable borrow at same time
66
+ // let d = &data;
67
+ // let e = &mut data; // error
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Lifetimes: Elision vs Annotation (Ch 9)
73
+
74
+ **Elision works (no annotation needed):**
75
+ ```rust
76
+ fn first_word(s: &str) -> &str { // compiler infers output lifetime = input lifetime
77
+ s.split_whitespace().next().unwrap_or("")
78
+ }
79
+ ```
80
+
81
+ **Annotation required (multiple inputs, ambiguous output):**
82
+ ```rust
83
+ // Without annotation — compiler can't tell which input the output borrows from
84
+ fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str {
85
+ if s1.len() > s2.len() { s1 } else { s2 }
86
+ }
87
+ ```
88
+
89
+ **Struct holding a reference — must annotate:**
90
+ ```rust
91
+ struct Excerpt<'a> {
92
+ text: &'a str, // struct can't outlive the string it borrows
93
+ }
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Error Handling: Result + ? (Ch 12)
99
+
100
+ **Before:**
101
+ ```rust
102
+ fn read_username() -> String {
103
+ let f = std::fs::File::open("username.txt").unwrap();
104
+ let mut s = String::new();
105
+ std::io::Read::read_to_string(&mut std::io::BufReader::new(f), &mut s).unwrap();
106
+ s
107
+ }
108
+ ```
109
+ **After:**
110
+ ```rust
111
+ fn read_username() -> Result<String, std::io::Error> {
112
+ std::fs::read_to_string("username.txt") // ? propagates automatically
113
+ }
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Error Handling: Custom Error Types (Ch 12)
119
+
120
+ ```rust
121
+ use std::fmt;
122
+
123
+ #[derive(Debug)]
124
+ pub enum AppError {
125
+ Io(std::io::Error),
126
+ Parse(std::num::ParseIntError),
127
+ Custom(String),
128
+ }
129
+
130
+ impl fmt::Display for AppError {
131
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132
+ match self {
133
+ AppError::Io(e) => write!(f, "I/O: {e}"),
134
+ AppError::Parse(e) => write!(f, "parse: {e}"),
135
+ AppError::Custom(s) => write!(f, "{s}"),
136
+ }
137
+ }
138
+ }
139
+
140
+ impl std::error::Error for AppError {}
141
+
142
+ // Enables ? to convert std::io::Error → AppError automatically
143
+ impl From<std::io::Error> for AppError {
144
+ fn from(e: std::io::Error) -> Self { AppError::Io(e) }
145
+ }
146
+
147
+ impl From<std::num::ParseIntError> for AppError {
148
+ fn from(e: std::num::ParseIntError) -> Self { AppError::Parse(e) }
149
+ }
150
+
151
+ fn parse_port(s: &str) -> Result<u16, AppError> {
152
+ let port: i32 = s.parse()?; // ParseIntError → AppError via From
153
+ if port < 1 || port > 65535 {
154
+ return Err(AppError::Custom(format!("invalid port: {port}")));
155
+ }
156
+ Ok(port as u16)
157
+ }
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Traits: Static vs Dynamic Dispatch (Ch 17)
163
+
164
+ **Static dispatch — zero cost, preferred:**
165
+ ```rust
166
+ // Monomorphized at compile time — no runtime overhead
167
+ fn notify(item: &impl Summary) {
168
+ println!("Breaking news! {}", item.summarize());
169
+ }
170
+
171
+ // Equivalent with explicit generic:
172
+ fn notify<T: Summary>(item: &T) {
173
+ println!("Breaking news! {}", item.summarize());
174
+ }
175
+ ```
176
+
177
+ **Dynamic dispatch — use only for heterogeneous collections or plugins:**
178
+ ```rust
179
+ // Vtable lookup at runtime — small overhead, but enables mixed types
180
+ fn notify_all(items: &[Box<dyn Summary>]) {
181
+ for item in items {
182
+ println!("{}", item.summarize());
183
+ }
184
+ }
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Traits: Implementing Standard Traits (Ch 17)
190
+
191
+ ```rust
192
+ use std::fmt;
193
+
194
+ #[derive(Debug, Clone, PartialEq)] // derive common traits
195
+ struct Point {
196
+ x: f64,
197
+ y: f64,
198
+ }
199
+
200
+ // Display for user-facing output
201
+ impl fmt::Display for Point {
202
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203
+ write!(f, "({}, {})", self.x, self.y)
204
+ }
205
+ }
206
+
207
+ // From for ergonomic conversion
208
+ impl From<(f64, f64)> for Point {
209
+ fn from((x, y): (f64, f64)) -> Self {
210
+ Point { x, y }
211
+ }
212
+ }
213
+
214
+ let p: Point = (1.0, 2.0).into(); // uses From impl
215
+ println!("{p}"); // uses Display
216
+ println!("{p:?}"); // uses Debug
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Pattern Matching: Exhaustive match (Ch 15)
222
+
223
+ **Before:**
224
+ ```rust
225
+ let opt: Option<i32> = get_value();
226
+ match opt {
227
+ Some(x) => println!("{x}"),
228
+ _ => {} // silently ignores None — intent unclear
229
+ }
230
+ ```
231
+ **After:**
232
+ ```rust
233
+ // if let for single-variant match
234
+ if let Some(x) = get_value() {
235
+ println!("{x}");
236
+ }
237
+
238
+ // Exhaustive match when both branches matter
239
+ match get_value() {
240
+ Some(x) => println!("got {x}"),
241
+ None => println!("nothing"),
242
+ }
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Closures: move for Threads (Ch 16, 18)
248
+
249
+ **Before:**
250
+ ```rust
251
+ let name = String::from("Alice");
252
+ let handle = std::thread::spawn(|| {
253
+ println!("{name}"); // error: closure may outlive name
254
+ });
255
+ ```
256
+ **After:**
257
+ ```rust
258
+ let name = String::from("Alice");
259
+ let handle = std::thread::spawn(move || {
260
+ println!("{name}"); // name is moved into the closure — safe
261
+ });
262
+ handle.join().unwrap();
263
+ ```
264
+
265
+ ---
266
+
267
+ ## Concurrency: Arc<Mutex<T>> (Ch 19)
268
+
269
+ ```rust
270
+ use std::sync::{Arc, Mutex};
271
+ use std::thread;
272
+
273
+ fn main() {
274
+ let counter = Arc::new(Mutex::new(0u32));
275
+ let mut handles = vec![];
276
+
277
+ for _ in 0..10 {
278
+ let counter = Arc::clone(&counter); // clone the Arc, not the data
279
+ let handle = thread::spawn(move || {
280
+ let mut num = counter.lock().expect("mutex poisoned");
281
+ *num += 1;
282
+ });
283
+ handles.push(handle);
284
+ }
285
+
286
+ for handle in handles {
287
+ handle.join().unwrap();
288
+ }
289
+
290
+ println!("Result: {}", *counter.lock().unwrap()); // 10
291
+ }
292
+ ```
293
+
294
+ ---
295
+
296
+ ## Memory: RefCell for Interior Mutability (Ch 20)
297
+
298
+ Use `RefCell<T>` when you need mutability inside an otherwise immutable value (single-threaded only):
299
+
300
+ ```rust
301
+ use std::cell::RefCell;
302
+
303
+ struct Cache {
304
+ data: RefCell<Option<String>>, // interior mutability
305
+ }
306
+
307
+ impl Cache {
308
+ fn get(&self) -> String {
309
+ // borrow_mut even though &self is immutable
310
+ let mut data = self.data.borrow_mut();
311
+ if data.is_none() {
312
+ *data = Some(expensive_computation());
313
+ }
314
+ data.as_ref().unwrap().clone()
315
+ }
316
+ }
317
+ // For multi-threaded use, replace RefCell with Mutex
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Modules: Visibility (Ch 23)
323
+
324
+ ```rust
325
+ // lib.rs
326
+ pub mod api { // public module
327
+ pub struct Request { /* ... */ } // public type
328
+ pub(crate) fn validate() { } // crate-internal only
329
+ fn internal_helper() { } // private to module
330
+ }
331
+
332
+ mod storage { // private module — not part of public API
333
+ pub(super) fn save() { } // accessible to parent module only
334
+ }
335
+ ```