use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use biometrics::{Collector, Counter};
static NEW_STATE_HASH_TABLE: Counter = Counter::new("sync42.state_hash_table.new");
static ENTRY_INSERTED: Counter = Counter::new("sync42.state_hash_table.inserted");
static ENTRY_REMOVED: Counter = Counter::new("sync42.state_hash_table.removed");
static ARBITRARY_KEY: Counter = Counter::new("sync42.state_hash_table.arbitrary_key");
pub fn register_biometrics(collector: &Collector) {
collector.register_counter(&ENTRY_INSERTED);
collector.register_counter(&ENTRY_REMOVED);
collector.register_counter(&ARBITRARY_KEY);
}
pub trait Key: Clone + Debug + Hash + Eq + PartialEq {}
impl Key for u64 {}
impl Key for String {}
pub trait Value: Default {
fn finished(&self) -> bool;
}
pub struct Handle<'a, K: Key, V: Value> {
table: &'a StateHashTable<K, V>,
key: K,
value: Arc<V>,
}
impl<'a, K: Key, V: Value> Handle<'a, K, V> {
fn new(table: &'a StateHashTable<K, V>, key: K, value: Arc<V>) -> Self {
Self { table, key, value }
}
pub fn is_same(lhs: &Self, rhs: &Self) -> bool {
std::ptr::eq(lhs.table, rhs.table)
&& lhs.key == rhs.key
&& Arc::ptr_eq(&lhs.value, &rhs.value)
}
}
impl<'a, K: Key, V: Value> Deref for Handle<'a, K, V> {
type Target = V;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<'a, K: Key, V: Value> Drop for Handle<'a, K, V> {
fn drop(&mut self) {
let mut entries = self.table.entries.lock().unwrap();
if Arc::strong_count(&self.value) == 2 && (*self.value).finished() {
ENTRY_REMOVED.click();
entries.remove(&self.key);
}
}
}
pub struct StateHashTable<K: Key, V: Value> {
entries: Mutex<HashMap<K, Arc<V>>>,
}
impl<K: Key, V: Value> StateHashTable<K, V> {
pub fn new() -> Self {
NEW_STATE_HASH_TABLE.click();
Self {
entries: Mutex::new(HashMap::new()),
}
}
pub fn arbitary_key(&self) -> Option<K> {
ARBITRARY_KEY.click();
self.entries
.lock()
.unwrap()
.iter()
.map(|(k, _)| k.clone())
.next()
}
pub fn create_state<'a: 'b, 'b>(&'a self, key: K) -> Option<Handle<'a, K, V>>
where
V: From<K>,
{
let value = Arc::new(V::from(key.clone()));
let valuep = Arc::clone(&value);
let mut entries = self.entries.lock().unwrap();
if !entries.contains_key(&key) {
ENTRY_INSERTED.click();
entries.insert(key.clone(), value);
Some(Handle::new(self, key, valuep))
} else {
None
}
}
pub fn get_state<'a: 'b, 'b>(&'a self, key: K) -> Option<Handle<'b, K, V>> {
let entries = self.entries.lock().unwrap();
entries.get(&key).map(|value| Handle {
table: self,
key,
value: Arc::clone(value),
})
}
pub fn get_or_create_state<'a: 'b, 'b>(&'a self, key: K) -> Handle<'b, K, V>
where
V: From<K>,
{
let mut value = None;
let mut make_value = false;
loop {
if make_value && value.is_none() {
value = Some(Arc::new(V::from(key.clone())));
}
let mut entries = self.entries.lock().unwrap();
let state = entries.get(&key);
match (state, &value) {
(None, None) => {
make_value = true;
}
(None, Some(value)) => {
let value1 = Arc::clone(value);
let value2 = Arc::clone(value);
ENTRY_INSERTED.click();
entries.insert(key.clone(), value1);
return Handle::new(self, key, value2);
}
(Some(state), _) => {
let value = Arc::clone(state);
return Handle::new(self, key, value);
}
}
}
}
}
impl<K: Key, V: Value> Default for StateHashTable<K, V> {
fn default() -> Self {
Self::new()
}
}