Rust Reference: Comprehensive Developer's Guide

// ---------------------------------------------------------------------------------
// Rust Programming Guide
//
// ReferenceCollection.com
// Licensed under CC BY-SA
// ---------------------------------------------------------------------------------

// TABLE OF CONTENTS
// -----------------
// 1.  Introduction to Rust
// 2.  Basic Syntax and Structure
// 3.  Data Types and Variables
// 4.  Ownership and Borrowing
// 5.  Control Flow
// 6.  Functions and Methods
// 7.  Structs and Enums
// 8.  Collections
// 9.  Error Handling
// 10. Traits and Generics
// 11. Lifetimes
// 12. Modules and Crates
// 13. Testing
// 14. Concurrency
// 15. Smart Pointers
// 16. Macros
// 17. Unsafe Rust
// 18. Advanced Topics
// 19. Common Rust Patterns
// 20. Performance and Optimization

// ---------------------------------------------------------------------------------
// 1. Introduction to Rust
// ---------------------------------------------------------------------------------

// Rust is a systems programming language that emphasizes safety, concurrency, and 
// performance. It achieves memory safety without garbage collection through its 
// unique ownership system and provides zero-cost abstractions for building reliable
// and efficient software.

// Key Features:
// - Memory Safety: Prevents common programming errors like null pointer dereferencing,
//   buffer overflows, and data races at compile time
// - Zero-cost Abstractions: High-level features that compile to efficient low-level code
// - Concurrency: Safe concurrent programming through ownership and type system
// - Performance: C-like performance with modern language features
// - Reliability: Strong type system and compile-time guarantees
// - Modern Tooling: Integrated package manager (Cargo), documentation generator (rustdoc),
//   and formatting tool (rustfmt)

// Getting Started:
// 1. Install Rust:
//    - Visit https://rustup.rs/
//    - Follow installation instructions for your platform
// 2. Verify installation:
//    - Run `rustc --version` in terminal
// 3. Create new project:
//    - Run `cargo new project_name`
//    - CD into project directory
// 4. Build and run:
//    - Use `cargo build` to compile
//    - Use `cargo run` to compile and execute
// 5. Package management:
//    - Use `cargo add package_name` to add dependencies
//    - Edit Cargo.toml for manual dependency management

// Basic Project Structure:
// project_name/
// ├── Cargo.toml      // Project metadata and dependencies
// ├── src/
// │   └── main.rs     // Main entry point
// └── target/         // Build artifacts

// Example of a basic Rust program:
fn main() {
    println!("Hello, Rust!");
}

// ---------------------------------------------------------------------------------
// 2. Basic Syntax and Structure
// ---------------------------------------------------------------------------------

// Rust programs consist of functions, statements, and expressions. The main function
// is the entry point of every executable Rust program. The language emphasizes 
// explicit over implicit behavior and provides strong static typing with type inference.

// Comments:
// - Single-line comments start with //
// - Multi-line comments use /* ... */
// - Documentation comments use /// or //! (generate documentation)

/// This is a documentation comment that generates documentation for the following item
fn documented_function() {
    println!("This function has documentation!");
}

// Statements and Expressions:
// - Statements perform actions but don't return values
// - Expressions evaluate to a value
// - Last expression in a block becomes its return value

fn expression_example() {
    let x = 5;          // Statement
    let y = {           // Expression block
        let z = 3;
        z + 1           // Expression (returns 4)
    };
    println!("y is: {}", y);
}

// Variables:
// - Declared using 'let'
// - Immutable by default
// - Type inference available
// - Explicit type annotations use ':'

let immutable = 42;             // Immutable variable
let mut mutable = 42;           // Mutable variable
let typed: i32 = 42;           // Explicit type annotation
let inferred = 42;             // Type inferred as i32

// Constants:
// - Declared using 'const'
// - Must have type annotation
// - Value must be known at compile time

const MAX_POINTS: u32 = 100_000;

// ---------------------------------------------------------------------------------
// 3. Data Types and Variables
// ---------------------------------------------------------------------------------

// Rust is statically typed, meaning all variables must have known types at compile time.
// The compiler can often infer types, but explicit annotations are sometimes needed.
// Understanding Rust's type system is crucial for writing efficient and safe code.

// Scalar Types:
// ------------

// Integers:
let signed: i32 = -42;         // Signed 32-bit integer
let unsigned: u32 = 42;        // Unsigned 32-bit integer
let byte: u8 = b'A';           // Byte (u8)

// Integer types:
// - Signed: i8, i16, i32, i64, i128, isize (pointer-sized)
// - Unsigned: u8, u16, u32, u64, u128, usize (pointer-sized)

// Integer literals:
let decimal = 98_222;          // Decimal
let hex = 0xff;                // Hexadecimal
let octal = 0o77;              // Octal
let binary = 0b1111_0000;      // Binary

// Floating-point:
let float32: f32 = 3.14;       // 32-bit float
let float64: f64 = 2.71828;    // 64-bit float (default)

// Boolean:
let boolean: bool = true;       // true or false

// Character:
let character: char = 'A';      // Unicode scalar value (4 bytes)

// Compound Types:
// -------------

// Tuples:
let tup: (i32, f64, char) = (500, 6.4, 'A');
let (x, y, z) = tup;           // Destructuring
let first = tup.0;             // Access by index

// Arrays:
let array: [i32; 5] = [1, 2, 3, 4, 5];  // Fixed-size array
let repeated = [3; 5];         // [3, 3, 3, 3, 3]

// Slices:
let slice = &array[1..4];      // Reference to part of array

// Strings:
let string_literal = "hello";   // String literal (&str)
let string = String::from("hello"); // Owned String

// Type Aliases:
type Distance = f64;           // Create type alias
let distance: Distance = 5.0;

// ---------------------------------------------------------------------------------
// 4. Ownership and Borrowing
// ---------------------------------------------------------------------------------

// Ownership is Rust's innovative approach to memory management, ensuring memory safety
// without garbage collection. It's based on a set of rules checked at compile time,
// preventing common programming errors like use-after-free and data races.

// Ownership Rules:
// 1. Each value has exactly one owner
// 2. Only one owner at a time
// 3. When owner goes out of scope, value is dropped

// Example of Ownership:
fn ownership_example() {
    let s1 = String::from("hello");    // s1 owns the string
    let s2 = s1;                       // Value moved to s2
    // println!("{}", s1);             // Error: s1 no longer valid
    println!("{}", s2);                // Works fine
}

// Borrowing:
// - References allow using a value without taking ownership
// - References are immutable by default
// - Only one mutable reference OR any number of immutable references at a time

// Immutable Borrowing:
fn calculate_length(s: &String) -> usize {
    s.len()
}

let s1 = String::from("hello");
let len = calculate_length(&s1);       // Borrow s1

// Mutable Borrowing:
fn change(s: &mut String) {
    s.push_str(", world");
}

let mut s = String::from("hello");
change(&mut s);

// Reference Rules:
// 1. References must always be valid (no dangling references)
// 2. References must be one of:
//    - One mutable reference
//    - Any number of immutable references
// 3. References must not outlive their referent

// ---------------------------------------------------------------------------------
// 5. Control Flow
// ---------------------------------------------------------------------------------

// Rust provides several control flow constructs for controlling program execution.
// These include conditional statements, loops, and pattern matching through the
// match expression.

// If Expressions:
let number = 7;

if number < 5 {
    println!("condition was true");
} else {
    println!("condition was false");
}

// If in a Let Statement:
let condition = true;
let number = if condition { 5 } else { 6 };

// Loops:
// Three types of loops: loop, while, and for

// Infinite Loop with Break:
let mut counter = 0;
let result = loop {
    counter += 1;
    if counter == 10 {
        break counter * 2;
    }
};

// While Loop:
let mut number = 3;
while number != 0 {
    println!("{}!", number);
    number -= 1;
}

// For Loop:
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
    println!("the value is: {}", element);
}

// Range-based For Loop:
for number in 1..4 {
    println!("{}", number);
}

// Match Expression:
// Pattern matching with match is exhaustive and must cover all possibilities
let number = 6;
match number {
    1 => println!("One"),
    2 => println!("Two"),
    3..=5 => println!("Three to Five"),
    _ => println!("Something else"),
}

// ---------------------------------------------------------------------------------
// 6. Functions and Methods
// ---------------------------------------------------------------------------------

// Functions are the primary building blocks of Rust code. They can take parameters,
// return values, and serve as the core organizational unit of code. Methods are
// functions associated with a particular type.

// Basic Function:
fn greet(name: &str) {
    println!("Hello, {}!", name);
}

// Function with Return Value:
fn add(a: i32, b: i32) -> i32 {
    a + b       // Implicit return (no semicolon)
}

// Methods:
// Functions associated with a type, defined in impl blocks
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // Associated function (static method)
    fn new(width: u32, height: u32) -> Rectangle {
        Rectangle { width, height }
    }

    // Method (takes &self)
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // Mutable method
    fn resize(&mut self, width: u32, height: u32) {
        self.width = width;
        self.height = height;
    }
}

// ---------------------------------------------------------------------------------
// 7. Structs and Enums
// ---------------------------------------------------------------------------------

// Structs and enums are the building blocks for creating custom data types in Rust.
// They allow you to create complex data structures that group related data together.

// Regular struct:
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

// Creating struct instance:
let user1 = User {
    email: String::from("[email protected]"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

// Tuple structs:
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

// Unit structs:
struct AlwaysEqual;

// Enums:
// Define a type by enumerating its possible variants
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

// Using enums with match:
let home = IpAddr::V4(127, 0, 0, 1);

match home {
    IpAddr::V4(a, b, c, d) => println!("{}.{}.{}.{}", a, b, c, d),
    IpAddr::V6(addr) => println!("{}", addr),
}

// Option enum:
// Built-in enum for handling nullable values
let some_number = Some(5);
let absent_number: Option<i32> = None;

// ---------------------------------------------------------------------------------
// 8. Collections
// ---------------------------------------------------------------------------------

// Rust's standard library includes several collection types that provide ways to
// store multiple values. Unlike arrays, these collections are stored on the heap
// and can grow or shrink at runtime.

// Vectors:
// Growable arrays
let mut vec: Vec<i32> = Vec::new();
vec.push(1);
vec.push(2);

// Vector with initial values:
let vec = vec![1, 2, 3];

// Accessing elements:
let third: &i32 = &vec[2];
let third: Option<&i32> = vec.get(2);

// Strings:
// UTF-8 encoded, growable text
let mut s = String::from("hello");
s.push_str(", world!");

// Hash Maps:
use std::collections::HashMap;

let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);

// Accessing values:
let team_name = String::from("Blue");
let score = scores.get(&team_name);

// Updating values:
scores.entry(String::from("Blue")).or_insert(50);

// ---------------------------------------------------------------------------------
// 9. Error Handling
// ---------------------------------------------------------------------------------

// Rust groups errors into two categories: recoverable errors using Result<T, E>
// and unrecoverable errors using panic!. This approach ensures robust error handling
// while maintaining program reliability.

// Result enum:
enum Result<T, E> {
    Ok(T),    // Success case with value of type T
    Err(E),   // Error case with error of type E
}

// Example using Result:
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err(String::from("Division by zero"))
    } else {
        Ok(a / b)
    }
}

// Using match with Result:
match divide(10.0, 2.0) {
    Ok(result) => println!("Result: {}", result),
    Err(e) => println!("Error: {}", e),
}

// Using ? operator for error propagation:
fn read_username_from_file() -> Result<String, std::io::Error> {
    let mut file = std::fs::File::open("username.txt")?;
    let mut username = String::new();
    file.read_to_string(&mut username)?;
    Ok(username)
}

// Panic:
// For unrecoverable errors
// panic!("crash and burn");

// Custom error types:
#[derive(Debug)]
struct AppError {
    kind: String,
    message: String,
}

// ---------------------------------------------------------------------------------
// 10. Traits and Generics
// ---------------------------------------------------------------------------------

// Traits define shared behavior across types, similar to interfaces in other languages.
// Generics provide a way to write flexible, reusable code that works with different types
// while maintaining type safety.

// Traits: Define shared behavior
trait Summary {
    fn summarize(&self) -> String;
    
    // Default implementation
    fn default_summary(&self) -> String {
        String::from("(Read more...)")
    }
}

// Implementing a trait
struct NewsArticle {
    headline: String,
    location: String,
    author: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

// Generic Functions with Trait Bounds
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

// Generic Structs
struct Point<T> {
    x: T,
    y: T,
}

// ---------------------------------------------------------------------------------
// 11. Lifetimes
// ---------------------------------------------------------------------------------

// Lifetimes are Rust's way of ensuring that references are valid for the duration
// they're used. Every reference in Rust has a lifetime, which is the scope for
// which that reference is valid.

// Lifetime Annotation Syntax:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

// Struct with Lifetime Annotation:
struct ImportantExcerpt<'a> {
    part: &'a str,
}

// Lifetime Elision Rules:
// 1. Each parameter gets its own lifetime
// 2. If there is exactly one input lifetime, it is assigned to all outputs
// 3. If there is a &self parameter, its lifetime is assigned to all outputs

// ---------------------------------------------------------------------------------
// 12. Modules and Crates
// ---------------------------------------------------------------------------------

// Modules help organize code into logical units, while crates are the smallest
// amount of code that the Rust compiler considers at a time. Modules control
// privacy and provide namespace separation.

// Module Definition:
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
        
        fn seat_at_table() {}
    }
}

// Using modules:
use crate::front_of_house::hosting;

// Re-exporting names:
pub use crate::front_of_house::hosting;

// Nested paths:
use std::{cmp::Ordering, io};

// The glob operator:
use std::collections::*;

// Creating a library crate:
// In lib.rs:
pub mod client;
pub mod network;

// ---------------------------------------------------------------------------------
// 13. Testing
// ---------------------------------------------------------------------------------

// Rust has built-in support for unit testing, integration testing, and
// documentation testing. Tests are functions annotated with the #[test] attribute.

// Unit Tests:
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }

    #[test]
    #[should_panic(expected = "panic message")]
    fn test_panic() {
        panic!("panic message");
    }
    
    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle { width: 8, height: 7 };
        let smaller = Rectangle { width: 5, height: 1 };
        assert!(larger.can_hold(&smaller));
    }
}

// Integration Tests:
// In tests/integration_test.rs:
use my_crate;

#[test]
fn it_adds_two() {
    assert_eq!(4, my_crate::add_two(2));
}

// Documentation Tests:
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
    x + 1
}

// ---------------------------------------------------------------------------------
// 14. Concurrency
// ---------------------------------------------------------------------------------

// Rust's ownership and type systems guarantee thread safety and prevent data races.
// The language provides multiple tools for concurrent programming, including threads,
// message passing, and shared state concurrency.

// Threads:
use std::thread;
use std::time::Duration;

let handle = thread::spawn(|| {
    for i in 1..10 {
        println!("hi number {} from the spawned thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
});

// Message Passing:
use std::sync::mpsc;

let (tx, rx) = mpsc::channel();

thread::spawn(move || {
    tx.send(String::from("hello")).unwrap();
});

println!("Got: {}", rx.recv().unwrap());

// Mutual Exclusion:
use std::sync::Mutex;

let m = Mutex::new(5);
{
    let mut num = m.lock().unwrap();
    *num = 6;
}

// ---------------------------------------------------------------------------------
// 15. Smart Pointers
// ---------------------------------------------------------------------------------

// Smart pointers are data structures that act like pointers but include additional
// metadata and capabilities. They often own the data they point to.

// Box<T>: Heap allocation
let b = Box::new(5);

// Rc<T>: Reference counting
use std::rc::Rc;

let rc = Rc::new(String::from("shared data"));
let rc2 = Rc::clone(&rc);

// RefCell<T>: Interior mutability
use std::cell::RefCell;

let data = RefCell::new(5);
*data.borrow_mut() = 6;

// Custom Smart Pointer:
struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

// ---------------------------------------------------------------------------------
// 16. Macros
// ---------------------------------------------------------------------------------

// Macros are a way of writing code that writes other code, known as metaprogramming.
// Rust provides several types of macros: declarative macros and procedural macros.

// Declarative Macros:
macro_rules! say_hello {
    () => {
        println!("Hello!");
    };
    ($name:expr) => {
        println!("Hello, {}!", $name);
    };
}

// Using macros:
say_hello!();           // Prints: Hello!
say_hello!("Rust");     // Prints: Hello, Rust!

// Procedural Macros:
// These are more complex and require a separate crate
#[derive(Debug)]     // Example of a derive macro
struct Point {
    x: i32,
    y: i32,
}

// ---------------------------------------------------------------------------------
// 17. Unsafe Rust
// ---------------------------------------------------------------------------------

// Unsafe Rust exists to perform operations that the compiler cannot guarantee are safe.
// It's necessary for low-level programming and interfacing with other languages.

// Unsafe blocks allow:
// 1. Dereferencing raw pointers
// 2. Calling unsafe functions
// 3. Implementing unsafe traits
// 4. Mutating static variables
// 5. Accessing fields of unions

unsafe fn dangerous() {
    // Unsafe operations here
}

unsafe {
    dangerous();
}

// Raw Pointers:
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;

unsafe {
    println!("r1 is: {}", *r1);
    *r2 = 6;
}

// ---------------------------------------------------------------------------------
// 18. Advanced Topics
// ---------------------------------------------------------------------------------

// Advanced Type System Features:

// Type Aliases:
type Kilometers = i32;
let distance: Kilometers = 5;

// Never Type:
fn bar() -> ! {
    panic!("This function never returns!");
}

// Sized Trait:
fn generic<T: ?Sized>(t: &T) {
    // This function can take unsized types
}

// Associated Types:
trait Container {
    type Item;
    fn get(&self) -> &Self::Item;
}

// ---------------------------------------------------------------------------------
// 19. Common Rust Patterns
// ---------------------------------------------------------------------------------

// Builder Pattern:
struct Builder {
    field1: Option<i32>,
    field2: Option<String>,
}

impl Builder {
    fn new() -> Builder {
        Builder {
            field1: None,
            field2: None,
        }
    }

    fn field1(mut self, value: i32) -> Builder {
        self.field1 = Some(value);
        self
    }

    fn field2(mut self, value: String) -> Builder {
        self.field2 = Some(value);
        self
    }
}

// RAII (Resource Acquisition Is Initialization):
struct Resource {
    data: String,
}

impl Drop for Resource {
    fn drop(&mut self) {
        println!("Cleaning up resource!");
    }
}

// ---------------------------------------------------------------------------------
// 20. Performance and Optimization
// ---------------------------------------------------------------------------------

// Zero-Cost Abstractions:
fn zero_cost_example<T: Iterator<Item = i32>>(iter: T) -> i32 {
    iter.filter(|&x| x > 0)
        .map(|x| x * 2)
        .sum()
}

// Memory Layout Optimization:
#[repr(C)]
struct Aligned {
    a: u8,
    b: u32,
    c: u16,
}

// Compile-Time Evaluation:
const fn compile_time_fn(x: u32) -> u32 {
    x * 2
}

const COMPUTED: u32 = compile_time_fn(21);

// Happy coding
Licensed under
CC BY-SA 4.0