{"id":51469357,"url":"https://github.com/utkarsh5026/rust-scratch","last_synced_at":"2026-07-06T15:01:16.266Z","repository":{"id":365806727,"uuid":"1272264806","full_name":"utkarsh5026/rust-scratch","owner":"utkarsh5026","description":"🦀📚 A learn-by-doing Rust workspace — pick a concept, get a ladder of 7-9 problems (easy → mastery), and implement each one yourself with staged hints, never handed the solution. Powered by a custom rust-practice coaching skill. 🚀","archived":false,"fork":false,"pushed_at":"2026-06-26T03:57:44.000Z","size":676,"stargazers_count":1,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-26T05:23:15.554Z","etag":null,"topics":["async-rust","claude-code","education","exercises","learn-by-doing","learning","lifetimes","ownership","practice","rust","rust-lang","systems-programming"],"latest_commit_sha":null,"homepage":"https://utkarsh5026.github.io/rust-scratch/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/utkarsh5026.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-17T12:51:00.000Z","updated_at":"2026-06-26T03:57:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/utkarsh5026/rust-scratch","commit_stats":null,"previous_names":["utkarsh5026/rust-scratch"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/utkarsh5026/rust-scratch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utkarsh5026%2Frust-scratch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utkarsh5026%2Frust-scratch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utkarsh5026%2Frust-scratch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utkarsh5026%2Frust-scratch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/utkarsh5026","download_url":"https://codeload.github.com/utkarsh5026/rust-scratch/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utkarsh5026%2Frust-scratch/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35195590,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-rust","claude-code","education","exercises","learn-by-doing","learning","lifetimes","ownership","practice","rust","rust-lang","systems-programming"],"created_at":"2026-07-06T15:01:15.604Z","updated_at":"2026-07-06T15:01:16.245Z","avatar_url":"https://github.com/utkarsh5026.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rust-scratch\n\nMy personal **learn-by-doing** workspace for mastering Rust. Not a product — a\npractice gym. I name a concept, get a ladder of problems, and implement each one\nmyself with coaching (never handed the answer), until I actually understand it.\n\nThe whole thing is built around the **`rust-practice` skill** + a structured\nmastery curriculum in [`ROADMAP.md`](./ROADMAP.md).\n\n## Where I'm at\n\n\u003c!-- Auto-rendered by .github/workflows/stats.yml on every push that changes progress.json.\n     Regenerate locally with: cargo run --bin stats -- --svg .github/assets/stats.svg --\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./.github/assets/stats.svg\" alt=\"Rust mastery dashboard — rank, XP, phase progress, achievements, streak\" width=\"540\"\u003e\n\u003c/p\u003e\n\n## The core loop\n\n1. Name a concept → `practice \u003cconcept\u003e` (or `/rust-practice \u003cconcept\u003e`)\n2. A ladder of **7-9 problems** (easy → mastery) is scaffolded into `src/bin/\u003cconcept\u003e.rs`\n3. Implement one rung at a time; run `cargo run --bin \u003cconcept\u003e` to check\n4. Get **staged hints** if stuck — the solution is revealed only if you ask\n5. Each ladder ends in a **build-it-from-scratch capstone**\n\nEvery solved rung earns **XP** and feeds a gamified dashboard (`cargo run --bin\nstats` or `/stats`): ranks 🥚→🦀→…→👑, achievements (Hint-Free, One-Shot,\nMiri-Clean, Capstone, Phase Clear), and a daily **streak**.\n\n```\npractice Rc and RefCell      # start a new ladder\ncargo run --bin rc_refcell   # run it — passes the solved rungs, stops at your next todo!\n```\n\n## Quick start\n\n```bash\n# run the scratch pad (quick throwaway code)\ncargo run\n\n# run a specific concept ladder\ncargo run --bin cow\n\n# start a fresh concept (in Claude Code)\n#   \"practice lifetimes\"   or   /rust-practice lifetimes\n```\n\n## How a concept file works\n\nOne file per concept. Each problem is a function you implement + a `check_N()`\nthat asserts it. `main` runs them in order, so it replays everything you've\nsolved and stops at the first unfinished rung (its `todo!` panics).\n\n```rust\nfn solve_it(...) -\u003e ... {\n    todo!(\"your turn\")          // \u003c- you fill this in\n}\n\nfn check_3() { /* asserts solve_it works */ }\n\nfn main() {\n    check_1();\n    check_2();\n    check_3();   // \u003c- run stops here until you implement rung 3\n    // check_4();\n}\n```\n\n## The curriculum\n\n[`ROADMAP.md`](./ROADMAP.md) is a 9-phase path from comfortable-with-basics to\nadvanced Rust engineer. Each item is a ladder to run:\n\n| Phase | Theme |\n|-------|-------|\n| 0 | Tooling, project structure \u0026 testing (features, property tests, fuzzing) |\n| 1 | Ownership, conversions \u0026 the type system (smart pointers, lifetimes, variance, HRTB) |\n| 2 | Traits \u0026 generics like a library author (object safety, GATs, const generics) |\n| 3 | API \u0026 error design (typestate, semver, strings, collections) |\n| 4 | Concurrency (atomics, memory ordering, lock-free, rayon) |\n| 5 | Async internals (`Future`, `Pin`, build an executor, tower) |\n| 6 | Unsafe \u0026 the machine (raw pointers, layout, Stacked Borrows, implement `Vec`) |\n| 7 | Performance \u0026 low-level craft |\n| 8 | Metaprogramming (declarative \u0026 proc macros) |\n| 9 | Specialization tracks (no_std/embedded · web · WASM · CLI) |\n| 10 | Capstones |\n\n~90 ladders · ~700 hands-on problems.\n\nSay **\"what's next\"** to pull the next unchecked item and start its ladder.\n\n## Completed concepts\n\n**Phase 0 — Tooling, project structure \u0026 testing**\n\n| Concept | File | Rungs |\n|---------|------|-------|\n| Modules \u0026 visibility | [`src/bin/modules.rs`](./src/bin/modules.rs) | 9 — module tree \u0026 paths → `pub` opens a door → field privacy + smart constructor → `use` vs `pub use` re-export → leaking a private type (E0603/E0616) → `pub(crate)`/`pub(super)`/`pub(in path)` → facade pattern → sealed trait via private module → `inventory` mini-library capstone |\n| Cargo features \u0026 `cfg` | [`src/bin/features_cfg.rs`](./src/bin/features_cfg.rs) | 9 — `cfg!()` macro → `#[cfg]` attribute (twin defs) → first feature flag → `cfg_attr` (serde idiom) → **additivity law** (collide vs accumulate) → missing-symbol trap (gate the call site too) → optional dep `dep:rand` → feature graphs (`default`/`full`/`--no-default-features`) → mini config/output module capstone |\n| 🔥 Testing | [`src/bin/testing.rs`](./src/bin/testing.rs) + [`practice/testing_lab/`](./practice/testing_lab/) | 9 — `#[cfg(test)] mod tests`/`assert_eq!` → assertion toolbox + custom messages → `Result`-returning tests \u0026 `?` → `#[should_panic(expected=…)]` → execution control (`#[ignore]`/filter/`--nocapture`/parallelism) → assertion footguns (loose should_panic, float eq, private reach) → integration tests (`tests/`, `common/mod.rs`, E0603 boundary) → doctests (`?`/hidden `#`/`should_panic`/`compile_fail`) → capstone `Ledger` tested every way |\n\n**Phase 1 — Ownership, conversions \u0026 the type system**\n\n| Concept | File | Rungs |\n|---------|------|-------|\n| `Cow` (Clone-on-Write) | [`src/bin/cow.rs`](./src/bin/cow.rs) | 9 — basics → serde zero-copy → reimplement from scratch |\n| `Box` \u0026 the heap | [`src/bin/box_heap.rs`](./src/bin/box_heap.rs) | 9 — recursive types → `dyn Trait`/`Box::leak` → hand-rolled linked list |\n| `Rc` / `Arc` | [`src/bin/rc_arc.rs`](./src/bin/rc_arc.rs) | 9 — shared ownership → cycles \u0026 `Weak` → `Arc\u003cMutex\u003e` → hand-rolled `MyRc` |\n| `Cell` / `RefCell` | [`src/bin/cell_refcell.rs`](./src/bin/cell_refcell.rs) | 9 — interior mutability → borrow panics → hand-rolled `MyRefCell` |\n| Conversion traits | [`src/bin/conversions.rs`](./src/bin/conversions.rs) | 9 — `From`/`Into` → `TryFrom` → `AsRef` → mini `serde_json::Value` |\n| Lifetimes in depth | [`src/bin/lifetimes_depth.rs`](./src/bin/lifetimes_depth.rs) | 9 — elision → structs → outlives bounds → hand-rolled `StrSplit` |\n| `Borrow` / `ToOwned` | [`src/bin/borrow_toowned.rs`](./src/bin/borrow_toowned.rs) | 9 — `HashMap::get(\u0026str)` → contracts → hand-rolled `MyCow` |\n| `Drop` \u0026 ordering | [`src/bin/drop_ordering.rs`](./src/bin/drop_ordering.rs) | 9 — LIFO/field order → drop flags → rollback-on-drop `Transaction` |\n| `Rc\u003cRefCell\u003cT\u003e\u003e` patterns | [`src/bin/rc_refcell.rs`](./src/bin/rc_refcell.rs) | 10 — shared cell → cycle leak + `Weak` → doubly-linked list w/ iterative Drop |\n| HRTB — `for\u003c'a\u003e` | [`src/bin/hrtb.rs`](./src/bin/hrtb.rs) | 9 — implicit `for\u003c'a\u003e` → `DecodeOwned` → parser-combinator capstone |\n\n**Phase 2 — Traits \u0026 generics like a library author**\n\n| Concept | File | Rungs |\n|---------|------|-------|\n| Generic bounds \u0026 `where` clauses | [`src/bin/generic_bounds.rs`](./src/bin/generic_bounds.rs) | 9 — bounds → `?Sized` → blanket impls → `IterExt` extension trait |\n| Associated types vs generic params | [`src/bin/assoc_vs_generic.rs`](./src/bin/assoc_vs_generic.rs) | 9 — one-impl-per-type vs many → `dyn` assoc pinning → `MyIterator` + `Map` |\n| Blanket impls \u0026 coherence | [`src/bin/blanket_coherence.rs`](./src/bin/blanket_coherence.rs) | 9 — `From`→`Into` → orphan rule → sealed extension trait |\n| Static vs dynamic dispatch | [`src/bin/dispatch.rs`](./src/bin/dispatch.rs) | 9 — monomorphization vs vtable → object safety → static/dynamic/enum pipeline |\n| Closures \u0026 `Fn`/`FnMut`/`FnOnce` | [`src/bin/closures.rs`](./src/bin/closures.rs) | 9 — capture modes → `Fn ⊂ FnMut ⊂ FnOnce` → desugar by hand → `impl Fn` vs `Box\u003cdyn Fn\u003e` → fn-pointer coercion → `Box\u003cdyn FnMut\u003e` event dispatcher |\n| `impl Trait` \u0026 RPIT | [`src/bin/impl_trait.rs`](./src/bin/impl_trait.rs) | 9 — APIT (caller picks) vs RPIT (callee picks one hidden type) → turbofish footgun → return closures/chains → one-type rule (Box/Vec/`Either`) → 2024 lifetime auto-capture + `use\u003c\u003e` → `async fn` ≡ `-\u003e impl Future` → RPITIT \u0026 async-fn-in-trait (not dyn-safe) → combinator toolkit |\n| Marker \u0026 auto traits | [`src/bin/marker_auto_traits.rs`](./src/bin/marker_auto_traits.rs) | 9 — marker permissions → `Copy`/`Sized`/`?Sized` → structural `Send`/`Sync` → opt-out/opt-in with `PhantomData` and `unsafe impl` → sealed typestate capstone |\n\n**Phase 3 — API \u0026 error design**\n\n| Concept | File | Rungs |\n|---------|------|-------|\n| Error handling architecture | [`src/bin/error_arch.rs`](./src/bin/error_arch.rs) | 9 — `Box\u003cdyn Error\u003e` → `thiserror`/`anyhow` → mini-anyhow |\n| Custom error types | [`src/bin/custom_errors.rs`](./src/bin/custom_errors.rs) | 9 — Display+Error by hand → source chains → `Report` reporter |\n| Newtype \u0026 zero-cost wrappers | [`src/bin/newtype.rs`](./src/bin/newtype.rs) | 9 — distinct identity → `repr(transparent)` → phantom-typed `Id\u003cT\u003e` |\n| Builder pattern | [`src/bin/builder.rs`](./src/bin/builder.rs) | 8 — consuming/`\u0026mut` builders → typestate builder → `ServerConfig` |\n| The typestate pattern | [`src/bin/typestate.rs`](./src/bin/typestate.rs) | 9 — ZST markers → sealed states → TCP-like protocol |\n| API evolution \u0026 semver | [`src/bin/semver.rs`](./src/bin/semver.rs) | 9 — what breaks → `#[non_exhaustive]` → sealed traits → `ApiChange→Bump` engine |\n| Collections deep-dive | [`src/bin/collections.rs`](./src/bin/collections.rs) | 9 — `Entry`/`Borrow` lookup → custom `Hash`/`Eq` → open-addressing `MyHashMap` |\n| Strings \u0026 text | [`src/bin/strings_text.rs`](./src/bin/strings_text.rs) | 9 — `str`/`String` \u0026 UTF-8 invariant → char-boundary slicing → `OsStr`/`Path`/`CStr` → `from_utf8` validation → hand-rolled UTF-8 decoder |\n\n**Phase 4 — Concurrency**\n\n| Concept | File | Rungs |\n|---------|------|-------|\n| Threads \u0026 scoped threads | [`src/bin/threads.rs`](./src/bin/threads.rs) | 9 — `spawn`/`join` → `thread::scope` → `parallel_map` (rayon-lite) |\n| `Send` \u0026 `Sync` deeply | [`src/bin/send_sync.rs`](./src/bin/send_sync.rs) | 9 — auto-derivation → the four quadrants → hand-rolled `SpinLock` |\n| `Mutex` / `RwLock` | [`src/bin/mutex_rwlock.rs`](./src/bin/mutex_rwlock.rs) | 9 — guard RAII → `Arc\u003cMutex\u003e` counter → `RwLock` readers-xor-writer → poisoning \u0026 recovery → non-reentrancy → ABBA deadlock + lock ordering → `Condvar` queue → concurrent `Bank` |\n| Channels | [`src/bin/channels.rs`](./src/bin/channels.rs) | 9 — `mpsc` send/recv → multi-producer `tx.clone()` → receiver-as-iterator (drop the sender) → `sync_channel` bounded/rendezvous backpressure → the hang + `RecvError`/`SendError` → `try_recv` Empty vs Disconnected → worker pool (`Arc\u003cMutex\u003cReceiver\u003e\u003e`) → crossbeam mpmc + `select!` → hand-rolled `Channel\u003cT\u003e` (`Mutex`+`Condvar`) |\n| Data parallelism with `rayon` | [`src/bin/rayon_parallel.rs`](./src/bin/rayon_parallel.rs) | 9 — `par_iter().sum()` → `map`/`filter`/`collect` (order preserved) → `reduce`/`fold` (identity closure, fold-then-reduce) → `rayon::join` fork-join primitive → break-even: when parallel LOSES vs WINS → non-associative reduce = silent non-determinism → shared-state wall (`for_each` push won't compile; `collect` vs `Mutex`) → `par_sort` + `par_bridge` → capstone: hand-rolled `parallel_map` + parallel quicksort (`split_at_mut` + `join`) |\n| Shared state vs message passing | [`src/bin/concurrency_models.rs`](./src/bin/concurrency_models.rs) | 9 — same counter via `Arc\u003cMutex\u003e` and mpsc aggregator → ownership transfer = no lock (Mutex guards the QUEUE, not the DATA) → pipeline of stages (EOF cascades as senders drop) → fan-out/fan-in: shared `VecDeque` vs mpsc queue (channel gives blocking + EOF free) → lock held too long (87ms vs 3ms; fat critical section serializes N threads to one) → message-passing footguns (stray sender hang, `RecvError`, `sync_channel` full, the `Arc\u003cMutex\u003e`-through-channel aliasing trap) → the actor (one owner of a HashMap, command + one-shot reply, no lock) → hybrid (writes via actor, lock-light reads from a published `Arc\u003cRwLock\u003cArc\u003cHashMap\u003e\u003e\u003e` snapshot) → capstone: one `KvStore: Send+Sync` trait, two impls (`Arc\u003cRwLock\u003cHashMap\u003e\u003e` vs actor), same 8-thread storm passes both — actor serializes at the queue, lock at the critical section |\n\n_(early standalone demos, not ladders: `src/bin/lifetimes.rs`, `src/bin/traits.rs`)_\n\n## Layout\n\n```\nrust-scratch/\n├── README.md       ← you are here\n├── ROADMAP.md      ← the mastery curriculum\n├── CLAUDE.md       ← how Claude Code should drive this project\n├── Cargo.toml\n├── .claude/\n│   ├── skills/rust-practice/   ← the practice-ladder coach\n│   └── commands/               ← /experiment, /run, /explain, /list\n└── src/\n    ├── main.rs                 ← scratch pad (cargo run)\n    └── bin/                    ← one file per concept ladder\n```\n\n## Slash commands\n\n| Command | Does |\n|---------|------|\n| `/rust-practice \u003cconcept\u003e` | start a coached practice ladder |\n| `/stats` | show the gamified dashboard — rank, XP, phases, badges, streak |\n| `/list` | show ladders \u0026 per-concept progress |\n| `/run \u003cname\u003e` | run an experiment and explain its output |\n| `/explain \u003cname\u003e` | tutor-mode walkthrough of an existing file |\n| `/experiment \u003cconcept\u003e` | scaffold a one-off demo (not a ladder) |\n\n## Preinstalled dependencies\n\nSo ladders never need setup: `tokio`, `futures`, `async-trait`, `anyhow`,\n`thiserror`, `serde` + `serde_json`, `reqwest`, `rand`, `tracing`. Add more in\n`Cargo.toml` as a concept needs them.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Futkarsh5026%2Frust-scratch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Futkarsh5026%2Frust-scratch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Futkarsh5026%2Frust-scratch/lists"}