back

employee db

background

The final section of the eighth chapter of the rust book ends with some suggested exercises. The last of which is to write a program that:

Using a hash map and vectors, create a text interface to allow a user to add employee names to a department in a company; for example, “Add Sally to Engineering” or “Add Amir to Sales.” Then, let the user retrieve a list of all people in a department or all people in the company by department, sorted alphabetically.

solution

Originally, the idea was to wrap an Instruction enum in a Command struct so that we could have a classmethod from_string that could parse user input directly; I was under the impression that an enum couldn’t have a constructor method.

Other than that, I dropped the “to” in the Add commands for simplicity. But, looking back, I didn’t do much to enforce it. If a command started with Add we just take the first 3 words in the input.

use std::collections::HashMap;
use std::io;

#[derive(Debug)]
enum Instruction {
    Add { name: String, department: String },
    View { department: String },
    Unknown
}

#[derive(Debug)]
struct Command {
   instruction: Instruction
}

impl Command {
    fn from_string(input: String) -> Self {
        let words: Vec<&str> = input.split(" ").collect();
        if words[0] == "Add" {
            return Self {
                instruction: Instruction::Add {
                    name: words[1].to_string(),
                    department: words[2].to_string()
                }
            }
        } else if words[0] == "View" {
            return Self {
                instruction: Instruction::View {
                    department: words[1].to_string()
                }
            }
        } else {
            return Self { instruction: Instruction::Unknown }
        }
    }
}

fn main() {
    let mut db = HashMap::new();
    println!("Welcome to the company employee management database!");
    loop {
        println!("Your command: ");
        let mut command = String::new();
        io::stdin()
            .read_line(&mut command)
            .expect("Failed to read line");

        let command = Command::from_string(command.trim().to_string());
        match command.instruction {
            Instruction::Add{name, department} => {
                let department_names = db.entry(department).or_insert(Vec::new());
                department_names.push(name);
            }
            Instruction::View{department} => {
                if department == "All" {
                    for (dept, names) in &mut db {
                        println!("{} department includes:", dept);
                        names.sort();
                        for name in names {
                            println!("{}", name);
                        }
                    }
                } else {
                    println!("{} department includes:", department);

                    let names = db.entry(department).or_insert(Vec::new());
                    names.sort();
                    for name in names {
                        println!("{}", name);
                    }
                }
            }
            Instruction::Unknown => println!("Unknown command...")
        }
    }

Redundant Command struct, repetitive vector printing that could be extracted into a function, and lack of proper exception handling and out of index panics aside, it’s not the worst for 8 chapters in.

We catch unknown commands at least…

mail@jonahv.comrss