Rust learning: lessons, notes, and exercise crates

This commit is contained in:
2026-09-06 23:59:08 +07:00
commit 6ddf41aa81
119 changed files with 10873 additions and 0 deletions
+136
View File
@@ -0,0 +1,136 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Rust Book coverage map — what is owned, what is missing</title>
<link rel="stylesheet" href="../assets/style.css" />
</head>
<body>
<h1>Coverage map</h1>
<p class="subtitle">Every chapter of The Rust Programming Language against this workspace · updated after lesson 0009</p>
<div class="callout">
The chapter list is taken verbatim from the book's
<a href="https://github.com/rust-lang/book/blob/main/src/SUMMARY.md">table of contents</a>, not from memory.
<strong>Read</strong> means you covered it in your two months. <strong>Produced</strong> means code you wrote in this
workspace uses it correctly — that is the only column that counts for the
<a href="../MISSION.md">mission</a>.
</div>
<h2>The map</h2>
<table>
<tr><th>Ch</th><th>Topic</th><th>State</th><th>Evidence / gap</th></tr>
<tr><td>1–2</td><td>Getting started, guessing game</td><td>Produced</td>
<td><code>hello_cargo/</code>, <code>guessing_game/</code></td></tr>
<tr><td>3</td><td>Variables, types, functions, control flow</td><td>Produced</td>
<td><code>variables/</code>, <code>function/</code>, <code>control_flow/</code>; 0001 diagnostic solid</td></tr>
<tr><td>4</td><td>Ownership, borrowing, slices</td><td>Produced</td>
<td><code>&amp;self</code> methods and <code>&amp;[Task]</code> accessor in <code>tasks/</code>. Watch for: you have never hit
a borrow-checker fight in your own multi-owner code, because nothing has needed two owners yet.</td></tr>
<tr><td>5</td><td>Structs and methods</td><td>Produced</td><td>0003 / 0004, <code>tasks/src/task.rs</code></td></tr>
<tr><td>6</td><td>Enums and <code>match</code></td><td>Produced</td>
<td><code>Status</code>, <code>Priority</code>, <code>Command</code>, and now <code>TaskError</code> (0006)</td></tr>
<tr><td>7</td><td>Packages, crates, modules</td><td>Produced</td>
<td><code>tasks/</code> is a lib + bin package with four modules</td></tr>
<tr><td>8</td><td>Collections: <code>Vec</code>, <code>String</code>, <code>HashMap</code></td><td>Produced</td>
<td>0008 drill, in <code>tasks/</code>: <code>HashMap&lt;Priority, usize&gt;</code> built with the <code>entry</code>/<code>or_insert</code>
counting idiom, <code>get().copied().unwrap_or(0)</code>, <code>Eq + Hash + Copy</code> derives on a key type, and a
<code>String</code> built by <code>collect</code>. Not done: <code>BTreeMap</code>, <code>HashSet</code>, string slicing by byte index.</td></tr>
<tr><td>9</td><td>Error handling: <code>panic!</code>, <code>Result</code>, <code>?</code></td><td>Produced</td>
<td>0005 + 0006: <code>?</code>, <code>ok_or</code>, own error enum, stderr + exit 1</td></tr>
<tr><td>10.1</td><td>Generic data types</td><td>Produced</td>
<td>0008 drill: <code>fn tally&lt;T, K, F&gt;(items: &amp;[T], key: F) -&gt; HashMap&lt;K, usize&gt;</code> in <code>tasks/src/stats.rs</code>,
with a <code>where</code> clause bounding <code>K: Eq + Hash</code> and <code>F: Fn(&amp;T) -&gt; K</code> — written from the
signature up, called at three different <code>T</code>/<code>K</code> pairs, one of them a non-<code>Copy</code> key.
Not done: generic <em>structs</em> and generic <code>impl</code> blocks.</td></tr>
<tr><td>10.2</td><td>Traits</td><td>Produced</td>
<td><code>Display for Task</code> (0005), <code>Display</code> + <code>Error</code> + <code>From</code> for <code>TaskError</code> (0006),
<code>FromStr for Task</code> with an associated <code>type Err</code> and a hand-written <code>PartialEq</code> (0007)</td></tr>
<tr><td>10.3</td><td>Lifetimes</td><td class="gap">Gap — untouched</td>
<td>Zero exposure in this workspace. You have dodged it by owning everything (<code>String</code>, not <code>&amp;'a str</code>).
Needed to read other people's code and to review a PR; not needed to ship your CLI.</td></tr>
<tr><td>11</td><td>Writing automated tests</td><td class="gap">Taught — drill pending</td>
<td>0009: <code>#[test]</code>, <code>#[cfg(test)] mod tests</code> with <code>use super::*</code>, the three assertion macros
and their failure output, <code>#[should_panic(expected)]</code> vs a <code>-&gt; Result&lt;(), E&gt;</code> test, unit vs
integration access (<code>E0603</code>/<code>E0616</code>), <code>tests/common/mod.rs</code>, the runner flags, and why
<code>src/main.rs</code> is untestable — <code>run</code> moves to the library and writes to <code>&amp;mut impl Write</code>.
Graded by six planted mutants, not by a test count.</td></tr>
<tr><td>12</td><td>I/O project: args, files, stderr, env</td><td>Produced</td>
<td>0007: <code>fs::read_to_string</code>/<code>fs::write</code>, <code>io::Error</code> + <code>ErrorKind::NotFound</code> match guard,
<code>env::var</code> with a default, on top of <code>env::args</code> and stderr + exit 1 from 0005. Not done: <code>BufReader</code>,
file locking, serde — none needed at this size.</td></tr>
<tr><td>13</td><td>Closures and iterators</td><td>Produced</td>
<td>0008 drill: <code>filter</code>/<code>map</code>/<code>collect</code> chains, <code>find</code> vs <code>position</code>,
<code>Vec::retain</code>, <code>lines()</code>, <code>collect::&lt;Result&lt;Vec&lt;_&gt;, E&gt;&gt;()</code> short-circuiting, and a
function that <em>takes</em> a closure (<code>F: Fn</code>). Not done: <code>fold</code>, <code>zip</code>,
<code>impl Iterator</code> for your own type.</td></tr>
<tr><td>14</td><td>Cargo, crates.io, workspaces</td><td>Skip for now</td>
<td>Learn <code>cargo add</code> and features when a dependency is actually needed (serde, axum).</td></tr>
<tr><td>15</td><td>Smart pointers: <code>Box</code>, <code>Rc</code>, <code>RefCell</code>, <code>Deref</code>, <code>Drop</code></td><td>Partial</td>
<td><code>Box&lt;dyn Error&gt;</code> met in 0005/0006. <code>Rc</code>/<code>RefCell</code> untouched — reach for them only when a real
shared-ownership problem appears, not before.</td></tr>
<tr><td>16</td><td>Concurrency: threads, channels, <code>Send</code>/<code>Sync</code></td><td class="gap">Gap</td>
<td>Untouched apart from the <code>Send + Sync</code> bound your 0006 test asserts. Prerequisite for understanding
why an axum handler must be <code>Send</code>.</td></tr>
<tr><td>17</td><td>Async: futures, <code>async</code>/<code>await</code>, streams</td><td class="gap">Gap — by design</td>
<td>Required for axum/tokio, deliberately last. The unused <code>trpl</code> dependency in <code>get-dependecies/</code> is
the abandoned first attempt. Do it after 8, 11, 13.</td></tr>
<tr><td>18</td><td>Trait objects, OOP patterns</td><td>Partial</td>
<td><code>dyn Error</code> is the same mechanism as 18.2. The state-machine pattern (18.3) is optional reading.</td></tr>
<tr><td>19</td><td>Patterns and matching</td><td>Partial</td>
<td><code>match</code> ✓, <code>if let</code> ✓ (0005 drill). Guards (<code>Some(x) if x &gt; 5</code>), <code>@</code> bindings,
<code>let ... else</code>, and <code>matches!</code> — one page of reading, high value per minute.</td></tr>
<tr><td>20</td><td>Unsafe, advanced traits, macros</td><td>Skip</td>
<td>Associated types and generic-parameter defaults matter eventually (serde uses them). Not now.</td></tr>
<tr><td>21</td><td>Final project: multithreaded web server</td><td>Not started</td>
<td>The natural capstone before axum — it is a backend service with no framework.</td></tr>
</table>
<h2>The order that follows from this</h2>
<p>After the 0009 drill, one gap in the book's core is left, and it is the mildest one:</p>
<ol>
<li><strong>Lifetimes</strong> (ch 10.3) — as reading practice, not as a build. You have written two without
noticing: <code>titles_with</code> returns <code>Vec&lt;&amp;str&gt;</code> borrowed from <code>&amp;self</code>, and
<code>Status::label</code> returns <code>&amp;str</code> the same way. Elision filled both annotations in. Reading
other people's signatures needs the explicit form.</li>
<li><strong>Patterns</strong> (ch 19) — one page: match guards, <code>@</code> bindings, <code>matches!</code>,
<code>let … else</code>. Your suite already uses <code>matches!</code>; the rest is high value per minute.</li>
</ol>
<p>Then serde → axum → async, where the traits from 0005–0008 and the testing from 0009 stop being an exercise
and start being the whole API surface: an axum handler is a function a test can call. Chapter 21's web server is
the natural capstone before a framework.</p>
<footer>
<p><strong>Primary source:</strong> <a href="https://doc.rust-lang.org/stable/book/">The Rust Programming Language</a> ·
chapter list from <a href="https://github.com/rust-lang/book/blob/main/src/SUMMARY.md">SUMMARY.md</a>.</p>
<p>Reference: <a href="rust-syntax.html">Rust syntax reference</a> ·
Lessons: <a href="../lessons/0006-your-own-error-type.html">0006</a> ·
<a href="../lessons/0007-files-and-fromstr.html">0007</a> ·
<a href="../lessons/0008-iterators-and-hashmap.html">0008</a> ·
<a href="../lessons/0009-writing-your-own-tests.html">0009</a></p>
<p>Disagree with a "Produced" or a "Gap"? Say so — this table decides what gets taught next, so it is worth arguing about.</p>
</footer>
</body>
</html>