use std::collections::HashMap;
use std::hash::Hash;
use std::sync::{Mutex, MutexGuard, OnceLock};
#[derive(Debug, Default)]
pub struct StaticPartitionMap<K, V> {
inner: OnceLock<Mutex<HashMap<K, V>>>,
}
impl<K, V> StaticPartitionMap<K, V> {
pub const fn new() -> Self {
Self {
inner: OnceLock::new(),
}
}
}
impl<K, V> StaticPartitionMap<K, V>
where
K: Eq + Hash,
{
fn get_or_init_inner(&self) -> MutexGuard<'_, HashMap<K, V>> {
self.inner
.get_or_init(|| Mutex::new(HashMap::with_capacity(1)))
.lock()
.unwrap()
}
}
impl<K, V> StaticPartitionMap<K, V>
where
K: Eq + Hash,
V: Clone,
{
#[must_use]
pub fn get(&self, partition_key: K) -> Option<V> {
self.get_or_init_inner().get(&partition_key).cloned()
}
#[must_use]
pub fn get_or_init<F>(&self, partition_key: K, init: F) -> V
where
F: FnOnce() -> V,
{
let mut inner = self.get_or_init_inner();
let v = inner.entry(partition_key).or_insert_with(init);
v.clone()
}
}
impl<K, V> StaticPartitionMap<K, V>
where
K: Eq + Hash,
V: Clone + Default,
{
#[must_use]
pub fn get_or_init_default(&self, partition_key: K) -> V {
self.get_or_init(partition_key, V::default)
}
}
#[cfg(test)]
mod tests {
use super::StaticPartitionMap;
#[test]
fn test_keyed_partition_returns_same_value_for_same_key() {
let kp = StaticPartitionMap::new();
let _ = kp.get_or_init("A", || "A".to_owned());
let actual = kp.get_or_init("A", || "B".to_owned());
let expected = "A".to_owned();
assert_eq!(expected, actual);
}
#[test]
fn test_keyed_partition_returns_different_value_for_different_key() {
let kp = StaticPartitionMap::new();
let _ = kp.get_or_init("A", || "A".to_owned());
let actual = kp.get_or_init("B", || "B".to_owned());
let expected = "B".to_owned();
assert_eq!(expected, actual);
let actual = kp.get("A").unwrap();
let expected = "A".to_owned();
assert_eq!(expected, actual);
}
}