use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use join::Join;
use shred::Resource;
use storage::{DenseVecStorage, ReadStorage, WriteStorage};
use world::{Component, EntitiesRes, Entity, EntityBuilder};
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
impl<'a> EntityBuilder<'a> {
pub fn marked<M>(self) -> Self
where
M: Marker,
{
let mut alloc = self.world.write_resource::<M::Allocator>();
alloc.mark(self.entity, &mut self.world.write_storage::<M>());
self
}
}
pub trait Marker: Clone + Component + Debug + Eq + Hash + DeserializeOwned + Serialize {
type Identifier;
type Allocator: MarkerAllocator<Self>;
fn id(&self) -> Self::Identifier;
fn update(&mut self, new_revision: Self) {
*self = new_revision;
}
}
pub trait MarkerAllocator<M: Marker>: Resource {
fn allocate(&mut self, entity: Entity, id: Option<M::Identifier>) -> M;
fn retrieve_entity_internal(&self, id: M::Identifier) -> Option<Entity>;
fn retrieve_entity(
&mut self,
marker: M,
storage: &mut WriteStorage<M>,
entities: &EntitiesRes,
) -> Entity {
if let Some(entity) = self.retrieve_entity_internal(marker.id()) {
if let Some(marker_comp) = storage.get_mut(entity) {
marker_comp.update(marker);
return entity;
}
}
let entity = entities.create();
let marker = self.allocate(entity, Some(marker.id()));
storage.insert(entity, marker);
entity
}
fn mark<'m>(
&mut self,
entity: Entity,
storage: &'m mut WriteStorage<M>,
) -> Option<(&'m M, bool)> {
if let Ok(entry) = storage.entry(entity) {
let mut new = false;
let marker = entry.or_insert_with(|| {
new = true;
self.allocate(entity, None)
});
Some((marker, new))
} else {
None
}
}
fn maintain(&mut self, _entities: &EntitiesRes, _storage: &ReadStorage<M>);
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct U64Marker(u64);
impl Component for U64Marker {
type Storage = DenseVecStorage<Self>;
}
impl Marker for U64Marker {
type Allocator = U64MarkerAllocator;
type Identifier = u64;
fn id(&self) -> u64 {
self.0
}
}
#[derive(Clone, Debug)]
pub struct U64MarkerAllocator {
index: u64,
mapping: HashMap<u64, Entity>,
}
impl Default for U64MarkerAllocator {
fn default() -> Self {
U64MarkerAllocator::new()
}
}
impl U64MarkerAllocator {
pub fn new() -> Self {
U64MarkerAllocator {
index: 0,
mapping: HashMap::new(),
}
}
}
impl MarkerAllocator<U64Marker> for U64MarkerAllocator {
fn allocate(&mut self, entity: Entity, id: Option<u64>) -> U64Marker {
let marker = if let Some(id) = id {
U64Marker(id)
} else {
self.index += 1;
U64Marker(self.index - 1)
};
self.mapping.insert(marker.id(), entity);
marker
}
fn retrieve_entity_internal(&self, id: u64) -> Option<Entity> {
self.mapping.get(&id).cloned()
}
fn maintain(&mut self, entities: &EntitiesRes, storage: &ReadStorage<U64Marker>) {
self.mapping = (&*entities, storage)
.join()
.map(|(e, m)| (m.id(), e))
.collect();
}
}