calx_ecs/
lib.rs

1//! Entity component system
2
3#![deny(missing_docs)]
4
5#[macro_use]
6extern crate serde_derive;
7extern crate serde;
8
9use std::default::Default;
10use std::ops;
11use std::slice;
12
13use serde::{Serialize, Deserialize};
14
15/// Handle for an entity in the entity component system.
16#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
17pub struct Entity {
18    uid: u32,
19    idx: u32,
20}
21
22/// Indexing entity index to data array.
23#[derive(Copy, Clone, PartialEq, Eq, Default, Debug, Serialize, Deserialize)]
24struct Index {
25    /// Must match the uid for the entity that is querying for component.
26    uid: u32,
27    /// Index for this entity in the data array.
28    data_idx: u32,
29}
30
31/// Operations all components must support.
32pub trait AnyComponent {
33    /// Remove an entity's component.
34    fn remove(&mut self, e: Entity);
35}
36
37/// Nonredundant component data, in separate struct for efficient serialization.
38#[derive(Serialize, Deserialize)]
39struct DenseComponentData<C> {
40    /// Dense component data.
41    data: Vec<C>,
42    /// Entity idx corresponding to elements in data.
43    entities: Vec<Entity>,
44}
45
46/// Storage for a single component type.
47pub struct ComponentData<C> {
48    inner: DenseComponentData<C>,
49    /// Map entity indices to component data.
50    ///
51    /// This array spans all live component indices.
52    entity_idx_to_data: Vec<Index>,
53}
54
55impl<C> ComponentData<C> {
56    /// Construct new empty `ComponentData` instance.
57    pub fn new() -> ComponentData<C> {
58        ComponentData {
59            inner: DenseComponentData {
60                data: Vec::new(),
61                entities: Vec::new(),
62            },
63            entity_idx_to_data: Vec::new(),
64        }
65    }
66
67    /// Insert a component to an entity.
68    pub fn insert(&mut self, e: Entity, comp: C) {
69        debug_assert_eq!(self.inner.data.len(), self.inner.entities.len());
70
71        if self.contains(e) {
72            // Component is set for entity, replace existing component.
73            self.inner.data[self.entity_idx_to_data[e.idx as usize].data_idx as usize] = comp;
74        } else {
75            // Grow lookup vector if needed.
76            if e.idx as usize >= self.entity_idx_to_data.len() {
77                self.entity_idx_to_data.resize(
78                    e.idx as usize + 1,
79                    Default::default(),
80                );
81            }
82
83            // Add a new component.
84            let data_idx = self.inner.data.len() as u32;
85            self.inner.data.push(comp);
86            self.inner.entities.push(e);
87            self.entity_idx_to_data[e.idx as usize] = Index {
88                uid: e.uid,
89                data_idx: data_idx,
90            };
91        }
92    }
93
94    /// Return whether an entity contains this component.
95    pub fn contains(&self, e: Entity) -> bool {
96        debug_assert_ne!(e.uid, 0);
97
98        (e.idx as usize) < self.entity_idx_to_data.len() &&
99            self.entity_idx_to_data[e.idx as usize].uid == e.uid
100    }
101
102    /// Get a reference to a component only if it exists for this entity.
103    pub fn get(&self, e: Entity) -> Option<&C> {
104        if self.contains(e) {
105            Some(
106                &self.inner.data[self.entity_idx_to_data[e.idx as usize].data_idx as usize],
107            )
108        } else {
109            None
110        }
111    }
112
113    /// Get a mutable reference to a component only if it exists for this entity.
114    pub fn get_mut(&mut self, e: Entity) -> Option<&mut C> {
115        if self.contains(e) {
116            Some(
117                &mut self.inner.data[self.entity_idx_to_data[e.idx as usize].data_idx as usize],
118            )
119        } else {
120            None
121        }
122    }
123
124    /// Iterate entity ids in this component.
125    pub fn ent_iter(&self) -> slice::Iter<Entity> {
126        self.inner.entities.iter()
127    }
128
129    /// Iterate elements in this component.
130    pub fn iter(&self) -> slice::Iter<C> {
131        self.inner.data.iter()
132    }
133
134    /// Iterate mutable elements in this component.
135    pub fn iter_mut(&mut self) -> slice::IterMut<C> {
136        self.inner.data.iter_mut()
137    }
138}
139
140impl<C> ops::Index<Entity> for ComponentData<C> {
141    type Output = C;
142
143    fn index(&self, e: Entity) -> &C {
144        self.get(e).unwrap()
145    }
146}
147
148impl<C> ops::IndexMut<Entity> for ComponentData<C> {
149    fn index_mut(&mut self, e: Entity) -> &mut C {
150        self.get_mut(e).unwrap()
151    }
152}
153
154impl<C> AnyComponent for ComponentData<C> {
155    fn remove(&mut self, e: Entity) {
156        debug_assert_eq!(self.inner.data.len(), self.inner.entities.len());
157        if self.contains(e) {
158            let removed_index = self.entity_idx_to_data[e.idx as usize];
159            self.entity_idx_to_data[e.idx as usize] = Default::default();
160
161            // To keep the data compact, we do swap-remove with the last data item and update the
162            // lookup on the moved item. If the component being removed isn't the last item in the
163            // list, we need to reset the lookup value for the component that was moved.
164            if removed_index.data_idx as usize != self.inner.entities.len() - 1 {
165                let last_entity = self.inner.entities[self.inner.entities.len() - 1];
166                self.inner.entities.swap_remove(
167                    removed_index.data_idx as usize,
168                );
169                self.entity_idx_to_data[last_entity.idx as usize] = Index {
170                    uid: last_entity.uid,
171                    data_idx: removed_index.data_idx,
172                };
173            } else {
174                self.inner.entities.swap_remove(
175                    removed_index.data_idx as usize,
176                );
177            }
178
179            self.inner.data.swap_remove(removed_index.data_idx as usize);
180        }
181    }
182}
183
184#[derive(Serialize, Deserialize)]
185struct Packed<C> {
186    entity_count: u32,
187    data: Vec<C>,
188    entities: Vec<Entity>,
189}
190
191impl<C: Serialize + Clone> serde::Serialize for ComponentData<C> {
192    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
193        self.inner.serialize(s)
194    }
195}
196
197impl<'a, C: Deserialize<'a>> serde::Deserialize<'a> for ComponentData<C> {
198    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
199        let inner: DenseComponentData<C> = serde::Deserialize::deserialize(d)?;
200
201        // Regenerate cache.
202        let mut entity_idx_to_data = Vec::new();
203        for (i, e) in inner.entities.iter().enumerate() {
204            if e.idx as usize >= entity_idx_to_data.len() {
205                entity_idx_to_data.resize(e.idx as usize + 1, Default::default());
206            }
207            entity_idx_to_data[e.idx as usize] = Index {
208                uid: e.uid,
209                data_idx: i as u32,
210            };
211        }
212
213        Ok(ComponentData {
214            inner: inner,
215            entity_idx_to_data: entity_idx_to_data,
216        })
217    }
218}
219
220/// Operations for the internal component store object.
221pub trait Store {
222    /// Perform an operation for each component container.
223    fn for_each_component<F>(&mut self, f: F)
224    where
225        F: FnMut(&mut AnyComponent);
226}
227
228/// Generic entity component system container
229///
230/// Needs to be specified with the parametrized `Store` type that has struct fields for the actual
231/// components. This can be done with the `Ecs!` macro.
232#[derive(Serialize, Deserialize)]
233pub struct Ecs<ST> {
234    next_uid: u32,
235    next_idx: u32,
236    free_indices: Vec<u32>,
237    active: ComponentData<bool>,
238    store: ST,
239}
240
241impl<ST: Default + Store> Ecs<ST> {
242    /// Construct a new entity component system.
243    pub fn new() -> Ecs<ST> {
244        Ecs {
245            next_uid: 1,
246            next_idx: 0,
247            free_indices: Vec::new(),
248            active: ComponentData::new(),
249            store: Default::default(),
250        }
251    }
252
253    /// Create a new empty entity.
254    pub fn make(&mut self) -> Entity {
255        let uid = self.next_uid;
256        self.next_uid += 1;
257
258        let idx = if let Some(idx) = self.free_indices.pop() {
259            idx
260        } else {
261            self.next_idx += 1;
262            self.next_idx - 1
263        };
264
265        let ret = Entity { uid: uid, idx: idx };
266        self.active.insert(ret, true);
267        ret
268    }
269
270    /// Remove an entity from the system and clear its components.
271    pub fn remove(&mut self, e: Entity) {
272        if self.contains(e) {
273            self.free_indices.push(e.idx);
274            self.active.remove(e);
275            self.store.for_each_component(|c| c.remove(e));
276        }
277    }
278
279    /// Return whether the system contains an entity.
280    pub fn contains(&self, e: Entity) -> bool {
281        self.active.contains(e)
282    }
283
284    /// Iterate through all the active entities.
285    pub fn iter(&self) -> slice::Iter<Entity> {
286        self.active.ent_iter()
287    }
288}
289
290impl<ST> ops::Deref for Ecs<ST> {
291    type Target = ST;
292
293    fn deref(&self) -> &ST {
294        &self.store
295    }
296}
297
298impl<ST> ops::DerefMut for Ecs<ST> {
299    fn deref_mut(&mut self) -> &mut ST {
300        &mut self.store
301    }
302}
303
304/// Entity component system builder macro.
305///
306/// Defines a local `Ecs` type that's parametrized with a custom component
307/// store type with the component types you specify. Will also define a trait
308/// `Component` which will be implemented for the component types.
309#[macro_export]
310macro_rules! Ecs {
311    {
312        // Declare the type of the (plain old data) component and the
313        // identifier to use for it in the ECS.
314        $($compname:ident: $comptype:ty,)+
315    } => {
316        mod _ecs_inner {
317            // Use the enum to convert components to numbers for component bit masks etc.
318            #[allow(non_camel_case_types, dead_code)]
319            pub enum ComponentNum {
320                $($compname,)+
321            }
322
323        }
324
325        pub use self::_ecs_inner::ComponentNum;
326
327        #[derive(Serialize, Deserialize)]
328        pub struct _ComponentStore {
329            $(pub $compname: $crate::ComponentData<$comptype>),+
330        }
331
332        impl ::std::default::Default for _ComponentStore {
333            fn default() -> _ComponentStore {
334                _ComponentStore {
335                    $($compname: $crate::ComponentData::new()),+
336                }
337            }
338        }
339
340        impl $crate::Store for _ComponentStore {
341            fn for_each_component<F>(&mut self, mut f: F)
342                where F: FnMut(&mut $crate::AnyComponent)
343            {
344                $(f(&mut self.$compname as &mut $crate::AnyComponent);)+
345            }
346        }
347
348        #[allow(dead_code)]
349        pub fn matches_mask(ecs: &$crate::Ecs<_ComponentStore>, e: $crate::Entity, mask: u64) -> bool {
350            $(if mask & (1 << ComponentNum::$compname as u8) != 0 && !ecs.$compname.contains(e) {
351                return false;
352            })+
353            return true;
354        }
355
356        /// Common operations for ECS component value types.
357        pub trait Component {
358            /// Add a clone of the component value to an entity in an ECS.
359            ///
360            /// Can't move the component itself since we might be using this
361            /// through a trait object.
362            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity);
363
364            /// Add a clone of the component to a loadout struct.
365            fn add_to_loadout(self, loadout: &mut Loadout);
366        }
367
368        $(impl Component for $comptype {
369            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity) {
370                ecs.$compname.insert(e, self.clone());
371            }
372
373            fn add_to_loadout(self, loadout: &mut Loadout) {
374                loadout.$compname = Some(self);
375            }
376        })+
377
378        pub type Ecs = $crate::Ecs<_ComponentStore>;
379
380        /// A straightforward representation for the complete data of an
381        /// entity.
382        #[derive(Clone, Debug, Serialize, Deserialize)]
383        pub struct Loadout {
384            $(pub $compname: Option<$comptype>),+
385        }
386
387        impl ::std::default::Default for Loadout {
388            fn default() -> Loadout {
389                Loadout {
390                    $($compname: None),+
391                }
392            }
393        }
394
395        #[allow(dead_code)]
396        impl Loadout {
397            /// Create a new blank loadout.
398            pub fn new() -> Loadout { Default::default() }
399
400            /// Get the loadout that corresponds to an existing entity.
401            pub fn get(ecs: &Ecs, e: $crate::Entity) -> Loadout {
402                Loadout {
403                    $($compname: ecs.$compname.get(e).cloned()),+
404                }
405            }
406
407            /// Create a new entity in the ECS with this loadout.
408            pub fn make(&self, ecs: &mut Ecs) -> $crate::Entity {
409                let e = ecs.make();
410                $(self.$compname.as_ref().map(|c| ecs.$compname.insert(e, c.clone()));)+
411                e
412            }
413
414            /// Builder method for adding a component to this loadout.
415            pub fn c<C: Component>(mut self, comp: C) -> Loadout {
416                comp.add_to_loadout(&mut self);
417                self
418            }
419        }
420    }
421}
422
423/// Build a component type mask to match component iteration with.
424///
425/// You must have `ComponentNum` enum from the Ecs! macro expansion in scope
426/// when using this.
427#[macro_export]
428macro_rules! build_mask {
429    ( $($compname:ident),+ ) => {
430        0u64 $(| (1u64 << ComponentNum::$compname as u8))+
431    }
432}