extern crate shrev; extern crate specs; extern crate specs_mirror; use shrev::{EventChannel, ReaderId}; use specs::prelude::*; use specs::world::Index; use specs_mirror::*; use std::collections::HashMap; use std::sync::Arc; #[derive(Clone, Debug, PartialEq, Eq)] struct Comp(Arc); impl Component for Comp { type Storage = MirroredStorage; } enum CompEvent { Inserted(Index, Comp), Removed(Index, Comp), } impl Mirrored for Comp { type Event = CompEvent; fn insert(&mut self, chan: &mut EventChannel, id: Index) { chan.single_write(CompEvent::Inserted(id, self.clone())); } fn remove(&mut self, chan: &mut EventChannel, id: Index) { chan.single_write(CompEvent::Removed(id, self.clone())); } } impl Comp { fn set(&mut self, chan: &mut EventChannel, entity: Entity, state: Comp) { chan.single_write(CompEvent::Removed(entity.id(), self.clone())); *self = state; chan.single_write(CompEvent::Inserted(entity.id(), self.clone())); } } struct CompSystem { reader: ReaderId, store: HashMap, } impl CompSystem { fn new(mut store: WriteStorage) -> Self { let reader = store.register_reader(); let store = HashMap::new(); CompSystem { reader, store } } } impl<'a> System<'a> for CompSystem { type SystemData = ReadStorage<'a, Comp>; fn run(&mut self, comp: Self::SystemData) { for event in comp.read_events(&mut self.reader) { match *event { CompEvent::Inserted(id, ref data) => { assert!(self.store.insert(id, data.clone()).is_none()) } CompEvent::Removed(id, ref data) => { assert_eq!(self.store.remove(&id), Some(data.clone())) } } } } } const ACTIONS: usize = 4; fn modify(comps: &mut WriteStorage, ent: Entity, i: usize) { match i % ACTIONS { 0 => { comps .insert(ent, Comp(Arc::from(ent.id().to_string()))) .unwrap(); } 1 => { comps.remove(ent); } 3 => { if let Some((comp, chan)) = comps.modify(ent) { comp.set(chan, ent, Comp(Arc::from(ent.id().to_string()))); } } _ => (), } } fn test_synced(ents: Entities, left: ReadStorage, right: &HashMap) { let left: HashMap = (&*ents, &left) .join() .map(|(ent, comp)| (ent.id(), comp.clone())) .collect(); assert_eq!(&left, right); } #[test] fn test() { const N: u32 = 6; let mut world = World::new(); world.register::(); let mut sys = CompSystem::new(world.write_storage::()); let entities: Vec = world.create_iter().take(ACTIONS.pow(N)).collect(); sys.run_now(&mut world.res); test_synced(world.entities(), world.read_storage::(), &sys.store); { let mut comps = world.write_storage::(); for (mut i, &ent) in entities.iter().enumerate() { for _ in 0..N { modify(&mut comps, ent, i); i /= ACTIONS; } assert_eq!(i, 0); } } sys.run_now(&mut world.res); test_synced(world.entities(), world.read_storage::(), &sys.store); { let mut comps = world.write_storage::(); for (mut i, &ent) in entities.iter().rev().enumerate() { for _ in 0..N { modify(&mut comps, ent, i); i /= ACTIONS; } assert_eq!(i, 0); } } sys.run_now(&mut world.res); test_synced(world.entities(), world.read_storage::(), &sys.store); }