rust_programming_book 0.1.1

Programming works from THE RUST PROGRAMMING LANGUAGE
Documentation
use chrono::{DateTime, Local};
use rand::Rng;
/**

 * here polymorphism means returning or using traits as a function parameter.
 * It is used when we don't know the type of trait (struct) in compile time.
 */
#[allow(dead_code)]
pub trait PersonData {
    fn is_valid(&self) -> bool;

    fn get_type(&self) -> &str;
}

#[allow(dead_code)]
#[derive(Debug)]
pub struct SurajData<'a> {
    name: &'a str,
    age: i8,
    pokhrel_data: PokhrelData<'a>,
    some_bool: bool,
    data_name: &'a str,
}

#[derive(Debug)]
pub struct PokhrelData<'a> {
    uniqueness: bool,
    data_name: &'a str,
}

impl<'a> PersonData for SurajData<'a> {
    fn is_valid(&self) -> bool {
        self.some_bool
    }
    fn get_type(&self) -> &str {
        self.data_name
    }
}

impl<'a> PersonData for PokhrelData<'a> {
    fn is_valid(&self) -> bool {
        self.uniqueness
    }
    fn get_type(&self) -> &str {
        self.data_name
    }
}

#[allow(dead_code)]
fn check_if_valid(person_data: &dyn PersonData) {
    if person_data.is_valid() {
        println!("Yes, valid!");
    }
}

#[allow(dead_code)]
fn check_better_data<'a>(
    data1: &'a dyn PersonData,
    data2: &'a dyn PersonData,
) -> &'a dyn PersonData {
    if rand::thread_rng().gen_range(1..=5) > 2 {
        data1
    } else {
        data2
    }
}

#[allow(dead_code)]
pub fn polymorphism() {
    let suraj_data = SurajData {
        name: "suraj",
        age: 20,
        pokhrel_data: PokhrelData {
            uniqueness: true,
            data_name: "pokhrel data",
        },
        some_bool: true,
        data_name: "suraj data",
    };

    let pokhrel_data = PokhrelData {
        uniqueness: false,
        data_name: "pokhrel data",
    };

    check_if_valid(&suraj_data);
    check_if_valid(&pokhrel_data);

    let better_data = check_better_data(&suraj_data, &pokhrel_data);

    println!(
        "better data is : {} and is valid: {}",
        better_data.get_type(),
        better_data.is_valid()
    );
}

/*
Second example of polymorphism but here a function is defined for enum using implementation
for enum
*/
#[allow(dead_code)]
pub enum PaymentType {
    Cash(f32),
    Cheque(i32),
    Debit {
        debit_number: i32,
        date_of_transaction: DateTime<Local>,
    },
    Bitcoin {
        hash: String,
        sender_id: u32,
    },
}

impl PaymentType {
    fn checkout(payment_type: PaymentType) {
        match payment_type {
            Self::Cash(cash_amt) => println!("Cash payment: ${}", cash_amt),
            Self::Cheque(check_num) => println!("Cheque payment, check number: {}", check_num),
            Self::Bitcoin { hash, sender_id } => {
                println!("Bitcoin payment\nhash: {}\nsender id: {}", hash, sender_id)
            }
            Self::Debit {
                debit_number,
                date_of_transaction,
            } => {
                println!(
                    "Debit payment\ndebit number: {}\ndate of transaction: {}",
                    debit_number, date_of_transaction
                )
            }
        }
    }
}
#[allow(dead_code)]
pub fn payment() {
    let payment1 = PaymentType::Cash(500.);
    let payment2 = PaymentType::Bitcoin {
        hash: "2345234lksjflaack2534".to_string(),
        sender_id: 91,
    };
    let payment3 = PaymentType::Debit {
        debit_number: 2311,
        date_of_transaction: Local::now(),
    };

    PaymentType::checkout(payment1);
    PaymentType::checkout(payment2);
    PaymentType::checkout(payment3);
}