Skip to content

Instantly share code, notes, and snippets.

Created April 27, 2017 13:35
Show Gist options
  • Save anonymous/e2dfadb439c00ad25a20b5cbc99b2b8a to your computer and use it in GitHub Desktop.
Save anonymous/e2dfadb439c00ad25a20b5cbc99b2b8a to your computer and use it in GitHub Desktop.
Shared via Rust Playground
use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::Entry;
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
struct EntityId(usize);
enum Component {
}
#[derive(Debug, Eq, PartialEq)]
enum WorldError {
/// Indicates that no more entities may be created because we have exceeded the maximum amount allowed for this World.
ExceededMaximumEntityLimit
}
/// Maintains the current state of the game World.
/// The World will create and delete entities.
struct World {
maximum_entities: usize,
next_new_id: usize,
reuse_pool: VecDeque<EntityId>,
components: HashMap<EntityId, Vec<Component>>
}
impl World {
fn new() -> Self {
Self::with_maximum_capacity(::std::usize::MAX)
}
/// Returns a new World with the maximum number of entities.
fn with_maximum_capacity(max: usize) -> Self {
World {
maximum_entities: max,
reuse_pool: VecDeque::new(),
// We will eventually reach a point where no new entities will need to be created due to reuse;
// this will also limit fragmentation. However, there could come a point when next-ne
next_new_id: 0,
components: HashMap::new()
}
}
fn create_entity(&mut self) -> Result<EntityId, WorldError> {
if let Some(e) = self.reuse_pool.pop_front() {
self.components.insert(e, Vec::new());
return Ok(e)
}
// Due to the above code, there should come a point where we no longer need to create 'new' entities because of reuse, which should also limit fragmentation. However, there will eventually come a limit where we are simply unable to create more entities due to exceeding the maximum size of the id counter (in this case, usize). In that case, we need to be courteous and return an error. This is why we return a Result and not a raw EntityId.
if self.next_new_id >= self.maximum_entities {
return Err(WorldError::ExceededMaximumEntityLimit);
}
let e = EntityId(self.next_new_id);
self.next_new_id = self.next_new_id + 1;
self.components.insert(e, Vec::new());
Ok(e)
}
fn get_components(&self, entity_id: EntityId) -> Option<&[Component]> {
self.components.get(&entity_id).map(|x| x.as_slice())
}
fn destroy_entity(&mut self, entity_id: EntityId) -> () {
if let Entry::Occupied(mut e) = self.components.entry(entity_id) {
e.insert(Vec::new());
self.reuse_pool.push_back(entity_id);
}
}
}
#[cfg(test)]
mod test {
use super::{World, WorldError};
#[test]
fn world_create_new_entity_returns_entity_with_no_components() {
let mut world = World::new();
let entity = world.create_entity().unwrap();
assert_eq!(world.get_components(entity).unwrap().len(), 0);
}
#[test]
fn world_will_not_give_duplicate_entity_ids() {
let mut world = World::new();
let e1 = world.create_entity().unwrap();
let e2 = world.create_entity().unwrap();
assert!(e1 != e2);
}
#[allow(unused_must_use)]
#[test]
fn world_will_reuse_entity_id_if_destroyed() {
let mut world = World::new();
let e1 = world.create_entity().unwrap();
world.create_entity();
world.destroy_entity(e1);
let e3 = world.create_entity().unwrap();
assert_eq!(e1, e3);
}
#[allow(unused_must_use)]
#[test]
fn world_returns_failure_if_we_attempt_to_exceed_maximum_threshold() {
let mut world = World::with_maximum_capacity(1);
world.create_entity();
assert_eq!(world.create_entity(), Err(WorldError::ExceededMaximumEntityLimit));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment