#![allow(unused)]
fn main() {
use std::collections::HashMap;
use std::convert::From;
use std::ops::Add;
pub struct Inventory {
items: HashMap<String, u32>,
}
impl From<Vec<(String, u32)>> for Inventory {
fn from(items: Vec<(String, u32)>) -> Self {
let mut inventory = HashMap::new();
for (name, qty) in items {
inventory.insert(name, qty);
}
Self { items: inventory }
// We will learn more about iterators in day 4, but here is a more idiomatic way to do the above:
// Self {
// items: items.into_iter().collect(),
// }
}
}
impl Add for Inventory {
type Output = Inventory;
fn add(self, other: Inventory) -> Inventory {
let mut combined = self.items;
for (name, qty) in other.items {
// This is a more idiomatic way to do the following:
// match combined.get(&name) {
// Some(existing_qty) => {
// combined.insert(name, existing_qty + qty);
// }
// None => {
// combined.insert(name, qty);
// }
// }
*combined.entry(name).or_insert(0) += qty;
}
Self { items: combined }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_vec() {
let items = vec![("apple".to_string(), 10), ("banana".to_string(), 20)];
let inventory: Inventory = items.into();
let expected: HashMap<String, u32> =
[("apple".to_string(), 10), ("banana".to_string(), 20)]
.iter()
.cloned()
.collect();
assert_eq!(inventory.items, expected);
}
#[test]
fn test_from_empty_vec() {
let items: Vec<(String, u32)> = Vec::new();
let inventory: Inventory = items.into();
let expected: HashMap<String, u32> = HashMap::new();
assert_eq!(inventory.items, expected);
}
#[test]
fn test_add() {
let items1 = vec![("apple".to_string(), 10), ("banana".to_string(), 20)];
let items2 = vec![("banana".to_string(), 5), ("orange".to_string(), 15)];
let inventory1: Inventory = items1.into();
let inventory2: Inventory = items2.into();
let combined_inventory = inventory1 + inventory2;
let expected: HashMap<String, u32> = [
("apple".to_string(), 10),
("banana".to_string(), 25),
("orange".to_string(), 15),
]
.iter()
.cloned()
.collect();
assert_eq!(combined_inventory.items, expected);
}
#[test]
fn test_add_empty_inventories() {
let inventory1: Inventory = Vec::new().into();
let inventory2: Inventory = Vec::new().into();
let combined_inventory = inventory1 + inventory2;
let expected: HashMap<String, u32> = HashMap::new();
assert_eq!(combined_inventory.items, expected);
}
#[test]
fn test_add_non_empty_with_empty_inventory() {
let items = vec![("apple".to_string(), 10), ("banana".to_string(), 20)];
let inventory1: Inventory = items.into();
let inventory2: Inventory = Vec::new().into();
let combined_inventory = inventory1 + inventory2;
let expected: HashMap<String, u32> =
[("apple".to_string(), 10), ("banana".to_string(), 20)]
.iter()
.cloned()
.collect();
assert_eq!(combined_inventory.items, expected);
}
#[test]
fn test_add_empty_with_non_empty_inventory() {
let items = vec![("apple".to_string(), 10), ("banana".to_string(), 20)];
let inventory1: Inventory = Vec::new().into();
let inventory2: Inventory = items.into();
let combined_inventory = inventory1 + inventory2;
let expected: HashMap<String, u32> =
[("apple".to_string(), 10), ("banana".to_string(), 20)]
.iter()
.cloned()
.collect();
assert_eq!(combined_inventory.items, expected);
}
}
}