use crate::DbError;
use crate::StorageData;
use crate::collections::map::DbMap;
use crate::collections::map::DbMapData;
use crate::collections::map::MapData;
use crate::collections::map::MapImpl;
use crate::collections::map::MapIterator;
use crate::collections::vec::VecValue;
use crate::storage::Storage;
use crate::storage::StorageIndex;
use crate::utilities::stable_hash::StableHash;
use std::marker::PhantomData;
pub struct IndexedMapImpl<K, T, D, DataKT, DataTK>
where
D: StorageData,
DataKT: MapData<K, T, D>,
DataTK: MapData<T, K, D>,
{
keys_to_values: MapImpl<K, T, D, DataKT>,
values_to_keys: MapImpl<T, K, D, DataTK>,
storage: PhantomData<D>,
}
impl<K, T, D, DataKT, DataTK> IndexedMapImpl<K, T, D, DataKT, DataTK>
where
D: StorageData,
K: Default + PartialEq + StableHash,
T: Default + PartialEq + StableHash,
DataKT: MapData<K, T, D>,
DataTK: MapData<T, K, D>,
{
pub fn insert(&mut self, storage: &mut Storage<D>, key: &K, value: &T) -> Result<(), DbError> {
if let Some(v) = self.keys_to_values.insert(storage, key, value)? {
self.values_to_keys.remove(storage, &v)?;
}
if let Some(k) = self.values_to_keys.insert(storage, value, key)? {
self.keys_to_values.remove(storage, &k)?;
}
Ok(())
}
pub fn iter<'a>(&'a self, storage: &'a Storage<D>) -> MapIterator<'a, K, T, D, DataKT> {
self.keys_to_values.iter(storage)
}
pub fn key(&self, storage: &Storage<D>, value: &T) -> Result<Option<K>, DbError> {
self.values_to_keys.value(storage, value)
}
pub fn remove_key(&mut self, storage: &mut Storage<D>, key: &K) -> Result<(), DbError> {
if let Some(value) = self.keys_to_values.value(storage, key)? {
self.values_to_keys.remove(storage, &value)?;
}
self.keys_to_values.remove(storage, key)
}
#[allow(dead_code)]
pub fn remove_value(&mut self, storage: &mut Storage<D>, value: &T) -> Result<(), DbError> {
if let Some(key) = self.values_to_keys.value(storage, value)? {
self.keys_to_values.remove(storage, &key)?;
}
self.values_to_keys.remove(storage, value)
}
pub fn shrink_to_fit(&mut self, storage: &mut Storage<D>) -> Result<(), DbError> {
self.keys_to_values.shrink_to_fit(storage)?;
self.values_to_keys.shrink_to_fit(storage)
}
pub fn value(&self, storage: &Storage<D>, key: &K) -> Result<Option<T>, DbError> {
self.keys_to_values.value(storage, key)
}
}
pub type DbIndexedMap<K, T, D> = IndexedMapImpl<K, T, D, DbMapData<K, T, D>, DbMapData<T, K, D>>;
impl<K, T, D> DbIndexedMap<K, T, D>
where
K: Default + Clone + VecValue<D>,
T: Default + Clone + VecValue<D>,
D: StorageData,
{
pub fn new(storage: &mut Storage<D>) -> Result<Self, DbError> {
let keys_to_values = DbMap::<K, T, D>::new(storage)?;
let values_to_keys = DbMap::<T, K, D>::new(storage)?;
Ok(Self {
keys_to_values,
values_to_keys,
storage: PhantomData,
})
}
pub fn from_storage(
storage: &Storage<D>,
index: (StorageIndex, StorageIndex),
) -> Result<Self, DbError> {
let keys_to_values = DbMap::<K, T, D>::from_storage(storage, index.0)?;
let values_to_keys = DbMap::<T, K, D>::from_storage(storage, index.1)?;
Ok(Self {
keys_to_values,
values_to_keys,
storage: PhantomData,
})
}
pub fn storage_index(&self) -> (StorageIndex, StorageIndex) {
(
self.keys_to_values.storage_index(),
self.values_to_keys.storage_index(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
storage::file_storage_memory_mapped::FileStorageMemoryMapped,
test_utilities::test_file::TestFile,
};
#[test]
fn from_storage() {
let test_file = TestFile::new();
let mut storage = Storage::new(test_file.file_name()).unwrap();
let storage_index;
{
let mut map =
DbIndexedMap::<String, u64, FileStorageMemoryMapped>::new(&mut storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;
map.insert(&mut storage, &key, &value).unwrap();
storage_index = map.storage_index();
}
let map = DbIndexedMap::<String, u64, FileStorageMemoryMapped>::from_storage(
&storage,
storage_index,
)
.unwrap();
assert_eq!(
map.value(&storage, &"alias".to_string()).unwrap(),
Some(1_u64)
);
}
#[test]
fn insert() {
let test_file = TestFile::new();
let mut storage = Storage::new(test_file.file_name()).unwrap();
let mut map =
DbIndexedMap::<String, u64, FileStorageMemoryMapped>::new(&mut storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;
assert_eq!(map.insert(&mut storage, &key, &value), Ok(()));
assert_eq!(map.value(&storage, &key), Ok(Some(value)));
assert_eq!(map.key(&storage, &value), Ok(Some(key)));
}
#[test]
fn iter() {
let test_file = TestFile::new();
let mut storage = Storage::new(test_file.file_name()).unwrap();
let mut map =
DbIndexedMap::<String, u64, FileStorageMemoryMapped>::new(&mut storage).unwrap();
assert_eq!(
map.insert(&mut storage, &"alias1".to_string(), &1_u64),
Ok(())
);
assert_eq!(
map.insert(&mut storage, &"alias2".to_string(), &2_u64),
Ok(())
);
assert_eq!(
map.insert(&mut storage, &"alias3".to_string(), &3_u64),
Ok(())
);
let mut values = Vec::<(String, u64)>::new();
for key_value in map.iter(&storage) {
values.push(key_value);
}
values.sort();
assert_eq!(
values,
vec![
("alias1".to_string(), 1_u64),
("alias2".to_string(), 2_u64),
("alias3".to_string(), 3_u64)
]
);
}
#[test]
fn replace_by_key() {
let test_file = TestFile::new();
let mut storage = Storage::new(test_file.file_name()).unwrap();
let mut map =
DbIndexedMap::<String, u64, FileStorageMemoryMapped>::new(&mut storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;
let new_value = 2_u64;
assert_eq!(map.insert(&mut storage, &key, &value), Ok(()));
assert_eq!(map.insert(&mut storage, &key, &new_value), Ok(()));
assert_eq!(map.value(&storage, &key), Ok(Some(new_value)));
assert_eq!(map.key(&storage, &new_value), Ok(Some(key)));
assert_eq!(map.key(&storage, &value), Ok(None));
}
#[test]
fn replace_by_value() {
let test_file = TestFile::new();
let mut storage = Storage::new(test_file.file_name()).unwrap();
let mut map =
DbIndexedMap::<String, u64, FileStorageMemoryMapped>::new(&mut storage).unwrap();
let key = "alias".to_string();
let new_key = "new_alias".to_string();
let value = 1_u64;
assert_eq!(map.insert(&mut storage, &key, &value), Ok(()));
assert_eq!(map.insert(&mut storage, &new_key, &value), Ok(()));
assert_eq!(map.value(&storage, &key), Ok(None));
assert_eq!(map.value(&storage, &new_key), Ok(Some(value)));
assert_eq!(map.key(&storage, &value), Ok(Some(new_key)));
}
#[test]
fn remove_key() {
let test_file = TestFile::new();
let mut storage = Storage::new(test_file.file_name()).unwrap();
let mut map =
DbIndexedMap::<String, u64, FileStorageMemoryMapped>::new(&mut storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;
assert_eq!(map.insert(&mut storage, &key, &value), Ok(()));
assert_eq!(map.value(&storage, &key), Ok(Some(value)));
assert_eq!(map.key(&storage, &value), Ok(Some(key.clone())));
map.remove_key(&mut storage, &key).unwrap();
map.remove_key(&mut storage, &key).unwrap();
assert_eq!(map.value(&storage, &key), Ok(None));
assert_eq!(map.key(&storage, &value), Ok(None));
}
#[test]
fn remove_value() {
let test_file = TestFile::new();
let mut storage = Storage::new(test_file.file_name()).unwrap();
let mut map =
DbIndexedMap::<String, u64, FileStorageMemoryMapped>::new(&mut storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;
assert_eq!(map.insert(&mut storage, &key, &value), Ok(()));
assert_eq!(map.value(&storage, &key), Ok(Some(value)));
assert_eq!(map.key(&storage, &value), Ok(Some(key.clone())));
map.remove_value(&mut storage, &value).unwrap();
map.remove_value(&mut storage, &value).unwrap();
assert_eq!(map.value(&storage, &key), Ok(None));
assert_eq!(map.key(&storage, &value), Ok(None));
}
}