use std::collections::HashMap;
use std::hash::Hash;
use std::sync::{Arc, Mutex};
use crate::Storage;
pub struct InMemoryStorage<K, V> {
data: Arc<Mutex<HashMap<K, V>>>,
}
impl<K, V> InMemoryStorage<K, V>
where
K: Eq + Hash,
V: Clone,
{
pub fn create() -> Self {
Self {
data: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: Arc::new(Mutex::new(HashMap::with_capacity(capacity))),
}
}
pub fn clone(&self) -> Self {
Self {
data: self.data.clone(),
}
}
}
impl<K, V> Default for InMemoryStorage<K, V>
where
K: Eq + Hash,
V: Clone,
{
fn default() -> Self {
Self::create()
}
}
impl<K, V> Storage<K, V> for InMemoryStorage<K, V>
where
K: Eq + Hash + Clone,
V: Clone,
{
fn get(&self, key: &K) -> Option<V> {
self.data.lock().expect("Mutex poisoned").get(key).cloned()
}
fn insert(&mut self, key: K, value: V) -> Option<V> {
self.data.lock().expect("Mutex poisoned").insert(key, value)
}
fn remove(&mut self, key: &K) -> Option<V> {
self.data.lock().expect("Mutex poisoned").remove(key)
}
fn contains_key(&self, key: &K) -> bool {
self.data.lock().expect("Mutex poisoned").contains_key(key)
}
fn clear(&mut self) {
self.data.lock().expect("Mutex poisoned").clear()
}
fn len(&self) -> usize {
self.data.lock().expect("Mutex poisoned").len()
}
fn is_empty(&self) -> bool {
self.data.lock().expect("Mutex poisoned").is_empty()
}
fn keys(&self) -> Vec<K> {
self.data
.lock()
.expect("Mutex poisoned")
.keys()
.cloned()
.collect()
}
fn search_by_value<F>(&self, predicate: F) -> Vec<K>
where
F: Fn(&V) -> bool,
{
self.data
.lock()
.expect("Mutex poisoned")
.iter()
.filter_map(|(k, v)| {
if predicate(v) {
Some(k.clone())
} else {
None
}
})
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_operations() {
let mut db = InMemoryStorage::<String, i32>::default();
assert_eq!(db.insert("key1".to_string(), 100), None);
assert_eq!(db.len(), 1);
assert_eq!(db.get(&"key1".to_string()), Some(100));
assert_eq!(db.insert("key1".to_string(), 200), Some(100));
assert_eq!(db.get(&"key1".to_string()), Some(200));
assert!(db.contains_key(&"key1".to_string()));
assert!(!db.contains_key(&"key2".to_string()));
assert_eq!(db.remove(&"key1".to_string()), Some(200));
assert_eq!(db.len(), 0);
assert!(db.is_empty());
}
#[test]
fn test_multiple_entries() {
let mut db = InMemoryStorage::<i32, String>::create();
db.insert(1, "one".to_string());
db.insert(2, "two".to_string());
db.insert(3, "three".to_string());
assert_eq!(db.len(), 3);
assert_eq!(db.get(&2), Some("two".to_string()));
db.clear();
assert!(db.is_empty());
}
#[test]
fn test_thread_safety() {
use std::thread;
let mut db = InMemoryStorage::<i32, i32>::create();
let mut db_clone = db.clone();
let handle = thread::spawn(move || {
db_clone.insert(1, 100);
db_clone.insert(2, 200);
});
db.insert(3, 300);
handle.join().unwrap();
assert_eq!(db.len(), 3);
assert_eq!(db.get(&1), Some(100));
assert_eq!(db.get(&2), Some(200));
assert_eq!(db.get(&3), Some(300));
}
#[test]
fn test_keys_iterator() {
let mut storage = InMemoryStorage::<i32, &str>::create();
storage.insert(10, "ten");
storage.insert(20, "twenty");
storage.insert(30, "thirty");
let mut keys = storage.keys();
keys.sort_unstable();
assert_eq!(keys, vec![10, 20, 30]);
storage.remove(&20);
let keys_after_remove = storage.keys();
assert_eq!(keys_after_remove.len(), 2);
assert!(keys_after_remove.contains(&10));
assert!(keys_after_remove.contains(&30));
assert!(!keys_after_remove.contains(&20));
}
#[test]
fn test_search_by_value() {
let mut storage = InMemoryStorage::<String, i32>::create();
storage.insert("Alice".to_string(), 25);
storage.insert("Bob".to_string(), 30);
storage.insert("Charlie".to_string(), 25);
storage.insert("Diana".to_string(), 35);
storage.insert("Eve".to_string(), 30);
let mut age_25 = storage.search_by_value(|&age| age == 25);
age_25.sort();
assert_eq!(age_25, vec!["Alice".to_string(), "Charlie".to_string()]);
let mut age_30_plus = storage.search_by_value(|&age| age >= 30);
age_30_plus.sort();
assert_eq!(
age_30_plus,
vec![
"Bob".to_string(),
"Diana".to_string(),
"Eve".to_string()
]
);
let age_100 = storage.search_by_value(|&age| age == 100);
assert!(age_100.is_empty());
let mut even_ages = storage.search_by_value(|&age| age % 2 == 0);
even_ages.sort();
assert_eq!(
even_ages,
vec!["Bob".to_string(), "Eve".to_string()]
);
}
}