use super::{Collection, Intent, Key, Load, LocalField, SparseField, Store, Strategy, Value};
use crate::{
index::{FieldWriter, Transaction},
object::{self, serializer::SizedPointer, ObjectError},
};
use scc::HashMap;
use std::{borrow::Borrow, hash::Hash, sync::Arc};
#[derive(Clone, Default)]
pub struct Map<K: 'static + Key, V: 'static + Value>(Arc<HashMap<K, Arc<V>>>);
impl<K, V> Map<K, V>
where
K: Key,
V: Value,
{
#[inline(always)]
pub fn insert(&self, key: K, value: impl Into<Arc<V>>) -> Arc<V> {
match self.get(&key) {
Some(existing) => existing,
None => {
let new: Arc<_> = value.into();
let _ = self.0.insert(key, new.clone());
new
}
}
}
#[inline(always)]
pub fn update_with<Q, R>(&self, key: &Q, fun: impl FnOnce(&K, &mut Arc<V>) -> R) -> Option<R>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.0.update(key, fun)
}
#[inline(always)]
pub fn insert_with(&self, key: K, mut fun: impl FnMut() -> V) -> Arc<V> {
match self.get(&key) {
Some(existing) => existing,
None => {
let new: Arc<_> = (fun)().into();
self.insert(key, new.clone());
new
}
}
}
#[inline(always)]
pub fn get<Q>(&self, key: &Q) -> Option<Arc<V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.0.read(key, |_, v| v.clone())
}
#[inline(always)]
pub fn remove<Q>(&self, key: &Q)
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.0.remove(key);
}
#[inline(always)]
pub fn contains<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.0.contains(key)
}
#[inline(always)]
pub fn for_each(&self, mut callback: impl FnMut(&K, &Arc<V>)) {
let mut current = self.0.first_entry();
while let Some(entry) = current {
(callback)(entry.key(), entry.get());
current = entry.next();
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline(always)]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.0.len() == 0
}
}
impl<K, V> Store for LocalField<Map<K, V>>
where
K: Key,
V: Value,
{
fn store(&mut self, mut transaction: &mut dyn Transaction, _object: &mut dyn object::Writer) {
self.field.for_each(|k, v| {
transaction.write_next((k, v));
})
}
}
impl<K, V> Collection for LocalField<Map<K, V>>
where
K: Key,
V: Value,
{
type Depth = super::depth::Snapshot;
type Key = K;
type Serialized = (K, V);
type Item = (K, V);
fn key(from: &Self::Serialized) -> &Self::Key {
&from.0
}
fn load(from: Self::Serialized, _object: &mut dyn object::Reader) -> Self::Item {
from
}
fn insert(&mut self, record: Self::Item) {
self.field.insert(record.0, record.1);
}
}
impl<K, V> Store for SparseField<Map<K, V>>
where
K: Key,
V: Value,
{
fn store(&mut self, mut transaction: &mut dyn Transaction, writer: &mut dyn object::Writer) {
self.field.for_each(|key, value| {
let ptr = object::serializer::write(
writer,
|x| {
crate::serialize_to_vec(x).map_err(|e| ObjectError::Serialize {
source: Box::new(e),
})
},
value,
)
.unwrap();
transaction.write_next((key, ptr));
})
}
}
impl<K, V> Collection for SparseField<Map<K, V>>
where
K: Key,
V: Value,
{
type Depth = super::depth::Snapshot;
type Key = K;
type Serialized = (K, SizedPointer);
type Item = (K, V);
fn key(from: &Self::Serialized) -> &Self::Key {
&from.0
}
fn load(from: Self::Serialized, object: &mut dyn object::Reader) -> Self::Item {
let (key, ptr) = from;
let value = object::serializer::read(
object,
|x| {
crate::deserialize_from_slice(x).map_err(|e| ObjectError::Deserialize {
source: Box::new(e),
})
},
ptr,
)
.unwrap();
(key, value)
}
fn insert(&mut self, record: Self::Item) {
self.field.insert(record.0, record.1);
}
}
impl<K, V> crate::Index for Map<K, V>
where
K: Key + Clone,
V: Value + Clone,
{
fn store_all(&self) -> anyhow::Result<Vec<Intent<Box<dyn Store>>>> {
Ok(vec![Intent::new(
"root",
Box::new(LocalField::for_field(self)),
)])
}
fn load_all(&self) -> anyhow::Result<Vec<Intent<Box<dyn Load>>>> {
Ok(vec![Intent::new(
"root",
Box::new(LocalField::for_field(self)),
)])
}
}
#[cfg(test)]
mod test {
use super::Map;
use crate::{
fields::{LocalField, SparseField, Strategy},
index::test::store_then_load,
};
#[test]
fn duplicate_insert_is_noop() {
let m = Map::<usize, String>::default();
assert_eq!(m.insert(1, "first".to_owned()), "first".to_owned().into());
assert_eq!(m.insert(1, "second".to_owned()), "first".to_owned().into());
}
#[test]
fn updating_empty_is_noop() {
let m = Map::<usize, String>::default();
assert_eq!(
m.update_with(&1, |_, v| *v = "first".to_owned().into()),
None
);
}
#[test]
fn store_then_confirm_then_remove() {
let m = Map::<usize, String>::default();
let first = "first".to_owned();
let updated = "updated".to_owned();
let second = "second".to_owned();
assert_eq!(m.insert_with(1, || first.clone()), first.clone().into());
assert_eq!(m.insert_with(2, || second.clone()), second.clone().into());
assert_eq!(m.get(&1), Some(first.into()));
assert!(m.contains(&1));
assert!(m.contains(&2));
assert_eq!(
m.update_with(&1, |_, v| {
*v = updated.clone().into();
v.clone()
}),
Some(updated.clone().into())
);
assert_eq!(m.get(&1), Some(updated.into()));
m.remove(&1);
assert_eq!(m.get(&1), None);
assert_eq!(m.get(&2), Some(second.into()));
}
type TestMap = Map<usize, String>;
fn init_map(store: &TestMap) {
store.insert(1, "one".to_owned());
store.insert(2, "two".to_owned());
}
crate::len_check_test!(TestMap, LocalField, init_map, |m: TestMap| m.len());
crate::len_check_test!(TestMap, SparseField, init_map, |m: TestMap| m.len());
}