use std::{
any,
collections::{HashMap, hash_map},
marker::PhantomData,
};
use derive_where::derive_where;
use spru::{
Item,
item::{self, IdT},
};
#[derive_where(Debug, Default; )]
pub struct Standalone<State> {
map: HashMap<any::TypeId, Box<dyn any::Any>>,
_state: PhantomData<fn() -> State>,
}
impl<State> Standalone<State> {
pub fn new() -> Self {
Self::default()
}
}
impl<State: spru::State> spru::item::Storage for Standalone<State> {
type State = State;
fn get<T>(&self, id: IdT<T>) -> spru::item::storage::Result<&Item<T>>
where
T: item::storage::Storable<Self::State>,
{
let type_id = any::TypeId::of::<T>();
let item = if let Some(inner_map) = self.map.get(&type_id) {
let inner_map = inner_map
.downcast_ref::<HashMap<item::IdT<T>, Item<T>>>()
.expect("Internal type mismatch");
inner_map.get(&id)
} else {
None
};
item.ok_or(Error::IdNotFound(id.untyped()))
.map_err(Into::into)
}
#[allow(refining_impl_trait)]
fn get_mut<T>(&mut self, id: IdT<T>) -> spru::item::storage::Result<&mut spru::Item<T>>
where
T: item::storage::Storable<Self::State>,
{
let type_id = any::TypeId::of::<T>();
let item = if let Some(inner_map) = self.map.get_mut(&type_id) {
let inner_map = inner_map
.downcast_mut::<InnerMap<T>>()
.expect("Interal type mismatch");
inner_map.get_mut(&id)
} else {
None
};
item.ok_or(Error::IdNotFound(id.untyped()))
.map_err(Into::into)
}
fn create<T>(&mut self, value: spru::Item<T>) -> spru::item::storage::Result<()>
where
T: item::storage::Storable<Self::State>,
{
let id = value.id();
let type_id = any::TypeId::of::<T>();
let inner_map = self
.map
.entry(type_id)
.or_insert(Box::new(InnerMap::<T>::new()));
let inner_map = inner_map
.downcast_mut::<InnerMap<T>>()
.expect("Interal type mismatch");
if let hash_map::Entry::Vacant(v) = inner_map.entry(id) {
v.insert(value);
Ok(())
} else {
Err(Error::IdAlreadyExists(id.untyped()).into())
}
}
fn destroy<T>(&mut self, id: IdT<T>) -> spru::item::storage::Result<spru::Item<T>>
where
T: item::storage::Storable<Self::State>,
{
let type_id = any::TypeId::of::<T>();
let item = if let Some(inner_map) = self.map.get_mut(&type_id) {
let inner_map = inner_map
.downcast_mut::<InnerMap<T>>()
.expect("Interal type mismatch");
inner_map.remove(&id)
} else {
None
};
item.ok_or(Error::IdNotFound(id.untyped()).into())
}
}
type InnerMap<T> = HashMap<item::IdT<T>, Item<T>>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Id '{0}' was not found")]
IdNotFound(item::Id),
#[error("Id '{0}' already exists")]
IdAlreadyExists(item::Id),
}
#[cfg(test)]
mod test {
use super::*;
#[tagset::tagset(impl spru::State)]
#[tagset(String)]
struct State;
#[test]
fn standalone() {
use spru::item::storage::Storage as _;
let mut storage = Standalone::<State>::new();
let id0 = spru::item::IdT::test_new(0);
let id1 = spru::item::IdT::test_new(1);
let id2 = spru::item::IdT::test_new(2);
storage
.create(spru::Item::test_new(id0.clone(), "zero".to_string()))
.unwrap();
storage
.create(spru::Item::test_new(id1.clone(), "one".to_string()))
.unwrap();
storage
.create(spru::Item::test_new(id2.clone(), "two".to_string()))
.unwrap();
let s0 = storage.get_mut(id0).unwrap().test_get_mut();
*s0 = "ZERO".to_string();
let s0 = storage.get(id0).unwrap().get();
assert_eq!(s0, &"ZERO");
let s1 = storage.get(id1).unwrap().get();
assert_eq!(s1, &"one");
storage.destroy(id2).unwrap();
}
}