1use crate::entity_table::EntityTable;
13use crate::object::{EntityId, PsObject};
14
15pub struct ArrayStore {
17 data: Vec<PsObject>,
18 pub entities: EntityTable,
19}
20
21impl ArrayStore {
22 pub fn new() -> Self {
23 Self {
24 data: Vec::new(),
25 entities: EntityTable::new(),
26 }
27 }
28
29 pub fn allocated_objects(&self) -> usize {
36 self.data.len()
37 }
38
39 pub fn truncate_to(&mut self, data_len: usize, entity_len: usize) {
45 self.data.truncate(data_len);
46 self.entities.truncate(entity_len);
47 }
48
49 pub fn allocate(&mut self, len: usize) -> EntityId {
51 let offset = self.data.len() as u32;
52 self.data.resize(self.data.len() + len, PsObject::null());
53 self.entities.allocate(offset, len as u32, 0, false, 0)
54 }
55
56 pub fn allocate_from(&mut self, items: &[PsObject]) -> EntityId {
58 let offset = self.data.len() as u32;
59 self.data.extend_from_slice(items);
60 self.entities
61 .allocate(offset, items.len() as u32, 0, false, 0)
62 }
63
64 pub fn allocate_from_with(
66 &mut self,
67 items: &[PsObject],
68 save_level: u16,
69 global: bool,
70 created_after_save: u32,
71 ) -> EntityId {
72 let offset = self.data.len() as u32;
73 self.data.extend_from_slice(items);
74 self.entities.allocate(
75 offset,
76 items.len() as u32,
77 save_level,
78 global,
79 created_after_save,
80 )
81 }
82
83 pub fn allocate_with(
85 &mut self,
86 len: usize,
87 save_level: u16,
88 global: bool,
89 created_after_save: u32,
90 ) -> EntityId {
91 let offset = self.data.len() as u32;
92 self.data.resize(self.data.len() + len, PsObject::null());
93 self.entities
94 .allocate(offset, len as u32, save_level, global, created_after_save)
95 }
96
97 pub fn iter_entities(&self) -> impl Iterator<Item = (EntityId, &[PsObject])> {
104 (0..self.entities.len()).map(|i| {
105 let meta = self.entities.get_by_index(i);
106 let id = if meta.is_global() {
107 EntityId::global(i as u32)
108 } else {
109 EntityId::local(i as u32)
110 };
111 let base = meta.offset as usize;
112 (id, &self.data[base..base + meta.len as usize])
113 })
114 }
115
116 pub fn get(&self, entity: EntityId, start: u32, len: u32) -> &[PsObject] {
118 let base = self.entities.get(entity).offset as usize + start as usize;
119 &self.data[base..base + len as usize]
120 }
121
122 pub fn get_mut(&mut self, entity: EntityId, start: u32, len: u32) -> &mut [PsObject] {
124 let base = self.entities.get(entity).offset as usize + start as usize;
125 &mut self.data[base..base + len as usize]
126 }
127
128 #[inline]
130 pub fn get_element(&self, entity: EntityId, index: u32) -> PsObject {
131 let base = self.entities.get(entity).offset as usize;
132 self.data[base + index as usize]
133 }
134
135 pub fn set_element(&mut self, entity: EntityId, index: u32, obj: PsObject) {
137 let base = self.entities.get(entity).offset as usize;
138 self.data[base + index as usize] = obj;
139 }
140
141 pub fn cow_copy(&mut self, entity: EntityId) -> EntityId {
145 let meta = self.entities.get(entity);
146 let old_offset = meta.offset as usize;
147 let len = meta.len;
148 let save_level = meta.save_level;
149 let is_global = meta.is_global();
150 let created_after_save = meta.created_after_save;
151
152 let temp: Vec<PsObject> = self.data[old_offset..old_offset + len as usize].to_vec();
153 let new_offset = self.data.len() as u32;
154 self.data.extend_from_slice(&temp);
155
156 let copy_id = self.entities.allocate(
158 meta.offset, len,
160 save_level,
161 is_global,
162 created_after_save,
163 );
164
165 self.entities.get_mut(copy_id).set_cow_backup();
166
167 self.entities.get_mut(entity).offset = new_offset;
169
170 copy_id
171 }
172
173 pub fn swap_offsets(&mut self, a: EntityId, b: EntityId) {
175 let off_a = self.entities.get(a).offset;
176 let off_b = self.entities.get(b).offset;
177 self.entities.get_mut(a).offset = off_b;
178 self.entities.get_mut(b).offset = off_a;
179 }
180}
181
182impl Default for ArrayStore {
183 fn default() -> Self {
184 Self::new()
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use crate::object::PsValue;
192
193 #[test]
194 fn test_allocate_from() {
195 let mut store = ArrayStore::new();
196 let items = [PsObject::int(1), PsObject::int(2), PsObject::int(3)];
197 let id = store.allocate_from(&items);
198 assert_eq!(store.get_element(id, 0).as_i32(), Some(1));
199 assert_eq!(store.get_element(id, 1).as_i32(), Some(2));
200 assert_eq!(store.get_element(id, 2).as_i32(), Some(3));
201 }
202
203 #[test]
204 fn test_allocate_null_filled() {
205 let mut store = ArrayStore::new();
206 let id = store.allocate(3);
207 for i in 0..3 {
208 assert!(matches!(store.get_element(id, i).value, PsValue::Null));
209 }
210 }
211
212 #[test]
213 fn test_set_element() {
214 let mut store = ArrayStore::new();
215 let id = store.allocate(2);
216 store.set_element(id, 0, PsObject::int(42));
217 assert_eq!(store.get_element(id, 0).as_i32(), Some(42));
218 }
219
220 #[test]
221 fn test_subarray_view() {
222 let mut store = ArrayStore::new();
223 let items = [
224 PsObject::int(10),
225 PsObject::int(20),
226 PsObject::int(30),
227 PsObject::int(40),
228 ];
229 let id = store.allocate_from(&items);
230 let sub = store.get(id, 1, 2);
232 assert_eq!(sub[0].as_i32(), Some(20));
233 assert_eq!(sub[1].as_i32(), Some(30));
234 }
235
236 #[test]
237 fn test_cow_copy() {
238 let mut store = ArrayStore::new();
239 let items = [PsObject::int(1), PsObject::int(2), PsObject::int(3)];
240 let id = store.allocate_from(&items);
241
242 let backup = store.cow_copy(id);
243
244 store.set_element(id, 0, PsObject::int(99));
246 assert_eq!(store.get_element(id, 0).as_i32(), Some(99));
247 assert_eq!(store.get_element(backup, 0).as_i32(), Some(1));
248 }
249
250 #[test]
251 fn test_swap_offsets() {
252 let mut store = ArrayStore::new();
253 let id1 = store.allocate_from(&[PsObject::int(1)]);
254 let id2 = store.allocate_from(&[PsObject::int(2)]);
255
256 store.swap_offsets(id1, id2);
257 assert_eq!(store.get_element(id1, 0).as_i32(), Some(2));
258 assert_eq!(store.get_element(id2, 0).as_i32(), Some(1));
259 }
260}