use crate::{DebugStore, EntityId, MichiuError, OptionTraceExt, Result};
pub trait MichiuSoA {
type Item;
fn find(&self, id: EntityId) -> Option<&Self::Item>;
fn find_mut(&mut self, id: EntityId) -> Option<&mut Self::Item>;
#[inline]
fn require(&self, id: EntityId) -> Result<&Self::Item> {
self.find(id).ok_or_else(|| MichiuError::ComponentNotFound {
id,
component: std::any::type_name::<Self>(),
})
}
#[inline]
fn require_mut(&mut self, id: EntityId) -> Result<&mut Self::Item> {
let component = std::any::type_name::<Self>();
self.find_mut(id)
.ok_or(MichiuError::ComponentNotFound { id, component })
}
#[inline]
#[track_caller]
#[allow(clippy::panic)]
fn at(&self, id: EntityId) -> &Self::Item {
self.find(id).unwrap_or_else(|| {
let type_name = std::any::type_name::<Self>();
let caller = std::panic::Location::caller();
panic!(
"[Michiu UI] SoA Component Access Failed\n\
Caller Loc : {caller}\n\
Target Entity : {id:?}\n\
SoA Container : {type_name}\n\
Possible causes :\n\
- The entity was already despawned (dangling EntityId).\n\
- The component was not attached to this entity during spawn.\n\
- The component was removed before this access.\n\
"
)
})
}
#[inline]
#[track_caller]
#[allow(clippy::panic)]
fn at_mut(&mut self, id: EntityId) -> &mut Self::Item {
self.find_mut(id).unwrap_or_else(|| {
let type_name = std::any::type_name::<Self>();
let caller = std::panic::Location::caller();
panic!(
"[Michiu UI] SoA Component Mutable Access Failed\n\
Caller Loc : {caller}\n\
Target Entity : {id:?}\n\
SoA Container : {type_name}\n\
Possible causes :\n\
- The entity was already despawned (dangling EntityId).\n\
- The component was not attached to this entity during spawn.\n\
- The component was removed before this access.\n\
"
)
})
}
#[inline]
#[track_caller]
fn find_or_default(&self, id: EntityId, debug: &mut DebugStore) -> Self::Item
where
Self::Item: Default + Clone + std::fmt::Debug + Send + Sync + 'static,
{
self.find(id)
.cloned()
.unwrap_or_default_trace(Some(id), debug)
}
#[inline]
#[track_caller]
fn find_or<'a>(
&'a self,
id: EntityId,
fallback: &'a Self::Item,
debug: &mut DebugStore,
) -> &'a Self::Item
where
Self::Item: Default + Clone + std::fmt::Debug + Send + Sync + 'static,
{
#[cfg(not(feature = "trace-entity"))]
{
let _ = debug;
self.find(id).unwrap_or(fallback)
}
#[cfg(feature = "trace-entity")]
if let Some(val) = self.find(id) {
val
} else {
use crate::{MichiuInfo, MichiuTrace, trace_entity};
use std::sync::Arc;
trace_entity!(Some(id), debug, || MichiuTrace::EntityInfo {
detail: MichiuInfo::ValueNotFound,
fallback: Some(Arc::new(fallback.clone())),
add: Some(std::any::type_name::<Self::Item>()),
});
fallback
}
}
#[inline]
fn contains(&self, id: EntityId) -> bool {
self.find(id).is_some()
}
}
#[macro_export]
macro_rules! define_slotmap {
($(#[$meta:meta])* $vis:vis struct $name:ident($key:ty, $item:ty) $(;)?) => {
$(#[$meta])*
#[derive(Debug, Default, derive_more::Deref, derive_more::DerefMut)]
$vis struct $name(pub(crate) slotmap::SlotMap<$key, $item>);
};
}
#[macro_export]
macro_rules! define_secondary {
($(#[$meta:meta])* $vis:vis struct $name:ident($item:ty) $(;)?) => {
$(#[$meta])*
#[derive(Debug, Default, Clone, derive_more::Deref, derive_more::DerefMut)]
$vis struct $name(pub(crate) slotmap::SecondaryMap<$crate::EntityId, $item>);
impl $crate::MichiuSoA for $name {
type Item = $item;
#[inline]
fn find(&self, id: $crate::EntityId) -> Option<&Self::Item> { self.0.get(id) }
#[inline]
fn find_mut(&mut self, id: $crate::EntityId) -> Option<&mut Self::Item> { self.0.get_mut(id) }
}
};
($(#[$meta:meta])* $vis:vis struct $name:ident($key:ty, $item:ty) $(;)?) => {
$(#[$meta])*
#[derive(Debug, Default, Clone, derive_more::Deref, derive_more::DerefMut)]
$vis struct $name(pub(crate) slotmap::SecondaryMap<$key, $item>);
};
}
#[macro_export]
macro_rules! define_sparse_secondary {
($(#[$meta:meta])* $vis:vis struct $name:ident($item:ty) $(;)?) => {
$(#[$meta])*
#[derive(Debug, Default, Clone, derive_more::Deref, derive_more::DerefMut)]
$vis struct $name(pub(crate) slotmap::SparseSecondaryMap<$crate::EntityId, $item>);
impl $crate::MichiuSoA for $name {
type Item = $item;
#[inline]
fn find(&self, id: $crate::EntityId) -> Option<&Self::Item> { self.0.get(id) }
#[inline]
fn find_mut(&mut self, id: $crate::EntityId) -> Option<&mut Self::Item> { self.0.get_mut(id) }
}
};
($(#[$meta:meta])* $vis:vis struct $name:ident($key:ty, $item:ty) $(;)?) => {
$(#[$meta])*
#[derive(Debug, Default, Clone, derive_more::Deref, derive_more::DerefMut)]
$vis struct $name(pub(crate) slotmap::SparseSecondaryMap<$key, $item>);
};
}
#[macro_export]
macro_rules! define_vec {
($(#[$meta:meta])* $vis:vis struct $name:ident($item:ty) $(;)?) => {
$(#[$meta])*
#[derive(Debug, Clone, Default, derive_more::Deref, derive_more::DerefMut, derive_more::IntoIterator)]
#[into_iterator(owned, ref, ref_mut)]
$vis struct $name(pub(crate) Vec<$item>);
};
}
#[macro_export]
macro_rules! define_smallvec {
($(#[$meta:meta])* $vis:vis struct $name:ident($item:ty, $size:expr) $(;)?) => {
$(#[$meta])*
#[derive(Debug, Clone, Default, derive_more::Deref, derive_more::DerefMut, derive_more::IntoIterator)]
$vis struct $name(pub(crate) smallvec::SmallVec<[$item; $size]>);
};
}