<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged intermediate</title>
<link>https://coderlegion.com/tag/intermediate</link>
<description>Powered by Question2Answer</description>
<item>
<title>Rust Concepts: dyn Trait, Custom Iterators, Deref/Drop &amp; Axum REST API (Part 5)</title>
<link>https://coderlegion.com/19038/rust-concepts-dyn-trait-custom-iterators-deref-drop-axum-rest-api-part-5</link>
<description>&lt;hr&gt;
&lt;p&gt;title: Rust Concepts: dyn Trait, Custom Iterators, Deref/Drop &amp;amp; Axum REST API (Part 5)&lt;br&gt;
published: true&lt;br&gt;
tags: rust, webdev, intermediate, systems&lt;br&gt;
cover_image: &lt;a rel=&quot;nofollow&quot; href=&quot;https://images.unsplash.com/photo-1504639725590-34d0984388bd?w=1000&quot;&gt;https://images.unsplash.com/photo-1504639725590-34d0984388bd?w=1000&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;series-core-rust-concepts&quot;&gt;series: Core Rust Concepts&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;This is &lt;strong&gt;Part 5&lt;/strong&gt; of the Core Rust Concepts series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 1&lt;/a&gt; — Ownership, Borrowing, Lifetimes, Traits, Result/Option, Pattern Matching&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 2&lt;/a&gt; — Closures, Iterators, Generics, Enums, Smart Pointers, Async/Await&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 3&lt;/a&gt; — Macros, Modules, Testing, Unsafe Rust, FFI&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 4&lt;/a&gt; — Threads, Channels, Send/Sync, Mutex, Atomics, clap&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#25-trait-objects-and-dynamic-dispatch&quot;&gt;Trait Objects and Dynamic Dispatch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#26-the-deref-trait&quot;&gt;The Deref Trait&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#27-the-drop-trait&quot;&gt;The Drop Trait&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#28-custom-iterators&quot;&gt;Custom Iterators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#29-building-a-rest-api-with-axum&quot;&gt;Building a REST API with Axum&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;25-trait-objects-and-dynamic-dispatch&quot;&gt;25. Trait Objects and Dynamic Dispatch&lt;/h3&gt;
&lt;p&gt;In Part 2 we used &lt;code&gt;impl Trait&lt;/code&gt; — that's &lt;strong&gt;static dispatch&lt;/strong&gt;: the compiler knows the exact type at compile time and monomorphizes it. Sometimes you don't know the type until runtime. That's where &lt;strong&gt;trait objects&lt;/strong&gt; (&lt;code&gt;dyn Trait&lt;/code&gt;) come in.&lt;/p&gt;
&lt;h4 id=&quot;static-vs-dynamic-dispatch&quot;&gt;Static vs Dynamic dispatch&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;trait Greet {
    fn hello(&amp;amp;self) -&amp;gt; String;
}

struct English;
struct Spanish;

impl Greet for English {
    fn hello(&amp;amp;self) -&amp;gt; String { String::from(&quot;Hello!&quot;) }
}

impl Greet for Spanish {
    fn hello(&amp;amp;self) -&amp;gt; String { String::from(&quot;¡Hola!&quot;) }
}

// Static dispatch — type known at compile time, zero overhead
fn greet_static(g: &amp;amp;impl Greet) {
    println!(&quot;{}&quot;, g.hello());
}

// Dynamic dispatch — type known at runtime via vtable
fn greet_dynamic(g: &amp;amp;dyn Greet) {
    println!(&quot;{}&quot;, g.hello());
}

fn main() {
    let e = English;
    let s = Spanish;

    greet_static(&amp;amp;e);
    greet_dynamic(&amp;amp;s);

    // Only dyn Trait allows mixing types in a collection
    let greeters: Vec&amp;lt;Box&amp;lt;dyn Greet&amp;gt;&amp;gt; = vec![
        Box::new(English),
        Box::new(Spanish),
        Box::new(English),
    ];

    for g in &amp;amp;greeters {
        println!(&quot;{}&quot;, g.hello());
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;when-to-use-dyn-trait-vs-impl-trait&quot;&gt;When to use &lt;code&gt;dyn Trait&lt;/code&gt; vs &lt;code&gt;impl Trait&lt;/code&gt;&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;code&gt;impl Trait&lt;/code&gt; &lt;/th&gt;&lt;th&gt;&lt;code&gt;dyn Trait&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Dispatch &lt;/td&gt;&lt;td&gt;Static (compile time) &lt;/td&gt;&lt;td&gt;Dynamic (runtime vtable)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Performance &lt;/td&gt;&lt;td&gt;Zero overhead &lt;/td&gt;&lt;td&gt;Small indirection cost&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Heterogeneous collections &lt;/td&gt;&lt;td&gt;❌ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Return from function &lt;/td&gt;&lt;td&gt;✅ (one concrete type) &lt;/td&gt;&lt;td&gt;✅ (any type at runtime)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Sized &lt;/td&gt;&lt;td&gt;✅ &lt;/td&gt;&lt;td&gt;❌ (must be behind &lt;code&gt;&amp;amp;&lt;/code&gt; or &lt;code&gt;Box&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;object-safe-traits&quot;&gt;Object-safe traits&lt;/h4&gt;
&lt;p&gt;Not every trait can be made into a trait object. A trait is &lt;strong&gt;object-safe&lt;/strong&gt; if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It has no methods that return &lt;code&gt;Self&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;It has no generic methods&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;// ✅ Object-safe
trait Drawable {
    fn draw(&amp;amp;self);
    fn area(&amp;amp;self) -&amp;gt; f64;
}

// ❌ NOT object-safe — returns Self
trait Clone2 {
    fn clone2(&amp;amp;self) -&amp;gt; Self; // can't use as dyn Clone2
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;real-world-pattern-plugin-system&quot;&gt;Real-world pattern — plugin system&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;trait Plugin {
    fn name(&amp;amp;self) -&amp;gt; &amp;amp;str;
    fn run(&amp;amp;self, input: &amp;amp;str) -&amp;gt; String;
}

struct UppercasePlugin;
struct ReversePlugin;

impl Plugin for UppercasePlugin {
    fn name(&amp;amp;self) -&amp;gt; &amp;amp;str { &quot;uppercase&quot; }
    fn run(&amp;amp;self, input: &amp;amp;str) -&amp;gt; String { input.to_uppercase() }
}

impl Plugin for ReversePlugin {
    fn name(&amp;amp;self) -&amp;gt; &amp;amp;str { &quot;reverse&quot; }
    fn run(&amp;amp;self, input: &amp;amp;str) -&amp;gt; String { input.chars().rev().collect() }
}

struct Pipeline {
    plugins: Vec&amp;lt;Box&amp;lt;dyn Plugin&amp;gt;&amp;gt;,
}

impl Pipeline {
    fn new() -&amp;gt; Self { Self { plugins: vec![] } }

    fn add(mut self, p: Box&amp;lt;dyn Plugin&amp;gt;) -&amp;gt; Self {
        self.plugins.push(p);
        self
    }

    fn run(&amp;amp;self, input: &amp;amp;str) -&amp;gt; String {
        self.plugins.iter().fold(input.to_string(), |acc, p| p.run(&amp;amp;acc))
    }
}

fn main() {
    let pipeline = Pipeline::new()
        .add(Box::new(UppercasePlugin))
        .add(Box::new(ReversePlugin));

    println!(&quot;{}&quot;, pipeline.run(&quot;hello&quot;)); // &quot;OLLEH&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;26-the-deref-trait&quot;&gt;26. The Deref Trait&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Deref&lt;/code&gt; controls what happens when you use the &lt;code&gt;*&lt;/code&gt; operator on a type. It's also what enables &lt;strong&gt;deref coercions&lt;/strong&gt; — Rust automatically calls &lt;code&gt;deref()&lt;/code&gt; to convert types so you don't have to do it manually.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::ops::Deref;

// A simple smart pointer
struct MyBox&amp;lt;T&amp;gt;(T);

impl&amp;lt;T&amp;gt; MyBox&amp;lt;T&amp;gt; {
    fn new(x: T) -&amp;gt; MyBox&amp;lt;T&amp;gt; { MyBox(x) }
}

impl&amp;lt;T&amp;gt; Deref for MyBox&amp;lt;T&amp;gt; {
    type Target = T;

    fn deref(&amp;amp;self) -&amp;gt; &amp;amp;Self::Target {
        &amp;amp;self.0 // return a reference to the inner value
    }
}

fn hello(name: &amp;amp;str) {
    println!(&quot;Hello, {name}!&quot;);
}

fn main() {
    let x = MyBox::new(String::from(&quot;Rustacean&quot;));

    // These are all equivalent due to deref coercions:
    hello(&amp;amp;x);           // MyBox&amp;lt;String&amp;gt; → &amp;amp;String → &amp;amp;str  (auto!)
    hello(&amp;amp;(*x)[..]);    // manual — what Rust does behind the scenes
    hello(x.deref());    // explicit deref
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;deref-coercion-chain&quot;&gt;Deref coercion chain&lt;/h4&gt;
&lt;p&gt;Rust automatically chains &lt;code&gt;Deref&lt;/code&gt; calls as many times as needed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;MyBox&amp;lt;String&amp;gt;  →  String  →  str
    &amp;amp;MyBox&amp;lt;String&amp;gt;  →  &amp;amp;String  →  &amp;amp;str
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn main() {
    let boxed = Box::new(String::from(&quot;hello&quot;));

    // Box&amp;lt;String&amp;gt; derefs to String, then to str
    println!(&quot;{}&quot;, boxed.to_uppercase()); // HELLO
    println!(&quot;{}&quot;, boxed.len());          // 5

    let s: &amp;amp;str = &amp;amp;boxed; // Box&amp;lt;String&amp;gt; → &amp;amp;String → &amp;amp;str — all automatic
    println!(&quot;{s}&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;derefmut&quot;&gt;DerefMut&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;DerefMut&lt;/code&gt; does the same for mutable contexts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::ops::{Deref, DerefMut};

struct Wrapper(Vec&amp;lt;i32&amp;gt;);

impl Deref for Wrapper {
    type Target = Vec&amp;lt;i32&amp;gt;;
    fn deref(&amp;amp;self) -&amp;gt; &amp;amp;Vec&amp;lt;i32&amp;gt; { &amp;amp;self.0 }
}

impl DerefMut for Wrapper {
    fn deref_mut(&amp;amp;mut self) -&amp;gt; &amp;amp;mut Vec&amp;lt;i32&amp;gt; { &amp;amp;mut self.0 }
}

fn main() {
    let mut w = Wrapper(vec![1, 2, 3]);
    w.push(4);                     // DerefMut lets you call Vec methods
    println!(&quot;{:?}&quot;, w.as_slice()); // Deref: [1, 2, 3, 4]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;27-the-drop-trait&quot;&gt;27. The Drop Trait&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Drop&lt;/code&gt; lets you run custom cleanup code when a value goes out of scope — like a destructor in C++. Rust calls &lt;code&gt;drop()&lt;/code&gt; automatically; you never call it yourself (use &lt;code&gt;std::mem::drop()&lt;/code&gt; to drop early).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;struct Resource {
    name: String,
}

impl Resource {
    fn new(name: &amp;amp;str) -&amp;gt; Self {
        println!(&quot;acquiring: {name}&quot;);
        Resource { name: name.to_string() }
    }
}

impl Drop for Resource {
    fn drop(&amp;amp;mut self) {
        println!(&quot;releasing: {}&quot;, self.name);
    }
}

fn main() {
    let _a = Resource::new(&quot;database connection&quot;);
    let _b = Resource::new(&quot;file handle&quot;);
    println!(&quot;resources in use...&quot;);
    // Drop order is LIFO: _b dropped first, then _a
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;acquiring: database connection
acquiring: file handle
resources in use...
releasing: file handle
releasing: database connection
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;dropping-early&quot;&gt;Dropping early&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn main() {
    let conn = Resource::new(&quot;db&quot;);
    println!(&quot;doing work...&quot;);

    drop(conn); // explicit early drop — calls Drop::drop()
    println!(&quot;conn already released&quot;);

    // conn.name; ← compile error: value was dropped
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;drop-in-practice-raii-pattern&quot;&gt;Drop in practice — RAII pattern&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::{Arc, Mutex};

struct DbPool {
    connections: Arc&amp;lt;Mutex&amp;lt;Vec&amp;lt;String&amp;gt;&amp;gt;&amp;gt;,
}

struct DbConnection {
    id: String,
    pool: Arc&amp;lt;Mutex&amp;lt;Vec&amp;lt;String&amp;gt;&amp;gt;&amp;gt;,
}

impl Drop for DbConnection {
    fn drop(&amp;amp;mut self) {
        // Return the connection back to the pool automatically
        self.pool.lock().unwrap().push(self.id.clone());
        println!(&quot;connection '{}' returned to pool&quot;, self.id);
    }
}

impl DbPool {
    fn new() -&amp;gt; Self {
        let conns = vec![&quot;conn-1&quot;.into(), &quot;conn-2&quot;.into(), &quot;conn-3&quot;.into()];
        Self { connections: Arc::new(Mutex::new(conns)) }
    }

    fn get(&amp;amp;self) -&amp;gt; Option&amp;lt;DbConnection&amp;gt; {
        let id = self.connections.lock().unwrap().pop()?;
        println!(&quot;checked out: {id}&quot;);
        Some(DbConnection { id, pool: Arc::clone(&amp;amp;self.connections) })
    }
}

fn main() {
    let pool = DbPool::new();
    {
        let _c1 = pool.get(); // &quot;conn-3&quot;
        let _c2 = pool.get(); // &quot;conn-2&quot;
    } // both returned to pool here automatically
    println!(&quot;pool size: {}&quot;, pool.connections.lock().unwrap().len()); // 3
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt; This is the &lt;strong&gt;RAII&lt;/strong&gt; (Resource Acquisition Is Initialization) pattern — the same one Rust's &lt;code&gt;MutexGuard&lt;/code&gt;, file handles, and socket wrappers use internally.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;28-custom-iterators&quot;&gt;28. Custom Iterators&lt;/h3&gt;
&lt;p&gt;You can make any type iterable by implementing the &lt;code&gt;Iterator&lt;/code&gt; trait, which requires only one method: &lt;code&gt;next()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;struct Counter {
    count: u32,
    max: u32,
}

impl Counter {
    fn new(max: u32) -&amp;gt; Self { Self { count: 0, max } }
}

impl Iterator for Counter {
    type Item = u32;

    fn next(&amp;amp;mut self) -&amp;gt; Option&amp;lt;Self::Item&amp;gt; {
        if self.count &amp;lt; self.max {
            self.count += 1;
            Some(self.count)
        } else {
            None // signals the iterator is exhausted
        }
    }
}

fn main() {
    let counter = Counter::new(5);

    // You get ALL iterator methods for free!
    let sum: u32 = counter.sum();
    println!(&quot;sum: {sum}&quot;); // 15

    // Chain with other iterators
    let result: Vec&amp;lt;u32&amp;gt; = Counter::new(5)
        .zip(Counter::new(5).skip(1))   // pair consecutive values
        .map(|(a, b)| a * b)            // multiply each pair
        .filter(|x| x % 3 == 0)        // keep multiples of 3
        .collect();

    println!(&quot;{:?}&quot;, result); // [6, 12]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;a-real-world-custom-iterator-paginated-results&quot;&gt;A real-world custom iterator — paginated results&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;struct Paginator {
    current_page: u32,
    total_pages: u32,
    page_size: u32,
}

impl Paginator {
    fn new(total_items: u32, page_size: u32) -&amp;gt; Self {
        Self {
            current_page: 0,
            total_pages: (total_items + page_size - 1) / page_size,
            page_size,
        }
    }
}

#[derive(Debug)]
struct Page {
    number: u32,
    offset: u32,
    limit: u32,
}

impl Iterator for Paginator {
    type Item = Page;

    fn next(&amp;amp;mut self) -&amp;gt; Option&amp;lt;Page&amp;gt; {
        if self.current_page &amp;lt; self.total_pages {
            self.current_page += 1;
            Some(Page {
                number: self.current_page,
                offset: (self.current_page - 1) * self.page_size,
                limit: self.page_size,
            })
        } else {
            None
        }
    }
}

fn main() {
    let pages = Paginator::new(95, 20);

    for page in pages {
        println!(&quot;Page {}: OFFSET {} LIMIT {}&quot;, page.number, page.offset, page.limit);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Page 1: OFFSET 0 LIMIT 20
Page 2: OFFSET 20 LIMIT 20
Page 3: OFFSET 40 LIMIT 20
Page 4: OFFSET 60 LIMIT 20
Page 5: OFFSET 80 LIMIT 20
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;intoiterator-making-structs-work-in-for-loops&quot;&gt;IntoIterator — making structs work in for loops&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;struct Stack&amp;lt;T&amp;gt; {
    items: Vec&amp;lt;T&amp;gt;,
}

impl&amp;lt;T&amp;gt; Stack&amp;lt;T&amp;gt; {
    fn new() -&amp;gt; Self { Self { items: vec![] } }
    fn push(&amp;amp;mut self, item: T) { self.items.push(item); }
}

impl&amp;lt;T&amp;gt; IntoIterator for Stack&amp;lt;T&amp;gt; {
    type Item = T;
    type IntoIter = std::vec::IntoIter&amp;lt;T&amp;gt;;

    fn into_iter(self) -&amp;gt; Self::IntoIter {
        self.items.into_iter()
    }
}

fn main() {
    let mut stack = Stack::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);

    for item in stack { // works because of IntoIterator
        println!(&quot;{item}&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;29-building-a-rest-api-with-axum&quot;&gt;29. Building a REST API with Axum&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;axum&lt;/code&gt; is the most popular async web framework in Rust, built on top of &lt;code&gt;tokio&lt;/code&gt; and &lt;code&gt;hyper&lt;/code&gt;. It uses Rust's type system to make routing and request extraction ergonomic and safe.&lt;/p&gt;
&lt;h4 id=&quot;setup&quot;&gt;Setup&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;# Cargo.toml
[dependencies]
axum      = &quot;0.7&quot;
tokio     = { version = &quot;1&quot;, features = [&quot;full&quot;] }
serde     = { version = &quot;1&quot;, features = [&quot;derive&quot;] }
serde_json = &quot;1&quot;
uuid      = { version = &quot;1&quot;, features = [&quot;v4&quot;] }
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;full-crud-api-todo-list&quot;&gt;Full CRUD API — Todo List&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::Json,
    routing::{delete, get, post, put},
    Router,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use uuid::Uuid;

// --- Models ---

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Todo {
    id: String,
    title: String,
    completed: bool,
}

#[derive(Deserialize)]
struct CreateTodo {
    title: String,
}

#[derive(Deserialize)]
struct UpdateTodo {
    title: Option&amp;lt;String&amp;gt;,
    completed: Option&amp;lt;bool&amp;gt;,
}

// --- Shared state ---

type Db = Arc&amp;lt;Mutex&amp;lt;Vec&amp;lt;Todo&amp;gt;&amp;gt;&amp;gt;;

// --- Handlers ---

async fn list_todos(State(db): State&amp;lt;Db&amp;gt;) -&amp;gt; Json&amp;lt;Vec&amp;lt;Todo&amp;gt;&amp;gt; {
    let todos = db.lock().unwrap();
    Json(todos.clone())
}

async fn create_todo(
    State(db): State&amp;lt;Db&amp;gt;,
    Json(payload): Json&amp;lt;CreateTodo&amp;gt;,
) -&amp;gt; (StatusCode, Json&amp;lt;Todo&amp;gt;) {
    let todo = Todo {
        id: Uuid::new_v4().to_string(),
        title: payload.title,
        completed: false,
    };
    db.lock().unwrap().push(todo.clone());
    (StatusCode::CREATED, Json(todo))
}

async fn get_todo(
    State(db): State&amp;lt;Db&amp;gt;,
    Path(id): Path&amp;lt;String&amp;gt;,
) -&amp;gt; Result&amp;lt;Json&amp;lt;Todo&amp;gt;, StatusCode&amp;gt; {
    let todos = db.lock().unwrap();
    todos
        .iter()
        .find(|t| t.id == id)
        .cloned()
        .map(Json)
        .ok_or(StatusCode::NOT_FOUND)
}

async fn update_todo(
    State(db): State&amp;lt;Db&amp;gt;,
    Path(id): Path&amp;lt;String&amp;gt;,
    Json(payload): Json&amp;lt;UpdateTodo&amp;gt;,
) -&amp;gt; Result&amp;lt;Json&amp;lt;Todo&amp;gt;, StatusCode&amp;gt; {
    let mut todos = db.lock().unwrap();
    let todo = todos.iter_mut().find(|t| t.id == id).ok_or(StatusCode::NOT_FOUND)?;

    if let Some(title) = payload.title { todo.title = title; }
    if let Some(completed) = payload.completed { todo.completed = completed; }

    Ok(Json(todo.clone()))
}

async fn delete_todo(
    State(db): State&amp;lt;Db&amp;gt;,
    Path(id): Path&amp;lt;String&amp;gt;,
) -&amp;gt; StatusCode {
    let mut todos = db.lock().unwrap();
    let before = todos.len();
    todos.retain(|t| t.id != id);

    if todos.len() &amp;lt; before { StatusCode::NO_CONTENT }
    else { StatusCode::NOT_FOUND }
}

// --- Router ---

fn app(db: Db) -&amp;gt; Router {
    Router::new()
        .route(&quot;/todos&quot;,      get(list_todos).post(create_todo))
        .route(&quot;/todos/:id&quot;,  get(get_todo).put(update_todo).delete(delete_todo))
        .with_state(db)
}

// --- Main ---

#[tokio::main]
async fn main() {
    let db: Db = Arc::new(Mutex::new(vec![]));

    let listener = tokio::net::TcpListener::bind(&quot;0.0.0.0:3000&quot;).await.unwrap();
    println!(&quot;listening on http://localhost:3000&quot;);

    axum::serve(listener, app(db)).await.unwrap();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;test-it-with-curl&quot;&gt;Test it with curl&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Create todos
curl -s -X POST http://localhost:3000/todos \
  -H &quot;Content-Type: application/json&quot; \
  -d '{&quot;title&quot;: &quot;Learn Rust&quot;}' | jq

curl -s -X POST http://localhost:3000/todos \
  -H &quot;Content-Type: application/json&quot; \
  -d '{&quot;title&quot;: &quot;Build an API&quot;}' | jq

# List all
curl -s http://localhost:3000/todos | jq

# Get one (replace ID)
curl -s http://localhost:3000/todos/&amp;lt;id&amp;gt; | jq

# Update
curl -s -X PUT http://localhost:3000/todos/&amp;lt;id&amp;gt; \
  -H &quot;Content-Type: application/json&quot; \
  -d '{&quot;completed&quot;: true}' | jq

# Delete
curl -s -X DELETE http://localhost:3000/todos/&amp;lt;id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;adding-middleware-request-logging&quot;&gt;Adding middleware — request logging&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use axum::middleware::{self, Next};
use axum::extract::Request;
use axum::response::Response;

async fn log_request(req: Request, next: Next) -&amp;gt; Response {
    let method = req.method().clone();
    let uri    = req.uri().clone();
    let res    = next.run(req).await;
    println!(&quot;{} {} → {}&quot;, method, uri, res.status());
    res
}

fn app(db: Db) -&amp;gt; Router {
    Router::new()
        .route(&quot;/todos&quot;,     get(list_todos).post(create_todo))
        .route(&quot;/todos/:id&quot;, get(get_todo).put(update_todo).delete(delete_todo))
        .layer(middleware::from_fn(log_request)) // add logging to all routes
        .with_state(db)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Concept &lt;/th&gt;&lt;th&gt;What it gives you&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;dyn Trait&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Runtime polymorphism, heterogeneous collections&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Deref&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Transparent smart pointer ergonomics, auto-coercions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Drop&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;RAII — deterministic cleanup, no GC needed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Custom iterators&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Any type can plug into Rust's iterator ecosystem&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Axum&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Type-safe, async REST APIs on top of tokio&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-full-series&quot;&gt;The full series&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Part &lt;/th&gt;&lt;th&gt;Topics&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 1&lt;/a&gt; &lt;/td&gt;&lt;td&gt;Ownership, Borrowing, Lifetimes, Traits, Result/Option, Pattern Matching&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 2&lt;/a&gt; &lt;/td&gt;&lt;td&gt;Closures, Iterators, Generics, Enums, Smart Pointers, Async/Await&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 3&lt;/a&gt; &lt;/td&gt;&lt;td&gt;Macros, Modules, Cargo, Testing, Unsafe, FFI&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 4&lt;/a&gt; &lt;/td&gt;&lt;td&gt;Threads, Channels, Send/Sync, Mutex, Atomics, clap&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Part 5&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;strong&gt;dyn Trait, Deref, Drop, Custom Iterators, Axum REST API&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h4 id=&quot;what-s-in-part-6-&quot;&gt;What's in Part 6?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Workspaces and multi-crate projects&lt;/li&gt;
&lt;li&gt;&lt;code&gt;serde&lt;/code&gt; — serialization deep dive&lt;/li&gt;
&lt;li&gt;Benchmarking with &lt;code&gt;criterion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Error handling patterns with &lt;code&gt;thiserror&lt;/code&gt; and &lt;code&gt;anyhow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Writing a real-world CLI + library crate&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Found this useful? Drop a ❤️ and follow for Part 6!&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/19038/rust-concepts-dyn-trait-custom-iterators-deref-drop-axum-rest-api-part-5</guid>
<pubDate>Wed, 27 May 2026 07:37:07 +0000</pubDate>
</item>
<item>
<title>Rust Concurrency: Threads, Channels, Mutex &amp; Sync (Part 4)</title>
<link>https://coderlegion.com/19037/rust-concurrency-threads-channels-mutex-sync-part-4</link>
<description>&lt;hr&gt;
&lt;p&gt;title: Rust Concurrency: Threads, Channels, Mutex &amp;amp; Sync (Part 4)&lt;br&gt;
published: true&lt;br&gt;
tags: rust, concurrency, intermediate, systems&lt;br&gt;
cover_image: &lt;a rel=&quot;nofollow&quot; href=&quot;https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=1000&quot;&gt;https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=1000&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;series-core-rust-concepts-1&quot;&gt;series: Core Rust Concepts&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;This is &lt;strong&gt;Part 4&lt;/strong&gt; of the Core Rust Concepts series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 1&lt;/a&gt; — Ownership, Borrowing, Lifetimes, Traits, Result/Option, Pattern Matching&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 2&lt;/a&gt; — Closures, Iterators, Generics, Enums, Smart Pointers, Async/Await&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 3&lt;/a&gt; — Macros, Modules, Testing, Unsafe Rust, FFI&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;table-of-contents-1&quot;&gt;Table of Contents&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#19-threads&quot;&gt;Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#20-message-passing-with-channels&quot;&gt;Message Passing with Channels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#21-send-and-sync-traits&quot;&gt;Send and Sync Traits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#22-mutex-and-rwlock&quot;&gt;Mutex and RwLock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#23-atomics&quot;&gt;Atomics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#24-building-a-cli-tool-with-clap&quot;&gt;Building a CLI Tool with clap&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;19-threads&quot;&gt;19. Threads&lt;/h3&gt;
&lt;p&gt;Rust's standard library provides OS threads via &lt;code&gt;std::thread&lt;/code&gt;. The ownership and type system prevents data races at compile time — if your code compiles, it's free of data races. That's a guarantee no other systems language makes.&lt;/p&gt;
&lt;h4 id=&quot;spawning-a-thread&quot;&gt;Spawning a thread&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::thread;
use std::time::Duration;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..=5 {
            println!(&quot;thread: {i}&quot;);
            thread::sleep(Duration::from_millis(50));
        }
    });

    for i in 1..=3 {
        println!(&quot;main:   {i}&quot;);
        thread::sleep(Duration::from_millis(80));
    }

    handle.join().unwrap(); // wait for the thread to finish
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;moving-data-into-a-thread&quot;&gt;Moving data into a thread&lt;/h4&gt;
&lt;p&gt;Use &lt;code&gt;move&lt;/code&gt; to transfer ownership of data into the thread closure:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::thread;

fn main() {
    let data = vec![1, 2, 3, 4, 5];

    let handle = thread::spawn(move || {
        // data is moved into this thread
        let sum: i32 = data.iter().sum();
        println!(&quot;sum: {sum}&quot;);
    });

    // println!(&quot;{:?}&quot;, data); ← compile error: data was moved

    handle.join().unwrap();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;spawning-many-threads&quot;&gt;Spawning many threads&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::thread;

fn main() {
    let handles: Vec&amp;lt;_&amp;gt; = (0..8)
        .map(|i| {
            thread::spawn(move || {
                println!(&quot;worker {i} done&quot;);
                i * i
            })
        })
        .collect();

    let results: Vec&amp;lt;_&amp;gt; = handles
        .into_iter()
        .map(|h| h.join().unwrap())
        .collect();

    println!(&quot;squares: {:?}&quot;, results);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt; &lt;code&gt;thread::spawn&lt;/code&gt; returns a &lt;code&gt;JoinHandle&amp;lt;T&amp;gt;&lt;/code&gt; where &lt;code&gt;T&lt;/code&gt; is the return type of the closure. Always &lt;code&gt;.join()&lt;/code&gt; your handles — a panicking thread silently fails otherwise.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;20-message-passing-with-channels&quot;&gt;20. Message Passing with Channels&lt;/h3&gt;
&lt;p&gt;Rust's standard library includes &lt;strong&gt;multiple-producer, single-consumer (mpsc)&lt;/strong&gt; channels. The philosophy: &lt;em&gt;&quot;do not communicate by sharing memory; share memory by communicating.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;basic-channel&quot;&gt;Basic channel&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let msgs = vec![&quot;hello&quot;, &quot;from&quot;, &quot;the&quot;, &quot;thread&quot;];
        for msg in msgs {
            tx.send(msg).unwrap();
        }
    });

    for received in rx {
        println!(&quot;got: {received}&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;multiple-producers&quot;&gt;Multiple producers&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel::&amp;lt;String&amp;gt;();

    for id in 0..4 {
        let tx_clone = tx.clone(); // each thread gets its own sender
        thread::spawn(move || {
            tx_clone.send(format!(&quot;msg from worker {id}&quot;)).unwrap();
        });
    }

    drop(tx); // drop the original so rx knows when all senders are gone

    for msg in rx {
        println!(&quot;{msg}&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;synchronous-channel-bounded-&quot;&gt;Synchronous channel (bounded)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::mpsc;
use std::thread;

fn main() {
    // Buffer of 2 — sender blocks when full
    let (tx, rx) = mpsc::sync_channel::&amp;lt;i32&amp;gt;(2);

    thread::spawn(move || {
        for i in 0..5 {
            println!(&quot;sending {i}&quot;);
            tx.send(i).unwrap(); // blocks at i=2 until receiver reads
        }
    });

    thread::sleep(std::time::Duration::from_millis(200));

    for val in rx {
        println!(&quot;received {val}&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt; For more advanced channel patterns (broadcast, watch, oneshot), use the &lt;code&gt;tokio::sync&lt;/code&gt; or &lt;code&gt;crossbeam-channel&lt;/code&gt; crates.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;21-send-and-sync-traits&quot;&gt;21. Send and Sync Traits&lt;/h3&gt;
&lt;p&gt;These two marker traits are the foundation of Rust's fearless concurrency. You rarely implement them manually — the compiler derives them automatically.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Trait &lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Send&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Safe to &lt;strong&gt;transfer ownership&lt;/strong&gt; to another thread&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Sync&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Safe to &lt;strong&gt;share a reference&lt;/strong&gt; across threads (&lt;code&gt;&amp;amp;T&lt;/code&gt; is &lt;code&gt;Send&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::thread;
use std::rc::Rc;
use std::sync::Arc;

fn main() {
    // Rc&amp;lt;T&amp;gt; is NOT Send — can't move across threads
    // let rc = Rc::new(42);
    // thread::spawn(move || println!(&quot;{}&quot;, rc)); ← compile error!

    // Arc&amp;lt;T&amp;gt; IS Send — atomic reference counting
    let arc = Arc::new(42);
    let arc_clone = Arc::clone(&amp;amp;arc);

    thread::spawn(move || {
        println!(&quot;thread sees: {}&quot;, arc_clone);
    }).join().unwrap();

    println!(&quot;main sees: {}&quot;, arc);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Types and their Send/Sync status:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Type &lt;/th&gt;&lt;th&gt;Send &lt;/th&gt;&lt;th&gt;Sync&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;i32&lt;/code&gt;, &lt;code&gt;f64&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt; &lt;/td&gt;&lt;td&gt;✅ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Vec&amp;lt;T&amp;gt;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;✅ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;❌ &lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Arc&amp;lt;T&amp;gt;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;✅ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;RefCell&amp;lt;T&amp;gt;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;✅ &lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Mutex&amp;lt;T&amp;gt;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;✅ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*mut T&lt;/code&gt; (raw pointer) &lt;/td&gt;&lt;td&gt;❌ &lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt; If you try to share a non-&lt;code&gt;Sync&lt;/code&gt; type across threads, the compiler refuses to compile. No runtime surprises.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;22-mutex-and-rwlock&quot;&gt;22. Mutex and RwLock&lt;/h3&gt;
&lt;p&gt;When multiple threads need to &lt;strong&gt;mutate shared data&lt;/strong&gt;, use a &lt;code&gt;Mutex&lt;/code&gt; (mutual exclusion lock). Wrap it in &lt;code&gt;Arc&lt;/code&gt; to share ownership across threads.&lt;/p&gt;
&lt;h4 id=&quot;mutex&quot;&gt;Mutex&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&amp;amp;counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap(); // blocks until lock acquired
            *num += 1;
        }); // lock is released here when `num` drops
        handles.push(handle);
    }

    for h in handles { h.join().unwrap(); }

    println!(&quot;result: {}&quot;, *counter.lock().unwrap()); // 10
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;rwlock-many-readers-one-writer&quot;&gt;RwLock — many readers, one writer&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::{Arc, RwLock};
use std::thread;

fn main() {
    let data = Arc::new(RwLock::new(vec![1, 2, 3]));

    // Spawn 4 reader threads
    let readers: Vec&amp;lt;_&amp;gt; = (0..4).map(|i| {
        let data = Arc::clone(&amp;amp;data);
        thread::spawn(move || {
            let r = data.read().unwrap(); // multiple readers allowed
            println!(&quot;reader {i}: {:?}&quot;, *r);
        })
    }).collect();

    // One writer thread
    let data_w = Arc::clone(&amp;amp;data);
    let writer = thread::spawn(move || {
        let mut w = data_w.write().unwrap(); // exclusive access
        w.push(4);
        println!(&quot;writer pushed 4&quot;);
    });

    for r in readers { r.join().unwrap(); }
    writer.join().unwrap();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Mutex vs RwLock:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;code&gt;Mutex&amp;lt;T&amp;gt;&lt;/code&gt; &lt;/th&gt;&lt;th&gt;&lt;code&gt;RwLock&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Readers &lt;/td&gt;&lt;td&gt;One at a time &lt;/td&gt;&lt;td&gt;Many simultaneously&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Writers &lt;/td&gt;&lt;td&gt;One at a time &lt;/td&gt;&lt;td&gt;One at a time (exclusive)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Best for &lt;/td&gt;&lt;td&gt;Write-heavy workloads &lt;/td&gt;&lt;td&gt;Read-heavy workloads&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Overhead &lt;/td&gt;&lt;td&gt;Lower &lt;/td&gt;&lt;td&gt;Higher&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;avoiding-deadlocks&quot;&gt;Avoiding deadlocks&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::{Arc, Mutex};

fn main() {
    let a = Arc::new(Mutex::new(1));
    let b = Arc::new(Mutex::new(2));

    // ✅ Always acquire locks in the same order
    {
        let _lock_a = a.lock().unwrap();
        let _lock_b = b.lock().unwrap();
        println!(&quot;safe&quot;);
    }

    // ❌ Acquiring in different orders across threads = deadlock risk
    // thread 1: lock a → lock b
    // thread 2: lock b → lock a  ← deadlock!
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;23-atomics&quot;&gt;23. Atomics&lt;/h3&gt;
&lt;p&gt;For simple counters and flags shared between threads, &lt;code&gt;std::sync::atomic&lt;/code&gt; types are faster than a &lt;code&gt;Mutex&lt;/code&gt; — they use hardware atomic instructions with no locking.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

fn main() {
    let counter = Arc::new(AtomicUsize::new(0));
    let mut handles = vec![];

    for _ in 0..8 {
        let counter = Arc::clone(&amp;amp;counter);
        handles.push(thread::spawn(move || {
            for _ in 0..1000 {
                counter.fetch_add(1, Ordering::Relaxed);
            }
        }));
    }

    for h in handles { h.join().unwrap(); }
    println!(&quot;total: {}&quot;, counter.load(Ordering::SeqCst)); // 8000
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;memory-ordering-cheat-sheet&quot;&gt;Memory ordering cheat sheet&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Ordering &lt;/th&gt;&lt;th&gt;Use case&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Relaxed&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Counters — no ordering guarantees needed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Acquire&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Load that synchronizes with a &lt;code&gt;Release&lt;/code&gt; store&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Release&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Store that publishes data to other threads&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AcqRel&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Read-modify-write (e.g. &lt;code&gt;fetch_add&lt;/code&gt; with sync)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SeqCst&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Strongest — total order across all threads&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;

fn main() {
    let ready = Arc::new(AtomicBool::new(false));
    let ready_clone = Arc::clone(&amp;amp;ready);

    let worker = thread::spawn(move || {
        thread::sleep(std::time::Duration::from_millis(100));
        ready_clone.store(true, Ordering::Release);
        println!(&quot;worker: done&quot;);
    });

    // Spin-wait (not ideal in prod — use a Condvar or channel instead)
    while !ready.load(Ordering::Acquire) {
        thread::yield_now();
    }
    println!(&quot;main: worker finished&quot;);
    worker.join().unwrap();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt; Available atomic types: &lt;code&gt;AtomicBool&lt;/code&gt;, &lt;code&gt;AtomicI8/16/32/64&lt;/code&gt;, &lt;code&gt;AtomicU8/16/32/64&lt;/code&gt;, &lt;code&gt;AtomicUsize&lt;/code&gt;, &lt;code&gt;AtomicIsize&lt;/code&gt;, &lt;code&gt;AtomicPtr&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;24-building-a-cli-tool-with-clap&quot;&gt;24. Building a CLI Tool with clap&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;clap&lt;/code&gt; is the standard Rust library for building command-line interfaces. It gives you argument parsing, help text, and subcommands with minimal boilerplate.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;# Cargo.toml
[dependencies]
clap = { version = &quot;4&quot;, features = [&quot;derive&quot;] }
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;basic-cli&quot;&gt;Basic CLI&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use clap::Parser;

/// A simple file word counter
#[derive(Parser, Debug)]
#[command(name = &quot;wordcount&quot;)]
#[command(about = &quot;Count words in a string or file&quot;, long_about = None)]
struct Cli {
    /// The text to count words in
    #[arg(short, long)]
    text: Option&amp;lt;String&amp;gt;,

    /// Show character count too
    #[arg(short, long, default_value_t = false)]
    chars: bool,

    /// Verbosity level
    #[arg(short, long, action = clap::ArgAction::Count)]
    verbose: u8,
}

fn main() {
    let cli = Cli::parse();

    let input = cli.text.unwrap_or_else(|| String::from(&quot;hello world&quot;));
    let words = input.split_whitespace().count();

    if cli.verbose &amp;gt; 0 {
        println!(&quot;Input: {:?}&quot;, input);
    }

    println!(&quot;Words: {words}&quot;);

    if cli.chars {
        println!(&quot;Chars: {}&quot;, input.chars().count());
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Running it:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cargo run -- --text &quot;the quick brown fox&quot; --chars -v
Input: &quot;the quick brown fox&quot;
Words: 4
Chars: 19

$ cargo run -- --help
Count words in a string or file

Usage: wordcount [OPTIONS]

Options:
  -t, --text &amp;lt;TEXT&amp;gt;   The text to count words in
  -c, --chars         Show character count too
  -v, --verbose...    Verbosity level
  -h, --help          Print help
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;subcommands&quot;&gt;Subcommands&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(name = &quot;mytool&quot;, about = &quot;A multi-command CLI&quot;)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Add two numbers
    Add { a: f64, b: f64 },
    /// Multiply two numbers
    Mul { a: f64, b: f64 },
    /// Greet someone
    Greet {
        name: String,
        #[arg(short, long, default_value = &quot;Hello&quot;)]
        greeting: String,
    },
}

fn main() {
    let cli = Cli::parse();

    match cli.command {
        Commands::Add { a, b } =&amp;gt; println!(&quot;{} + {} = {}&quot;, a, b, a + b),
        Commands::Mul { a, b } =&amp;gt; println!(&quot;{} × {} = {}&quot;, a, b, a * b),
        Commands::Greet { name, greeting } =&amp;gt; println!(&quot;{greeting}, {name}!&quot;),
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Running subcommands:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cargo run -- add 3.5 2.5
3.5 + 2.5 = 6

$ cargo run -- greet Alice --greeting &quot;Hey&quot;
Hey, Alice!

$ cargo run -- mul 6 7
6 × 7 = 42
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt; For a full production CLI, combine &lt;code&gt;clap&lt;/code&gt; with &lt;code&gt;anyhow&lt;/code&gt; for error handling, &lt;code&gt;indicatif&lt;/code&gt; for progress bars, and &lt;code&gt;colored&lt;/code&gt; or &lt;code&gt;owo-colors&lt;/code&gt; for terminal color output.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;wrapping-up-1&quot;&gt;Wrapping Up&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Concept &lt;/th&gt;&lt;th&gt;What it gives you&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Threads&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;OS-level parallelism, compile-time data race prevention&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Channels&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Safe message passing between threads (mpsc)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Send &amp;amp; Sync&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Compiler-enforced thread-safety contracts&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Mutex &amp;amp; RwLock&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Shared mutable state without data races&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Atomics&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Lock-free counters and flags&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;clap&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Production-grade CLI argument parsing&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-full-series-so-far&quot;&gt;The full series so far&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Part &lt;/th&gt;&lt;th&gt;Topics&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 1&lt;/a&gt; &lt;/td&gt;&lt;td&gt;Ownership, Borrowing, Lifetimes, Traits, Result/Option, Pattern Matching&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 2&lt;/a&gt; &lt;/td&gt;&lt;td&gt;Closures, Iterators, Generics, Enums, Smart Pointers, Async/Await&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#&quot;&gt;Part 3&lt;/a&gt; &lt;/td&gt;&lt;td&gt;Macros, Modules, Cargo, Testing, Unsafe, FFI&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Part 4&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;strong&gt;Threads, Channels, Send/Sync, Mutex, Atomics, clap&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h4 id=&quot;what-s-in-part-5-&quot;&gt;What's in Part 5?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Trait objects and dynamic dispatch (&lt;code&gt;dyn Trait&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Deref&lt;/code&gt; and &lt;code&gt;Drop&lt;/code&gt; traits&lt;/li&gt;
&lt;li&gt;Custom iterators&lt;/li&gt;
&lt;li&gt;Building a real REST API with &lt;code&gt;axum&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Found this helpful? Drop a ❤️ and follow for Part 5!&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/19037/rust-concurrency-threads-channels-mutex-sync-part-4</guid>
<pubDate>Wed, 27 May 2026 07:36:28 +0000</pubDate>
</item>
</channel>
</rss>