use std::collections::HashMap;
use std::hash::Hash;
#[derive(Debug, Clone)]
pub struct Store<K, V>
where
K: Eq + Hash,
{
data: HashMap<K, V>,
}
impl<K, V> Store<K, V>
where
K: Eq + Hash,
{
pub fn new() -> Self {
Self {
data: HashMap::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: HashMap::with_capacity(capacity),
}
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
self.data.insert(key, value)
}
pub fn get(&self, key: &K) -> Option<&V> {
self.data.get(key)
}
pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
self.data.get_mut(key)
}
pub fn remove(&mut self, key: &K) -> Option<V> {
self.data.remove(key)
}
pub fn contains_key(&self, key: &K) -> bool {
self.data.contains_key(key)
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn clear(&mut self) {
self.data.clear();
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.data.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
self.data.iter_mut()
}
pub fn keys(&self) -> impl Iterator<Item = &K> {
self.data.keys()
}
pub fn values(&self) -> impl Iterator<Item = &V> {
self.data.values()
}
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
self.data.values_mut()
}
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
self.data.retain(f);
}
}
impl<K, V> Default for Store<K, V>
where
K: Eq + Hash,
{
fn default() -> Self {
Self::new()
}
}
impl<K, V> FromIterator<(K, V)> for Store<K, V>
where
K: Eq + Hash,
{
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
Self {
data: HashMap::from_iter(iter),
}
}
}
pub type EntityStore<V> = Store<String, V>;
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, PartialEq)]
struct TestEntity {
name: String,
hp: i32,
}
#[test]
fn test_store_basic_operations() {
let mut store = Store::new();
let entity = TestEntity {
name: "Goblin".into(),
hp: 30,
};
assert_eq!(store.insert("goblin", entity.clone()), None);
assert_eq!(store.len(), 1);
assert_eq!(store.get(&"goblin").unwrap().hp, 30);
assert!(store.contains_key(&"goblin"));
assert!(!store.contains_key(&"orc"));
store.get_mut(&"goblin").unwrap().hp = 20;
assert_eq!(store.get(&"goblin").unwrap().hp, 20);
let removed = store.remove(&"goblin").unwrap();
assert_eq!(removed.hp, 20);
assert_eq!(store.len(), 0);
assert!(store.is_empty());
}
#[test]
fn test_store_iteration() {
let mut store = Store::new();
store.insert(
"goblin",
TestEntity {
name: "Goblin".into(),
hp: 30,
},
);
store.insert(
"orc",
TestEntity {
name: "Orc".into(),
hp: 50,
},
);
store.insert(
"troll",
TestEntity {
name: "Troll".into(),
hp: 100,
},
);
let total_hp: i32 = store.values().map(|e| e.hp).sum();
assert_eq!(total_hp, 180);
let alive_count = store.values().filter(|e| e.hp > 0).count();
assert_eq!(alive_count, 3);
}
#[test]
fn test_store_retain() {
let mut store = Store::new();
store.insert(
"goblin",
TestEntity {
name: "Goblin".into(),
hp: 30,
},
);
store.insert(
"orc",
TestEntity {
name: "Orc".into(),
hp: 0,
},
);
store.insert(
"troll",
TestEntity {
name: "Troll".into(),
hp: 100,
},
);
store.retain(|_, entity| entity.hp > 0);
assert_eq!(store.len(), 2);
assert!(!store.contains_key(&"orc"));
}
#[test]
fn test_entity_store() {
let mut players: EntityStore<TestEntity> = EntityStore::new();
players.insert(
"alice".to_string(),
TestEntity {
name: "Alice".into(),
hp: 100,
},
);
players.insert(
"bob".to_string(),
TestEntity {
name: "Bob".into(),
hp: 90,
},
);
assert_eq!(players.len(), 2);
assert_eq!(players.get(&"alice".to_string()).unwrap().hp, 100);
}
#[test]
fn test_from_iterator() {
let data = vec![
(
"goblin",
TestEntity {
name: "Goblin".into(),
hp: 30,
},
),
(
"orc",
TestEntity {
name: "Orc".into(),
hp: 50,
},
),
];
let store: Store<&str, TestEntity> = data.into_iter().collect();
assert_eq!(store.len(), 2);
}
#[test]
fn test_with_capacity() {
let store: Store<String, TestEntity> = Store::with_capacity(10);
assert_eq!(store.len(), 0);
assert!(store.is_empty());
}
}