3
\$\begingroup\$

Working my way through the second edition of the Rust Programming Language and did the exercise at the end of ch 8:

Using a hash map and vectors, create a text interface to allow a user to add employee names to a department in the 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.

My questions about my code are as follows:

  1. Do I handle errors correctly?
  2. Is the code more or less idiomatic Rust?
  3. Is there a way to make the code more efficient?

lib.rs:

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub mod add_employee;

pub mod department_list;

pub mod company_list;

pub mod selection;

pub mod select_activity;

main.rs:

extern crate company_hr;

use std::collections::HashMap;
use company_hr::selection::*;
use company_hr::add_employee::*;
use company_hr::select_activity::*;
use company_hr::department_list::*;
use company_hr::company_list::*;

fn main() {
    let mut data = HashMap::new();
    loop {
        let activity = select_activity();
        match activity {
            1 => { let data = add_employee(&mut data); continue },
            2 => { println!("List employees from which department?\n");
                let dept = selection_text();
                department_list(&data, &dept); continue },
            3 => { company_list(&data); continue},
            4 => break,
            _ => continue
        }
    }
}

selection.rs:

use std::io;

pub fn selection() -> Result<u32, ::std::num::ParseIntError> {
    let mut selection = String::new();
    io::stdin().read_line(&mut selection).expect("failed to read line");
    selection.trim().parse::<u32>()
}

pub fn selection_text() -> String {
    let mut selection = String::new();
    io::stdin().read_line(&mut selection).expect("failed to read line");
    selection.trim().to_string().to_uppercase()
}

select_activity.rs:

use ::selection::*;

pub fn select_activity() -> u32 {
    println!("Enter '1' to add an employee to a department.\nEnter '2'
            to list employees within a department.\nEnter '3' to list
            all company employees by department.\nEnter '4' to 
            exit.");
    check_activity()

}

pub fn check_activity() -> u32 {
    let selection = selection();
    match selection {
        Ok(i) => i,
        Err(_) => select_again()
    }
}

pub fn select_again() -> u32 {
    println!("Please enter a number 1 through 4.");
    select_activity()

}

add_employee.rs:

use std::collections::HashMap;
use ::selection::*;

pub fn add_employee(mut data: &mut HashMap<String, Vec<String>>)  -> HashMap<String, Vec<String>> {

    loop {
        println!("Please enter the name of the employee you would like 
                 to manage.");

        let employee = selection_text();

        let employee = employee.trim();

        println!("Please enter the name of the department you would 
                 like to add the employee to.");

        let department = selection_text();

        let department = department.trim();

        data.entry(department.to_string())
                .or_insert(vec![])
                .push(employee.to_string());

        match check_continue() {
            1 => continue,
            2 => break,
            _ => match try_again() {
                1 => continue,
                2 => break,
                _ => {println!("Too many errors.  Assuming you wish to
                      exit current function."); break}
            }
        }

    }

    data.to_owned()

}



pub fn select_continue() -> Result<u32, ::std::num::ParseIntError> {
    println!("Enter '1' to add more employees, '2' to finish adding 
            employees.");
    selection()
}

pub fn check_continue() -> u32 {
    let selection = select_continue();
    match selection {
        Ok(i) => i,
        Err(_) => try_again()
    }
}

pub fn try_again() -> u32 {
    println!("Please enter '1' or '2'.");
    check_continue()

}

department_list.rs:

use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub fn department_list(data: &HashMap<String, Vec<String>>, dept: &str) {

    match data.clone().entry(dept.to_string()) {
        Entry::Occupied(mut entry) => {
            let mut vals: Vec<_> = entry.get_mut().iter().collect();
            vals.sort();
            println!("\nEmployees in department {}:", dept);
            for x in vals {
                println!("{}\n", x)
            }
        },
        Entry::Vacant(entry) => {println!("The department {} does not
                                exist or does not have any employees 
                                yet.  You may add departments through 
                                the 'add an employee to a department' 
                                activity.  The current departments 
                                are:", dept);
            let mut keys: Vec<_> = data.keys().collect();
            keys.sort();
            for x in keys {
                println!("{}", x)
            }
        }
    }

}

company_list.rs:

use std::collections::HashMap;
use ::department_list::*;

pub fn company_list(data: &HashMap<String, Vec<String>>) {
    let depts = data.keys();
    println!("Company employees listed by department:");
    for dept in depts {
        department_list(data, dept)
    }
}
\$\endgroup\$
3
  • 2
    \$\begingroup\$ just a small comment. your expect(), and your parse statements seem very likely to crash the program. you might want to use something like unwrap() \$\endgroup\$
    – Rob
    Commented Jan 20, 2019 at 4:04
  • \$\begingroup\$ Thanks for the comment. I guess the non-panic inducing version would be to change the expect() calls to unwrap_or() calls to still get the custom message if unwrap returns a None value. It's been a long time since I thought about this project. Thanks for reminding me about it. I might take another stab at it now that I'm a little more versed in Rust. \$\endgroup\$ Commented Jan 21, 2019 at 20:53
  • 1
    \$\begingroup\$ yeah i was just browsing for some rust implementations from the book. i think it's really good just wanted to let you know someone read it. \$\endgroup\$
    – Rob
    Commented Jan 21, 2019 at 20:53

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.