93 lines
2.3 KiB
Rust
93 lines
2.3 KiB
Rust
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<Utc>,
|
|
pub out_of_stock_votes: HashSet<u64>,
|
|
}
|
|
|
|
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<H: Hasher>(&self, state: &mut H) {
|
|
self.item.name.hash(state);
|
|
self.price.hash(state);
|
|
self.count_per_price.hash(state);
|
|
}
|
|
}
|
|
|
|
impl PartialEq<Self> 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 {}
|