Files
rutster/LEARNING.md
adlee-was-taken f765fc2b27 docs: LEARNING.md + fuzz/ placeholder + README dev-loop (spec §7, §6.3)
LEARNING.md indexes ten concept-to-file pointers (the spec floor was
five) — the newtype pattern, exhaustive enum match, sans-IO, trait
extension seams, thiserror + hot-path match-and-continue, Arc<Mutex>
vs Arc<RwLock>, DashMap, str0m's single-mutation invariant, graceful
shutdown, include_str!. fuzz/README.md pre-paves the layout (no
hostile-bytes surface in slice 1; harnesses land at step 5 per the
out-of-scope table). README's new dev-loop section documents the
libopus FFI prerequisite and the manual e2e steps.
2026-06-28 13:06:37 -04:00

3.7 KiB

LEARNING.md — to learn concept X, read file Y

This index maps a Rust concept you might be learning to the file where slice 1 makes the concept concrete. Each entry is a worked example you can read in cargo doc --open plus the source file itself.

Concepts + pointers

  • Newtype pattern (type-safety via single-field wrappers)crates/rutster-call-model/src/lib.rsChannelId(Uuid). The newtype stops us from mixing up a ChannelId with some future SessionId at the type-system level. Compile-enforced where a comment could only ask.

  • enum for closed state sets + exhaustive matchcrates/rutster-call-model/src/lib.rsChannelState (New → Connecting → Connected → Closing → Closed). Exhaustiveness checking forces every match to consider each state; adding a state later surfaces every site that needs handling.

  • Sans-IO pattern (no I/O inside the library; input via method calls, output via return values)crates/rutster-media/src/loop_driver.rs — the str0m poll loop. Rtc::handle_input takes a network packet as a struct argument, not from a socket the library owns; poll_output returns Transmit packets the caller sends. Fully testable without a network — str0m integration tests use this property to drive faster than realtime.

  • Trait design for extension points (a futures-compatible seam)crates/rutster-media/src/pcm.rs — the AudioSource / AudioSink traits. Slice 1 wires an EchoAudioPipe between them; step 2 swaps that for a real WSS tap client without touching RtcSession. The traits describe what the splice point does, not how it's filled.

  • Error enums with thiserror + hot-path match-and-continuecrates/rutster-media/src/lib.rs (MediaError) and crates/rutster-media/src/opus_codec.rs (OpusDecoder::decode returns Option<PcmFrame>). Cold path: thiserror-derived enum + ?. Hot path: match-and-continue, never ?, never panic — "drop + observe, don't crash" (spec §3.8).

  • Arc<Mutex<T>> vs Arc<RwLock<T>> — when each is rightcrates/rutster/src/session_map.rs. The RtcSession lives behind Arc<Mutex<...>> because every access mutates it (str0m's &mut self contract) — RwLock's read-mode would be useless. Comment on the struct explains the trade-off.

  • DashMap for sharded concurrent mapscrates/rutster/src/session_map.rs. DashMap shards its inner map so two handlers operating on different ChannelIds don't contend; HashMap wrapped in a single Mutex would serialize every access.

  • str0m 0.21's single-mutation invariantcrates/rutster-media/src/loop_driver.rs. Mutate (handle_input / Writer::write) → drain poll_output to Output::Timeout → next mutate. Violating this leaves str0m in an inconsistent state.

  • tokio graceful shutdown via signal handlerscrates/rutster/src/main.rs (shutdown_signal). Ctrl-C / SIGTERM drops the AppState; the AppState drops the DashMap; the DashMap drops every RtcSession. No in-flight call preservation in slice 1.

  • include_str! for embedding static assetscrates/rutster/src/routes.rs (include_str!("../static/index.html")). The HTML test client is compiled into the binary at build time — no separate file to ship, no disk IO to serve it.

How to read

  1. cargo doc --open — every module has a //! doc comment; the doc tree is the high-level map.
  2. Pick a concept above; open the named file. The first occurrence of each non-obvious pattern has a // comment explaining why.
  3. Cross-ref back to the spec sections cited inline (spec §3.8, ADR-0002, etc.) for the architecture-level rationale.