2
\$\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\$
  • 1
    \$\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 Jan 20 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\$ – Matthew Stevenson Jan 21 at 20:53
  • \$\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 Jan 21 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.