Rust Series : Borrow Checker Part 4 | As Design Partner – Advanced Patterns and Smart Pointers



This content originally appeared on DEV Community and was authored by Abhishek Kumar

Moving beyond basic borrowing to master Rust’s powerful ownership tools and design patterns.
Recap: Your Journey So Far

Previous Articles on the same series

https://dev.to/triggerak/rust-ownership-mastery-the-zero-cost-safety-revolution-4p11
https://dev.to/triggerak/rust-series-borrow-checker-as-design-partner-understanding-lifetimes-through-analogies-84b
https://dev.to/triggerak/rust-series-borrow-checker-bonus-chapter-non-lexical-lifetimes-15cg
https://dev.to/triggerak/rust-series-borrow-checker-part-2-as-design-partner-the-compilers-mental-model-3en8
https://dev.to/triggerak/rust-series-borrow-checker-part-3-as-design-partner-common-errors-and-battle-tested-2da0

Now – Advanced patterns that make the borrow checker your ally

The Smart Pointer Toolkit

   fn main() {
    println!("=== Smart Pointers: Beyond Basic References ===");
    demonstrate_smart_pointers();

    println!("\n=== Design Patterns: Working WITH the Borrow Checker ===");
    demonstrate_design_patterns();

    println!("\n=== Performance Considerations ===");
    demonstrate_performance_patterns();
}

// SMART POINTERS: Tools for complex ownership scenarios
fn demonstrate_smart_pointers() {
    use std::rc::Rc;
    use std::cell::RefCell;
    use std::sync::Arc;

    println!("=== Box<T>: Heap Allocation ===");
    // CONCEPT: Box moves data to heap and provides ownership
    let expensive_data = Box::new(vec![1; 1000]); // Large data on heap
    let data_ref = &*expensive_data; // Deref to get &Vec<i32>
    println!("Heap data length: {}", data_ref.len());
    println!("Heap data - expensive_data {:?}", expensive_data);
    println!("Heap data - *expensive_data {:?}", *expensive_data);

    println!("Heap data - data_ref  {:?}", data_ref);
    println!("Heap data - *data_ref  {:?}", *data_ref);
    println!("\n=== Rc<T>: Shared Ownership (Single Thread) ===");
    // CONCEPT: Reference counting for multiple owners
    let shared_config = Rc::new("Global Configuration".to_string());
    let user1 = Rc::clone(&shared_config); // Increment ref count
    let user2 = Rc::clone(&shared_config); // Increment ref count

    println!("Config: {}", shared_config);
    println!("User1 sees: {}", user1);
    println!("User2 sees: {}", user2);
    println!("Reference count: {}", Rc::strong_count(&shared_config));

    println!("\n=== RefCell<T>: Interior Mutability ===");
    // CONCEPT: Runtime borrow checking instead of compile-time
    let mutable_in_immutable = RefCell::new(vec![1, 2, 3]);

    {
        let mut borrowed = mutable_in_immutable.borrow_mut();
        borrowed.push(4);
        println!("Modified: {:?}", *borrowed);
    } // Borrow released here

    let read_only = mutable_in_immutable.borrow();
    println!("Read-only view: {:?}", *read_only);

    println!("\n=== Rc<RefCell<T>>: Shared Mutable State ===");
    // CONCEPT: Combine shared ownership with interior mutability
    let shared_counter = Rc::new(RefCell::new(0));

    let incrementer1 = Rc::clone(&shared_counter);
    let incrementer2 = Rc::clone(&shared_counter);

    // Simulate different parts of code modifying shared state
    *incrementer1.borrow_mut() += 10;
    *incrementer2.borrow_mut() += 5;

    println!("Final counter value: {}", shared_counter.borrow());
}

// DESIGN PATTERNS: Architecting around ownership
fn demonstrate_design_patterns() {
    println!("=== Pattern 1: Builder with Ownership Transfer ===");

    struct ConfigBuilder {
        database_url: Option<String>,
        port: Option<u16>,
        debug: bool,
    }

    struct Config {
        database_url: String,
        port: u16,
        debug: bool,
    }

    impl ConfigBuilder {
        fn new() -> Self {
            Self {
                database_url: None,
                port: None,
                debug: false,
            }
        }

        // PATTERN: Consume self and return Self for chaining
        fn database_url(mut self, url: String) -> Self {
            self.database_url = Some(url);
            self // Return owned self
        }

        fn port(mut self, port: u16) -> Self {
            self.port = Some(port);
            self
        }

        fn debug(mut self, debug: bool) -> Self {
            self.debug = debug;
            self
        }

        // PATTERN: Final consumption to create the target type
        fn build(self) -> Result<Config, &'static str> {
            Ok(Config {
                database_url: self.database_url.ok_or("Database URL required")?,
                port: self.port.unwrap_or(5432),
                debug: self.debug,
            })
        }
    }

    let config = ConfigBuilder::new()
        .database_url("postgresql://localhost".to_string())
        .port(5433)
        .debug(true)
        .build()
        .unwrap();

    println!("Built config: {}:{}", config.database_url, config.port);

    println!("\n=== Pattern 2: Resource Manager with RAII ===");

    struct FileManager {
        filename: String,
        is_open: bool,
    }

    impl FileManager {
        fn open(filename: String) -> Self {
            println!("Opening file: {}", filename);
            Self { filename, is_open: true }
        }

        fn write(&mut self, data: &str) {
            if self.is_open {
                println!("Writing to {}: {}", self.filename, data);
            }
        }
    }

    impl Drop for FileManager {
        fn drop(&mut self) {
            if self.is_open {
                println!("Auto-closing file: {}", self.filename);
            }
        }
    }

    {
        let mut file = FileManager::open("data.txt".to_string());
        file.write("Important data");
        // File automatically closed when dropped
    }

    println!("\n=== Pattern 3: Visitor with Lifetime Bounds ===");

    trait Processor {
        fn process(&self, data: &str) -> String;
    }

    struct Logger;
    impl Processor for Logger {
        fn process(&self, data: &str) -> String {
            format!("[LOG] {}", data)
        }
    }

    struct Encryptor;
    impl Processor for Encryptor {
        fn process(&self, data: &str) -> String {
            format!("[ENCRYPTED] {}", data.chars().rev().collect::<String>())
        }
    }

    // PATTERN: Accept any processor without lifetime complications
    fn process_data(data: &str, processor: &dyn Processor) -> String {
        processor.process(data)
    }

    let logger = Logger;
    let encryptor = Encryptor;

    let result1 = process_data("sensitive data", &logger);
    let result2 = process_data("sensitive data", &encryptor);

    println!("Logged: {}", result1);
    println!("Encrypted: {}", result2);
}

// PERFORMANCE: When to use each pattern
fn demonstrate_performance_patterns() {
    println!("=== Performance Pattern 1: Avoid Unnecessary Clones ===");

    // SLOW: Cloning large data
    fn process_slow(data: Vec<String>) -> Vec<String> {
        data.into_iter()
            .map(|s| s.to_uppercase()) // Could avoid allocation here
            .collect()
    }

    // FASTER: Work with references when possible
    fn process_fast(data: &[String]) -> Vec<String> {
        data.iter()
            .map(|s| s.to_uppercase())
            .collect()
    }

    let data = vec!["hello".to_string(), "world".to_string()];
    let result = process_fast(&data); // No ownership transfer needed
    println!("Processed: {:?}", result);
    println!("Original still available: {:?}", data);



}

ADVANCED PATTERNS SUMMARY:

  1. SMART POINTERS:

    • Box: Single ownership, heap allocation
    • Rc: Multiple ownership, single thread
    • Arc: Multiple ownership, multi-thread
    • RefCell: Interior mutability with runtime checks
  2. DESIGN PATTERNS:

    • Builder: Consume and return Self for fluent APIs
    • RAII: Automatic resource cleanup with Drop
    • Visitor: Accept trait objects for flexibility
  3. PERFORMANCE PATTERNS:

    • Reference over ownership when possible
    • Cow for conditional allocation

About Me
https://www.linkedin.com/in/kumarabhishek21/


This content originally appeared on DEV Community and was authored by Abhishek Kumar