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);
}
}