Rust
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Ownership and Borrowing
-
Section 4: Structuring Data
-
Section 5: Collections and Error Handling
-
Section 6: Traits and Generics
-
Section 7: Concurrency
-
Section 8: Building for the Web
-
Section 9: Memory and Performance
-
Section 10: More Standard Library and Ecosystem
-
Section 11: Advanced Rust
-
Section 12: Rust for Systems and WebAssembly
-
Section 13: Tooling and Best Practices
-
Section 14: Data Structures and Algorithms in Rust
-
Section 15: Practical Projects
-
Section 16: Interview Practice
-
Section 17: std::collections In Depth
-
Section 18: std::io and std::fs In Depth
-
Section 19: std::net
-
Section 20: std::option and std::result In Depth
-
Section 21: std::iter In Depth
-
Section 22: std::sync In Depth
-
Section 23: std::string and std::str
-
Section 24: Cargo and Crates.io Ecosystem
-
Section 25: Popular Crates Ecosystem
-
Section 26: Rust Memory Model Deep Dive
-
Section 27: More Practice Exercises
-
Section 28: More Interview Practice
-
Section 29: Async Rust Deep Dive
-
Section 30: Tokio Ecosystem In Depth
-
Section 31: Error Handling Ecosystem Deep Dive
-
Section 32: Serde In Depth
-
Section 33: Web Development with Rust Deep Dive
-
Section 34: Database Access Ecosystem
-
Section 35: Rust for Embedded Systems Deep Dive
-
Section 36: Rust Macros In Depth
-
Section 37: Advanced Trait System
-
Section 38: Unsafe Rust In Depth
-
Section 39: Rust CLI Development
-
Section 40: Testing Ecosystem Deep Dive
-
Section 41: WebAssembly Deep Dive
-
Section 42: Rust Design Patterns
-
Section 43: More Data Structures in Rust
-
Section 44: Final Practice Projects
-
Section 45: Rust Performance Optimization
-
Section 46: Rust Ecosystem Tooling
-
Section 47: More Interview and Review
56: Unsafe Rust: When and Why
A few years ago, I was tasked with integrating a legacy C library for high-speed image processing into a new Rust-based tool. The library returned a raw pointer to a buffer of pixels, and I spent an entire afternoon trying to wrap that pointer in a way that would make the borrow checker happy. I kept trying to "trick" the compiler into treating the raw pointer as a safe slice, but every time I did, I hit a wall of lifetime errors that felt impossible to solve. I remember thinking, "Is Rust actually preventing me from doing my job?"
The epiphany came when I stopped treating unsafe as a "failure" to write idiomatic Rust and started treating it as a tool for boundary management. Rust isn't trying to stop you from performing low-level operations; it's just demanding that you draw a clear line around the code that the compiler can't possibly verify. Once I wrapped the raw pointer access in a small, carefully audited unsafe block and exposed a safe API to the rest of my app, the friction vanished.
The Superpowers of the Unsafe Block
When you wrap code in an unsafe { ... } block, you aren't turning off the borrow checker. That's a common misconception. The borrow checker is still running, and the usual rules of ownership still apply. What you're actually doing is granting yourself a set of "superpowers" that the compiler normally forbids because it cannot mathematically prove they are safe.
Specifically, unsafe allows you to:
- Dereference raw pointers (
*const Tand*mut T). - Call other unsafe functions (including FFI calls to C or C++).
- Implement unsafe traits.
- Access or modify mutable static variables.
In my image processing case, dereferencing that raw pointer from the C library was the "unsafe" act. The compiler had no way of knowing if the C library had already freed that memory or if the pointer was null. By using unsafe, I was telling the compiler: "I have read the C documentation, I know this pointer is valid for the next ten milliseconds, and I take full responsibility if this crashes."
Maintaining the Safety Invariant
The goal of a professional Rust engineer isn't to avoid unsafe entirely—that's impossible if you're building low-level primitives or interfacing with hardware. The goal is to encapsulate it. You want to build a "safe abstraction." This means you write a small amount of unsafe code, but you wrap it in a safe function that ensures the caller can't possibly cause a segmentation fault.
// A simplified example of an unsafe abstraction struct MyBuffer { ptr: *mut u8, len: usize, } impl MyBuffer { // The unsafe part is hidden inside this safe method pub fn get(&self, index: usize) -> Option<&u8> { if index >= self.len { return None; } // SAFETY: We just checked that index is within bounds, // so dereferencing the pointer is safe here. unsafe { Some(&*self.ptr.add(index)) } } }Notice the comment starting with
SAFETY:. This is a convention I highly recommend. Whenever you useunsafe, write a brief explanation of why it's actually safe. If you can't articulate why the code won't crash, you shouldn't be using theunsafekeyword. You're essentially signing a contract with the compiler; theSAFETYcomment is your evidence that you've done the due diligence to honor that contract.
📋 Practical Task
Build a Fast-Path Array Accessor
In this exercise, you will implement a wrapper around a raw pointer to simulate a "fast-path" memory accessor. Your goal is to create a struct that manages a pointer to a heap-allocated array and provides a method to retrieve an element without the standard bounds checking that Vec or slices perform, while still maintaining a safe public API.
Requirements:
- Create a struct called
FastArraythat holds a*const i32and asize: usize. - Implement a
newmethod that takes aVec<i32>, leaks the vector's memory (usingBox::leakorVec::into_raw_parts), and stores the pointer. - Implement a method
at(&self, index: usize) -> Option<i32>.- Inside this method, first perform a manual bounds check.
- If the index is valid, use an
unsafeblock to offset the pointer and dereference it to return the value. - Include a
// SAFETY:comment explaining why the dereference is valid.
- In your
mainfunction, instantiate theFastArrayand verify it can retrieve elements at the start and end of the array, as well as handle out-of-bounds requests gracefully.
There are no comments for now.