Geoffrey-rs/geoffrey_models/src/models/item.rs

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 {}