#Rust
16 posts
Rust in Practice #7 Release Optimization and Cross-Compilation: Small, Fast Binaries That Run Anywhere
The first half of shipping. Tightening [profile.release] (lto, codegen-units, strip) and what each option trades away, why panic = "abort" should not be flipped casually, how binary size shrinks, and cross-compilation with rustup target — especially the musl static-link build that removes the glibc dependency and runs on old servers, plus the cross tool that detours linker problems through Docker.
Rust in Practice #6 Testing: From Parser Unit Tests to CLI Integration Tests
Wrapping loglens in a safety net. #[cfg(test)] unit tests living next to the code (the parser's normal, boundary, and failure cases), integration tests in the tests/ directory, CLI tests that run the built binary and verify output and exit codes with assert_cmd and predicates, temporary log files via tempfile, and what it means that cargo test runs tests in parallel.
Rust in Practice #5 Parallelism with rayon: Map-Reduce Without Data Races
Spreading the aggregation across cores. When parallelism pays off (CPU-bound work) and why the strategy switches from streaming to whole-file reads, per-thread partial aggregates with rayon's par_lines plus fold and reduce, why sharing one HashMap behind a Mutex gets slower (lock contention), and the moment the compiler catches a shared-mutable-state mistake.
Rust in Practice #4 Iterators at Work: Aggregation, Top-N, and the Release Build Difference
Stacking analysis on the parser: an aggregation structure that counts failures while streaming successes, status code distribution via HashMap entry, top-N by sorting, the completion of the stats and top commands, and measuring debug vs release with Instant — why the gap runs to dozens of times, and why release is not the default.
Rust in Practice #3 File IO and Parsing: Read with BufReader, Turn a Log Line into a Struct
Two fundamentals for handling large files: choosing between read_to_string (whole file in memory) and BufReader streaming, and how buffering relates to system calls. Then the parser that turns an access-log line into a LogEntry struct — quote handling, status code conversion, Part 2's ParseError in action — and the serde extension that accepts JSON Lines logs.
Rust in Practice #2 Error Design: anyhow and thiserror, Engineering How It Dies
In a CLI tool, error messages are part of the user interface. The division of labor between anyhow — the default for the application layer, with main returning anyhow::Result and context stacking up the story — and thiserror, which builds concrete error types callers can branch on. The criterion for choosing between them, plus exit codes: designing every error path in loglens.
Rust in Practice #1 Project Design and clap: Structuring a Subcommand CLI
An eight-part practice course that turns the grammar from the basics course into a real tool. We build loglens, an access-log analysis CLI. Why CLI tools are Rust's signature stage (single binary, startup speed), declaring subcommands (stats, top, errors) as one enum with clap's derive style, the auto-generated --help, and the design map for all eight parts.
Rust Basics #9 Lifetimes and Modules: When Lifetime Annotations Are Needed, Finishing with Crates
The final part of the basics course. How Part 4's dangling-reference blocking actually worked, explained through lifetimes: the moment missing lifetime specifier appears, what the annotation really means (declaring a relationship, not extending a life), and why it is usually elided. Then the module system with mod and pub, using external crates from crates.io, and the learning path after this course.
Rust Basics #8 Traits and Generics: Shared Behavior in a Language Without Inheritance
The part that settles the IOUs. Traits as definitions of shared behavior with default implementations, generics with trait bounds, the standard traits derive generates for you (Debug, Clone, Copy, PartialEq), monomorphization — why generics compile down to zero runtime cost — and the dynamic dispatch behind the dyn in Box<dyn Error>.
Rust Basics #7 Collections and Iterators: Vec, String, HashMap, and Chains Instead of for
The three collections that make up the body of practical code. Vec and why get is used instead of indexing, why String cannot be indexed at all (UTF-8 and the difference between bytes and characters), HashMap and the entry API, and the iterator style — map, filter, collect chains with lazy evaluation — that replaces for loops.
Rust Basics #6 Error Handling: Result, the ? Operator, and the Boundary Between panic and unwrap
Error handling in a language with no exceptions. Result, which puts the possibility of failure into the return type; the ? operator that collapses nested match blocks into one character and propagates errors; the practical form where main returns a Result; and the judgment calls for when unwrap, expect, and panic are acceptable and when they are not.
Rust Basics #5 Structs and Enums: match, Option, and Designing Without null
The two axes of structuring data: structs and enums. Attaching methods with impl blocks, the expressiveness of Rust enums whose variants carry different data, match with compiler-enforced exhaustiveness, and Option — the type that expresses "there may be no value" instead of null. The tools that form the skeleton of Rust code.