use std::collections::HashMap;
use std::hash::Hash;
use crate::event::{Event, EventId};
use crate::time_wheel::{HashedWheelTimer, TimeWheelError};
use super::types::{KeyedScheduleResult, KeyedUpdateResult};
#[derive(Debug)]
pub struct KeyedHashedWheelTimer<T, K, F>
where
K: Eq + Hash + Clone,
F: Fn(&T) -> K,
{
dedup_key_fn: F,
by_key: HashMap<K, EventId>,
wheel: HashedWheelTimer<T>,
}
impl<T, K, F> KeyedHashedWheelTimer<T, K, F>
where
K: Eq + Hash + Clone,
F: Fn(&T) -> K,
{
pub fn new(buckets_num: usize, dedup_key_fn: F) -> Self {
Self {
wheel: HashedWheelTimer::new(buckets_num),
dedup_key_fn,
by_key: HashMap::new(),
}
}
pub fn count_all(&self) -> usize {
self.wheel.count_all()
}
pub fn count_in_bucket(&self, bucket_index: usize) -> Result<usize, TimeWheelError> {
self.wheel.count_in_bucket(bucket_index)
}
pub fn is_empty(&self) -> bool {
self.wheel.is_empty()
}
pub fn is_empty_bucket(&self, bucket_index: usize) -> Result<bool, TimeWheelError> {
self.wheel.is_empty_bucket(bucket_index)
}
pub fn has_events_in_current_tick(&self) -> bool {
self.wheel.has_events_in_current_tick()
}
pub fn curr_tick(&self) -> u64 {
self.wheel.curr_tick()
}
pub fn curr_bucket(&self) -> usize {
self.wheel.curr_bucket()
}
pub fn curr_delta_tick(&self) -> u64 {
self.wheel.curr_delta_tick()
}
pub fn curr_seq_id(&self) -> EventId {
self.wheel.curr_seq_id()
}
pub fn step(&mut self) {
self.wheel.step()
}
pub fn reset(&mut self) {
self.wheel.reset();
self.by_key.clear();
}
pub fn contains_by_id(&self, id: EventId) -> bool {
self.wheel.contains(id)
}
pub fn contains_by_key(&self, key: &K) -> bool {
self.by_key.contains_key(key)
}
pub fn id_by_key(&self, key: &K) -> Option<EventId> {
self.by_key.get(key).copied()
}
pub fn get(&self, id: EventId) -> Option<&Event<T>> {
self.wheel.get(id)
}
pub fn get_by_key(&self, key: &K) -> Option<&Event<T>> {
let id = self.id_by_key(key)?;
self.wheel.get(id)
}
pub fn schedule(&mut self, on_tick: u64, data: T) -> KeyedScheduleResult {
let key = (self.dedup_key_fn)(&data);
let replaced_id = self.by_key.get(&key).copied();
if let Some(old_id) = replaced_id {
let _ = self.wheel.remove(old_id);
}
let result = self.wheel.schedule(on_tick, data);
self.by_key.insert(key, result.id);
KeyedScheduleResult {
id: result.id,
replaced_id,
}
}
pub fn remove(&mut self, id: EventId) -> Option<Event<T>> {
let event = self.wheel.remove(id)?;
let key = (self.dedup_key_fn)(event.data());
if self.by_key.get(&key).copied() == Some(id) {
self.by_key.remove(&key);
}
Some(event)
}
pub fn remove_by_key(&mut self, key: &K) -> Option<Event<T>> {
let id = self.by_key.get(key).copied()?;
let event = self.wheel.remove(id)?;
self.by_key.remove(key);
Some(event)
}
pub fn update(&mut self, id: EventId, on_tick: u64, data: T) -> Option<KeyedUpdateResult> {
let old_key = {
let old_event = self.wheel.get(id)?;
(self.dedup_key_fn)(old_event.data())
};
if self.by_key.get(&old_key).copied() == Some(id) {
self.by_key.remove(&old_key);
}
let new_key = (self.dedup_key_fn)(&data);
let replaced_id = self.by_key.get(&new_key).copied();
if let Some(other_id) = replaced_id {
let _ = self.wheel.remove(other_id);
self.by_key.remove(&new_key);
}
let result = self.wheel.update(id, on_tick, data)?;
self.by_key.insert(new_key, result.id);
Some(KeyedUpdateResult {
id: result.id,
replaced_id,
})
}
pub fn update_by_key(&mut self, key: &K, on_tick: u64, data: T) -> Option<KeyedUpdateResult> {
let id = self.id_by_key(key)?;
self.update(id, on_tick, data)
}
pub fn reschedule(&mut self, id: EventId, on_tick: u64) -> Option<KeyedUpdateResult> {
let key = {
let event = self.wheel.get(id)?;
(self.dedup_key_fn)(event.data())
};
let result = self.wheel.reschedule(id, on_tick)?;
self.by_key.insert(key, result.id);
Some(KeyedUpdateResult {
id: result.id,
replaced_id: None,
})
}
pub fn reschedule_by_key(&mut self, key: &K, on_tick: u64) -> Option<KeyedUpdateResult> {
let id = self.id_by_key(key)?;
self.reschedule(id, on_tick)
}
pub fn pop_events(&mut self) -> Vec<Event<T>> {
let events = self.wheel.pop_events();
for event in &events {
let key = (self.dedup_key_fn)(event.data());
if self.by_key.get(&key).copied() == Some(event.id()) {
self.by_key.remove(&key);
}
}
events
}
}