use std::any::TypeId;
use rustc_hash::FxHashMap as HashMap;
use crate::attributes::{
AttributeBind, AttributeError, AttributeStorage, AttributeUpdate, UnknownAttributeStorage,
};
use crate::cmap::{DartIdType, OrbitPolicy};
use crate::stm::{StmClosureResult, Transaction, TransactionClosureResult};
macro_rules! get_storage {
($slf: ident, $id: ident) => {
let probably_storage = $slf.get_map(A::BIND_POLICY).get(&TypeId::of::<A>());
let $id = probably_storage
.map(|m| m.downcast_ref::<<A as AttributeBind>::StorageType>())
.flatten();
};
}
#[cfg(test)]
macro_rules! get_storage_mut {
($slf: ident, $id: ident) => {
let probably_storage = $slf.get_map_mut(A::BIND_POLICY).get_mut(&TypeId::of::<A>());
let $id = probably_storage
.map(|m| m.downcast_mut::<<A as AttributeBind>::StorageType>())
.flatten();
};
}
#[derive(Default)]
pub(crate) struct AttrStorageManager {
icells: [HashMap<TypeId, Box<dyn UnknownAttributeStorage>>; 4],
others: HashMap<TypeId, Box<dyn UnknownAttributeStorage>>, }
unsafe impl Send for AttrStorageManager {}
unsafe impl Sync for AttrStorageManager {}
impl AttrStorageManager {
#[allow(clippy::needless_pass_by_value)]
const fn get_map(
&self,
orbit: OrbitPolicy,
) -> &HashMap<TypeId, Box<dyn UnknownAttributeStorage>> {
match orbit {
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => &self.icells[0],
OrbitPolicy::Edge => &self.icells[1],
OrbitPolicy::Face | OrbitPolicy::FaceLinear => &self.icells[2],
OrbitPolicy::Volume | OrbitPolicy::VolumeLinear => &self.icells[3],
OrbitPolicy::Custom(_) => &self.others,
}
}
#[allow(clippy::needless_pass_by_value)]
const fn get_map_mut(
&mut self,
orbit: OrbitPolicy,
) -> &mut HashMap<TypeId, Box<dyn UnknownAttributeStorage>> {
match orbit {
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => &mut self.icells[0],
OrbitPolicy::Edge => &mut self.icells[1],
OrbitPolicy::Face | OrbitPolicy::FaceLinear => &mut self.icells[2],
OrbitPolicy::Volume | OrbitPolicy::VolumeLinear => &mut self.icells[3],
OrbitPolicy::Custom(_) => &mut self.others,
}
}
pub fn extend_storages(&mut self, length: usize) {
for map in &mut self.icells {
for storage in map.values_mut() {
storage.extend(length);
}
}
for storage in self.others.values_mut() {
storage.extend(length);
}
}
pub fn clear_attribute_values(
&self,
t: &mut Transaction,
id: DartIdType,
) -> StmClosureResult<()> {
for map in &self.icells {
for storage in map.values() {
storage.clear_slot(t, id)?;
}
}
Ok(())
}
pub fn add_storage<A: AttributeBind + 'static>(&mut self, size: usize) {
let typeid = TypeId::of::<A>();
let new_storage = <A as AttributeBind>::StorageType::new(size);
if self
.get_map_mut(A::BIND_POLICY)
.insert(typeid, Box::new(new_storage))
.is_some()
{
eprintln!(
"W: Storage of attribute `{}` already exists in the attribute storage manager",
std::any::type_name::<A>()
);
eprintln!(" Continuing...");
}
}
#[cfg(test)]
pub fn extend_storage<A: AttributeBind>(&mut self, length: usize) {
get_storage_mut!(self, storage);
if let Some(st) = storage {
st.extend(length);
} else {
eprintln!(
"W: could not extend storage of attribute {} - storage not found",
std::any::type_name::<A>()
);
}
}
#[cfg(test)]
#[must_use = "unused return value"]
pub fn get_storage<A: AttributeBind>(&self) -> Option<&<A as AttributeBind>::StorageType> {
self.get_map(A::BIND_POLICY)[&TypeId::of::<A>()]
.downcast_ref::<<A as AttributeBind>::StorageType>()
}
pub fn remove_storage<A: AttributeBind>(&mut self) {
let _ = self.get_map_mut(A::BIND_POLICY).remove(&TypeId::of::<A>());
}
}
impl AttrStorageManager {
pub fn merge_attributes(
&self,
t: &mut Transaction,
orbit_policy: OrbitPolicy,
id_out: DartIdType,
id_in_lhs: DartIdType,
id_in_rhs: DartIdType,
) -> TransactionClosureResult<(), AttributeError> {
for storage in self.get_map(orbit_policy).values() {
storage.merge(t, id_out, id_in_lhs, id_in_rhs)?;
}
Ok(())
}
pub fn split_attributes(
&self,
t: &mut Transaction,
orbit_policy: OrbitPolicy,
id_out_lhs: DartIdType,
id_out_rhs: DartIdType,
id_in: DartIdType,
) -> TransactionClosureResult<(), AttributeError> {
for storage in self.get_map(orbit_policy).values() {
storage.split(t, id_out_lhs, id_out_rhs, id_in)?;
}
Ok(())
}
}
impl AttrStorageManager {
#[allow(clippy::missing_errors_doc)]
pub fn read_attribute<A: AttributeBind>(
&self,
t: &mut Transaction,
id: A::IdentifierType,
) -> StmClosureResult<Option<A>> {
get_storage!(self, storage);
if let Some(st) = storage {
st.read(t, id)
} else {
eprintln!(
"W: could not update storage of attribute {} - storage not found",
std::any::type_name::<A>()
);
Ok(None)
}
}
#[allow(clippy::missing_errors_doc)]
pub fn write_attribute<A: AttributeBind>(
&self,
t: &mut Transaction,
id: A::IdentifierType,
val: A,
) -> StmClosureResult<Option<A>> {
get_storage!(self, storage);
if let Some(st) = storage {
st.write(t, id, val)
} else {
eprintln!(
"W: could not update storage of attribute {} - storage not found",
std::any::type_name::<A>()
);
Ok(None)
}
}
#[allow(clippy::missing_errors_doc)]
pub(crate) fn remove_attribute<A: AttributeBind + AttributeUpdate>(
&self,
t: &mut Transaction,
id: A::IdentifierType,
) -> StmClosureResult<Option<A>> {
get_storage!(self, storage);
if let Some(st) = storage {
st.remove(t, id)
} else {
eprintln!(
"W: could not update storage of attribute {} - storage not found",
std::any::type_name::<A>()
);
Ok(None)
}
}
pub(crate) fn contains_attribute<A: AttributeBind + AttributeUpdate>(&self) -> bool {
get_storage!(self, storage);
storage.is_some()
}
}
#[cfg(test)]
impl AttrStorageManager {
pub fn merge_attribute<A: AttributeBind + AttributeUpdate>(
&self,
t: &mut Transaction,
id_out: DartIdType,
id_in_lhs: DartIdType,
id_in_rhs: DartIdType,
) -> TransactionClosureResult<(), AttributeError> {
get_storage!(self, storage);
if let Some(st) = storage {
st.merge(t, id_out, id_in_lhs, id_in_rhs)
} else {
eprintln!(
"W: could not update storage of attribute {} - storage not found",
std::any::type_name::<A>()
);
Ok(())
}
}
pub fn split_attribute<A: AttributeBind + AttributeUpdate>(
&self,
t: &mut Transaction,
id_out_lhs: DartIdType,
id_out_rhs: DartIdType,
id_in: DartIdType,
) -> TransactionClosureResult<(), AttributeError> {
get_storage!(self, storage);
if let Some(st) = storage {
st.split(t, id_out_lhs, id_out_rhs, id_in)
} else {
eprintln!(
"W: could not update storage of attribute {} - storage not found",
std::any::type_name::<A>()
);
Ok(())
}
}
}