Basic questions after first mini-application

Thanks all! I learned a lot from your replies. I optimized my code using generics and traits.

//Module holding all the structs, enumerations,...
pub mod domain {
    
    use std::string::ToString;

    pub struct Cat {
        name: String,
        age: u8,
        color: CatColor,
        race: CatRace,
    }
    impl Cat {
        pub fn new(name: String, age: u8, color: CatColor, race: CatRace) -> Cat {
            Cat {
                name: name,
                age: age,
                color: color,
                race: race,
            }
        }

        pub fn to_string(&self) -> String {
            let mut s : String = String::new();
            s = format!("Name: {name}\nAge: {age}\nColor: {color}\nRace: {race}",
                    name = self.name,
                    age = self.age,
                    color = self.color.to_string(),
                    race = self.race.to_string(),
                );

            s
        }
    }

    #[derive(Display, Debug)]
    pub enum CatColor {
        Black,
        White,
        Orange,
        Gray,
    }
    impl CatColor {
        pub fn from_u8(value: u8) -> CatColor {
            match value {
                1 => CatColor::Black,
                2 => CatColor::White,
                3 => CatColor::Orange,
                4 => CatColor::Gray,
                _ => {
                    eprintln!("Invalid CatColor selected!");
                    std::process::exit(0);
                }
            }
        }
        
    }

    #[derive(Display, Debug)]
    pub enum CatRace {
        Streetcat,
        AmericanShorthair,
        BritishShorthair,
        Bengal,
        EgyptianMau,
    }
    impl CatRace {
        pub fn from_u8(value: u8) -> CatRace {
            match value {
                1 => CatRace::Streetcat,
                2 => CatRace::AmericanShorthair,
                3 => CatRace::BritishShorthair,
                4 => CatRace::Bengal,
                5 => CatRace::EgyptianMau,
                _ => {
                    eprintln!("Invalid CatRace selected!");
                    std::process::exit(0);
                }
            }
        }
    }
}

//Module holding functions necessary for the userinterface
pub mod user_interface {

    pub mod display {
        use std::io;
        
        //Function to display the start menu
        pub fn display_start_menu() {
            println!("Welcome to the cat database!");
            println!("1) Add cat");
            println!("2) View all cats");
        }

        //Function to display add-cat-menu
        pub fn display_add_cat_menu() {
            println!("Give all the info about the cat!");
        }

        //Function to display view-all-cats-menu
        pub fn display_view_all_cats_menu() {
            println!("List of all the cats:");
        }

        //Function to flush std output
        pub fn flush() {
            io::Write::flush(&mut io::stdout());
        }
    }

    pub mod input {
        use std::io;
        use std::io::stdin;
        use std::str::FromStr;

        //Function to get user input
        pub fn get<T: FromStr>() -> T {
            print!(">");
            //Flush display
            io::Write::flush(&mut io::stdout());

            //Get input and put it in mutable string
            let mut input = String::new();
            stdin()
                .read_line(&mut input)
                .expect("No valid input given...");
    
            match input.trim().parse() {
                Ok(i) => i,
                Err(..) => {
                    eprintln!("Corrupted input '{}' given!", input);
                    std::process::exit(0);
                }
            }
        }
    }
}

//Module to access, read, and write data
pub mod data_layer {
    use std::vec::Vec;
    use crate::domain::*;

    //Trait to generalize the different type of data management options
    pub trait DataManager {
        //Initialize data manager
        fn new() -> Self;

        //Add to the database
        fn add(&mut self, cat: Cat) -> bool;

        //Read from the database
        fn read(&mut self) -> &Vec<Cat>;
    }

    //To manage data in memory
    pub struct MemoryData {
        cats: Vec<Cat>,
    }
    impl DataManager for MemoryData {
        fn new() -> MemoryData {
            MemoryData { cats: Vec::new() }
        }
        fn add(&mut self, cat: Cat) -> bool {
            self.cats.push(cat);
            true
        }
        fn read(&mut self) -> &Vec<Cat> {
            &self.cats
        }
    }

    //*TO ADD:* Struct to manage data in text file and database
    //will follow
}

//Module holding logic and binding everything together
pub mod app {
    use crate::user_interface;
    use crate::data_layer;
    use crate::domain::*;

    //Run the application
    pub fn run(db: &mut data_layer::MemoryData) {
        user_interface::display::display_start_menu();
        let option: u8 = user_interface::input::get();
        execute_option(option, db);
        
    }

    //Execute the selected option with corresponding function
    pub fn execute_option<D: data_layer::DataManager>(option: u8, db: &mut D) {
        match option {
            1 => {
               add_cat(db); 
            }
            2 => {
                view_all_cats(db);
            }
            _ => {
                eprintln!("Invalid option '{}' selected...", option);
            }
        }
    }

    //Function to add a cat
    pub fn add_cat<D: data_layer::DataManager>(db: &mut D) {
        //Displaying menu header
        user_interface::display::display_add_cat_menu();

        //Getting al the info
        println!("Name:");
        let name: String = user_interface::input::get();

        println!("Age:");
        let age: u8 = user_interface::input::get();

        println!("Color:\n1) Black 2) White 3) Orange 4) Gray");
        let color: CatColor = CatColor::from_u8(user_interface::input::get());
        
        println!("Race:\n1) Streetcat 2) American Shorthair 3) British Shorthair 4) Bengal 5) Egyptian Mau");
        let race: CatRace = CatRace::from_u8(user_interface::input::get());

        //Create cat object
        let cat: Cat = Cat::new(name, age, color, race);

        //Save cat object
        db.add(cat);

        println!("Cat added...");
    }

    //Function to view all cats
    pub fn view_all_cats<D: data_layer::DataManager>(db: &mut D) {
        //Displaying menu header
        user_interface::display::display_view_all_cats_menu();
        //user_interface::display::flush();
        std::io::Write::flush(&mut std::io::stdout());

        //Reading, iterating over, and outputting all the cats
        for cat in db.read() {
            println!("{}", cat.to_string());
        }

    }
}

//Crates
extern crate strum;
#[macro_use]
extern crate strum_macros;

fn main() {
    use crate::data_layer::DataManager;

    //Initialize database
    let ref mut db = data_layer::MemoryData::new();

    while true {
        app::run(db);
    }
}
1 Like