use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; use std::collections::HashSet; use std::hash::{Hash, Hasher}; #[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)] pub struct Item { pub name: String, } impl Item { pub fn new(name: &str) -> Self { Self { name: name.to_string(), } } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ItemListing { pub item: Item, pub price: u32, pub count_per_price: u32, pub restocked_time: DateTime, pub out_of_stock_votes: HashSet, } impl ItemListing { pub fn new(item: &str, price: u32, count_per_price: u32) -> Self { Self { item: Item { name: item.to_string(), }, price, count_per_price, restocked_time: Utc::now(), out_of_stock_votes: HashSet::default(), } } pub fn normalized_price(&self) -> f32 { if self.count_per_price == 0 { f32::MAX } else { (self.price as f32) / (self.count_per_price as f32) } } pub fn order_by_price(a: &Self, b: &Self) -> Ordering { // Bit of a hack so we can using integer ordering let a_price = (a.normalized_price() * 1000.0) as u64; let b_price = (b.normalized_price() * 1000.0) as u64; a_price.cmp(&b_price) } pub fn order_by_restock(a: &Self, b: &Self) -> Ordering { a.restocked_time.cmp(&b.restocked_time) } pub fn report_out_of_stock(&mut self, id: u64) { self.out_of_stock_votes.insert(id); } pub fn is_out_of_stock(&self, report_limit: u32) -> bool { self.out_of_stock_votes.len() >= report_limit as usize } pub fn restock(&mut self) { self.restocked_time = Utc::now(); self.out_of_stock_votes.clear(); } } impl Hash for ItemListing { fn hash(&self, state: &mut H) { self.item.name.hash(state); self.price.hash(state); self.count_per_price.hash(state); } } impl PartialEq for ItemListing { fn eq(&self, other: &Self) -> bool { (self.item.name == other.item.name) && (self.price == other.price) && (self.count_per_price == other.count_per_price) } } impl Eq for ItemListing {}