use crate::tools::time::{DurationMillis, TimeMillis};
use crate::tools::tools::LeadingAgreementBits;
use crate::tools::types::Id;
use parking_lot::RwLock;
use std::collections::HashMap;
pub struct CacheRadiusTracker {
radii: RwLock<HashMap<Id, (LeadingAgreementBits, TimeMillis)>>,
ttl: DurationMillis,
}
impl CacheRadiusTracker {
pub fn new(ttl: DurationMillis) -> Self {
Self {
radii: RwLock::new(HashMap::new()),
ttl,
}
}
pub fn get(&self, location_id: Id, now: TimeMillis) -> Option<LeadingAgreementBits> {
let radii = self.radii.read();
if let Some(&(radius, stored_at)) = radii.get(&location_id) {
if (now - stored_at) < self.ttl {
return Some(radius);
}
}
None
}
pub fn update(&self, location_id: Id, radius: LeadingAgreementBits, now: TimeMillis) {
self.radii.write().insert(location_id, (radius, now));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tools::time::{DurationMillis, TimeMillis};
use crate::tools::types::Id;
#[test]
fn test_get_returns_none_when_empty() {
let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
let id = Id::random();
let now = TimeMillis(1_000_000);
assert_eq!(None, tracker.get(id, now));
}
#[test]
fn test_update_and_get() {
let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
let id = Id::random();
let now = TimeMillis(1_000_000);
tracker.update(id, 10, now);
assert_eq!(Some(10), tracker.get(id, now));
assert_eq!(Some(10), tracker.get(id, TimeMillis(1_000_000 + 59_999)));
}
#[test]
fn test_get_returns_none_after_ttl() {
let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
let id = Id::random();
let now = TimeMillis(1_000_000);
tracker.update(id, 10, now);
assert_eq!(None, tracker.get(id, TimeMillis(1_000_000 + 60_000)));
assert_eq!(None, tracker.get(id, TimeMillis(1_000_000 + 120_000)));
}
#[test]
fn test_update_overwrites() {
let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
let id = Id::random();
let now = TimeMillis(1_000_000);
tracker.update(id, 10, now);
tracker.update(id, 20, now);
assert_eq!(Some(20), tracker.get(id, now));
}
#[test]
fn test_different_locations_independent() {
let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
let id1 = Id::random();
let id2 = Id::random();
let now = TimeMillis(1_000_000);
tracker.update(id1, 10, now);
assert_eq!(Some(10), tracker.get(id1, now));
assert_eq!(None, tracker.get(id2, now));
}
}