use core::mem;
use crate::{
archetype::RefMut,
component::ComponentValue,
writer::{Replace, SingleComponentWriter},
Component, Entity, World,
};
pub enum Entry<'a, T: ComponentValue> {
Vacant(VacantEntry<'a, T>),
Occupied(OccupiedEntry<'a, T>),
}
pub struct VacantEntry<'a, T: ComponentValue> {
pub(crate) world: &'a mut World,
pub(crate) id: Entity,
pub(crate) component: Component<T>,
}
impl<'a, T: ComponentValue> VacantEntry<'a, T> {
pub fn insert(self, value: T) -> RefMut<'a, T> {
let (loc, _) = self
.world
.set_with_writer(
self.id,
SingleComponentWriter::new(self.component.desc(), Replace { value }),
)
.expect("Entry is valid");
self.world.get_mut_at(loc, self.component).unwrap()
}
}
pub struct OccupiedEntry<'a, T: ComponentValue> {
pub(crate) borrow: RefMut<'a, T>,
}
impl<'a, T: ComponentValue> OccupiedEntry<'a, T> {
pub fn into_mut(self) -> RefMut<'a, T> {
self.borrow
}
}
impl<'a, T> Entry<'a, T>
where
T: ComponentValue,
{
pub fn and_modify(mut self, mut func: impl FnMut(&mut T)) -> Self {
if let Self::Occupied(v) = &mut self {
(func)(&mut *v.borrow)
}
self
}
pub fn or_insert(self, value: T) -> RefMut<'a, T> {
match self {
Entry::Vacant(slot) => slot.insert(value),
Entry::Occupied(slot) => slot.into_mut(),
}
}
pub fn or_default(self) -> RefMut<'a, T>
where
T: Default,
{
match self {
Entry::Vacant(slot) => slot.insert(Default::default()),
Entry::Occupied(slot) => slot.into_mut(),
}
}
pub fn or_insert_with(self, func: impl FnOnce() -> T) -> RefMut<'a, T> {
match self {
Entry::Vacant(slot) => slot.insert((func)()),
Entry::Occupied(slot) => slot.into_mut(),
}
}
pub fn set(self, value: T) -> Option<T> {
match self {
Entry::Vacant(slot) => {
slot.insert(value);
None
}
Entry::Occupied(mut slot) => Some(mem::replace(&mut slot.borrow, value)),
}
}
}