Common pattern matching usage in Rust

use std::time::{SystemTime, UNIX_EPOCH};

#[allow(dead_code)]
enum Temperature<T> {
    Celsius(T),
    Fahrenheit(f32),
}
use std::arch::asm;

use Temperature::Celsius;
use Temperature::Fahrenheit;

struct Point {
    x: i32,
    y: i32,
}

fn generate_random_number() -> i32 {
    let since_epoch = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    let seed = since_epoch.as_secs();

    (seed % 101) as i32
}

fn main() {
    //destructing
    //enum 
    //guards
    let temperature = Temperature::Celsius(35);
    match temperature {
        Temperature::Celsius(t) if t > 30 => {
            println!("{}C is above 30 Celsius", t)
        },
        // The `if condition` part ^ is a guard
        Temperature::Celsius(t) => {
            println!("{}C is equal to or below 30 Celsius", t)
        },
        Temperature::Fahrenheit(t) if t > 86.0 => {
            println!("{}F is above 86 Fahrenheit", t)
        },
        Temperature::Fahrenheit(t) => {
            println!("{}F is equal to or below 86 Fahrenheit", t)
        } 
    }
    // unsafe  {
    //     asm!("int 3");
    // }
    //struct
    let point = Point { x: 10, y: 20 };
    match point {
        Point { x, y } => println!("Point at ({}, {})", x, y),
    }

    //tuple
    let tuple = (1, 2, 3);
    match tuple {
        (x, y, z) => println!("Tuple values: {}, {}, {}", x, y, z),
    }

    //array
    let array = [1, 2, 3];
    match array {
        [first, second, ..] => println!("First: {}, Second: {}", first, second),
        _ => println!("Not a match"),
    }
    
    let number = 4;
    match number {
        n if n % 2 == 0 => println!("Even number: {}", n),
        n => println!("Odd number: {}", n),
    }

    //pointer/reference
    // Assign a reference of type `i32`. The `&` signifies there
    // is a reference being assigned.
    let reference = &4;
    match reference {
        // If `reference` is pattern matched against `&val`, it results
        // in a comparison like:
        // `&i32`
        // `&val`
        // ^ We see that if the matching `&`s are dropped, then the `i32`
        // should be assigned to `val`.
        &val => println!("Got a value via destructuring: {:?}", val),
    }

    // To avoid the `&`, you dereference before matching.
    match *reference {
        val => println!("Got a value via dereferencing: {:?}", val),
    }

    // Accordingly, by defining 2 values without references, references
    // can be retrieved via `ref` and `ref mut`.
    let value = 5;
    let mut mut_value = 6;

    // Use `ref` keyword to create a reference.
    match value {
        ref r => println!("Got a reference to a value: {:?}", r),
    }

    // Use `ref mut` similarly.
    match mut_value {
        ref mut m => {
            // Got a reference. Gotta dereference it before we can
            // add anything to it.
            *m += 10;
            println!("We added 10. `mut_value`: {:?}", m);
        },
    }

    //if let
    let option_value: Option<i32> = Some(5);
    if let Some(v) = option_value {
        println!("Got a value: {}", v);
    }

    //whie let
    while let Some(v) = option_value {
        println!("Still got a value: {}", v);
        break;
    }

    //let-else
    let t = (Temperature::Celsius(35), Temperature::<f32>::Fahrenheit(35.0));
    let (Celsius(t0), Fahrenheit(t1)) = t else {
        panic!("Destructing failed!\n");
    };
    print!("t0 = {}, t1 = {}\n", t0, t1);

    //binding
    println!("Tell me what type of person you are");
    let age = generate_random_number();
    match age {
        0             => println!("I haven't celebrated my first birthday yet"),
        // Could `match` 1 ..= 12 directly but then what age
        // would the child be? Instead, bind to `n` for the
        // sequence of 1 ..= 12. Now the age can be reported.
        n @ 1  ..= 12 => println!("I'm a child of age {:?}", n),
        n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
        // Nothing bound. Return the result.
        n             => println!("I'm an old person of age {:?}", n),
    }
    unsafe  {
        asm!("int 3");
    }
}