rustbatch/entities/
storage.rs

1/// ComponentArray is alternative to storing components in hashmap. Its considerable faster to
2/// access elements of course there is a cost for that. You cannot choose your own ids ComponentArray
3/// generates them for you. Model is surprisingly simple but powerful. To use this properly you have
4/// to ALWAYS remove no longer needed component unless you like memory leaks.
5pub struct ComponentArray<T> {
6    inner: Vec<Option<T>>,
7    ids: Vec<usize>,
8    len: usize,
9    id: usize,
10}
11
12impl<T> ComponentArray<T> {
13    #[inline]
14    pub fn new() -> Self {
15        Self {
16            inner: vec![None],
17            ids: vec![],
18            len: 0,
19            id: 0,
20        }
21    }
22
23    /// insert takes an value and returns id to is. (Its not really id but you can use it like it)
24    #[inline]
25    pub fn insert(&mut self, component: T) -> usize {
26        self.len = self.inner.len();
27        if self.ids.is_empty() {
28            self.inner.push(Some(component));
29            return self.len
30        }
31        self.len = self.ids.len() - 1;
32        self.id = self.ids[self.len];
33        self.inner[self.id] = Some(component);
34        self.ids.truncate(self.len);
35
36        self.id
37    }
38
39    #[inline]
40    pub fn len(&self) -> usize {
41        self.inner.len()
42    }
43
44    /// remove is important. Always remove the objects so memory can be reused for another one.
45    #[inline]
46    pub fn remove(&mut self, id: usize) -> T {
47        if let None = self.inner[id] {
48            panic!("value with given id is already none, call put_back and then remove, calling \
49            just get instead of remove produces memory leak because space is still considered occupied.");
50        }
51        self.ids.push(id);
52        unsafe { self.get(id).unwrap() }
53    }
54
55    #[inline]
56    pub fn remove_if_present(&mut self, id: usize) -> Option<T> {
57        if let None = self.inner[id] {
58            return None
59        }
60        self.ids.push(id);
61        unsafe { self.get(id) }
62    }
63
64    /// get is not equivalent fo remove, if you do not put back what you taken you are leaking memory
65    /// because ComponentArray still considers it occupied. Function is here to solve situations when
66    /// you need mutable and immutable asses to array elements at the same time
67    #[inline]
68    pub unsafe fn get(&mut self, id: usize) -> Option<T> {
69        std::mem::replace(&mut self.inner[id], None)
70    }
71
72    /// Call this after get on the same id. This function is unsafe for a reason, you can very easily
73    /// put your data somewhere where its considered free and it can then be overwrite by insert call
74    #[inline]
75    pub unsafe fn put_back(&mut self, id: usize, component: T) {
76        self.inner[id] = Some(component);
77    }
78
79    /// get_ref returns reference to element or none
80    #[inline]
81    pub fn get_ref(&self, id: usize) -> &Option<T> {
82        &self.inner[id]
83    }
84
85    /// get:mut returns mutable reference or none
86    #[inline]
87    pub fn get_mut(&mut self, id: usize) -> &mut Option<T> {
88        &mut self.inner[id]
89    }
90}
91
92