use crate::block_storage::BlockStorage;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::hash::Hash;
use std::marker::PhantomData;
pub struct KeyValue<K, V> {
store: BlockStorage,
header: Header,
lookup: HashMap<K, usize>,
key_type: PhantomData<K>,
value_type: PhantomData<V>,
}
impl<K, V> KeyValue<K, V>
where
K: Serialize + Hash + Eq,
for<'de> K: Deserialize<'de>,
V: Serialize,
for<'de> V: Deserialize<'de>,
{
pub fn new(file: File) -> Result<Self, Box<dyn Error>> {
let mut store = BlockStorage::new(file)?;
let header = Self::read_header(&mut store)?;
let mut kv = Self {
store,
header,
lookup: HashMap::new(),
key_type: PhantomData,
value_type: PhantomData,
};
kv.save_header()?;
for index in kv.header.key_indices.iter() {
let bytes = kv.store.read(*index)?;
let entry: KeyEntry<K> = bincode::deserialize_from(bytes.as_slice())?;
kv.lookup.insert(entry.body, entry.value_index);
}
Ok(kv)
}
fn read_header(store: &mut BlockStorage) -> Result<Header, Box<dyn Error>> {
let bytes = store.read(0)?;
if store.is_empty() {
let header = Header::default();
let bytes: Vec<u8> = bincode::serialize(&header)?;
store.create(bytes.as_slice())?;
Ok(header)
} else {
let header = bincode::deserialize_from(bytes.as_slice())?;
Ok(header)
}
}
fn save_header(&mut self) -> Result<(), Box<dyn Error>> {
let bytes: Vec<u8> = bincode::serialize(&self.header)?;
self.store.update(0, bytes.as_slice())
}
pub fn len(&self) -> usize {
self.header.key_indices.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn keys(&self) -> Vec<&K> {
let mut result: Vec<&K> = vec![];
for key in self.lookup.keys() {
result.push(key);
}
result
}
pub fn get(&self, key: &K) -> Result<Option<V>, Box<dyn Error>> {
if let Some(value_index) = self.lookup.get(&key) {
let value_bytes = self.store.read(*value_index)?;
let value = bincode::deserialize_from(value_bytes.as_slice())?;
Ok(Some(value))
} else {
Ok(None)
}
}
pub fn set(&mut self, key: K, value: V) -> Result<(), Box<dyn Error>> {
if self.lookup.contains_key(&key) {
self.remove(&key)?;
}
let value_bytes: Vec<u8> = bincode::serialize(&value)?;
let value_index = self.store.create(value_bytes.as_slice())?;
let key_entry = KeyEntry {
body: key,
value_index,
};
let key_bytes = bincode::serialize(&key_entry)?;
let key_index = self.store.create(key_bytes.as_slice())?;
self.lookup.insert(key_entry.body, key_entry.value_index);
self.header.key_indices.push(key_index);
self.save_header()?;
Ok(())
}
pub fn remove(&mut self, key: &K) -> Result<(), Box<dyn Error>> {
let mut hit: Option<KeyEntry<K>> = None;
let mut hit_index: Option<usize> = None;
for index in self.header.key_indices.iter() {
let key_bytes = self.store.read(*index)?;
let key_entry: KeyEntry<K> = bincode::deserialize_from(key_bytes.as_slice())?;
if key_entry.body == *key {
hit = Some(key_entry);
hit_index = Some(*index);
}
}
if let Some(key_entry) = hit {
self.store.delete(key_entry.value_index)?;
self.store.delete(hit_index.unwrap())?;
self.lookup.remove(&key_entry.body);
let index_position = self
.header
.key_indices
.iter()
.position(|&x| x == hit_index.unwrap())
.unwrap();
self.header.key_indices.remove(index_position);
self.save_header()?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug, Default)]
struct Header {
key_indices: Vec<usize>,
}
#[derive(Serialize, Deserialize, Debug, Default)]
struct KeyEntry<K> {
body: K,
value_index: usize,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn works() {
let file = tempfile::tempfile().expect("could not create tempfile");
let mut kv = KeyValue::<i32, i32>::new(file).expect("could not create");
assert_eq!(kv.len(), 0);
assert_eq!(kv.keys(), Vec::<&i32>::new());
kv.set(17, 42).expect("can not set");
assert_eq!(kv.len(), 1);
assert_eq!(kv.keys(), vec![&17]);
let v = kv.get(&17).expect("can not get");
assert_eq!(v, Some(42));
kv.set(17, 101).expect("can not set");
assert_eq!(kv.len(), 1);
assert_eq!(kv.keys(), vec![&17]);
let v = kv.get(&17).expect("can not get");
assert_eq!(v, Some(101));
kv.remove(&17).expect("could not remove");
assert_eq!(kv.len(), 0);
assert_eq!(kv.keys(), Vec::<&i32>::new());
let v = kv.get(&17).expect("can not get");
assert_eq!(v, None);
}
}