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 allocate(&mut self, len: usize) -> EntityId {
31 let offset = self.data.len() as u32;
32 self.data.resize(self.data.len() + len, PsObject::null());
33 self.entities.allocate(offset, len as u32, 0, false, 0)
34 }
35
36 pub fn allocate_from(&mut self, items: &[PsObject]) -> EntityId {
38 let offset = self.data.len() as u32;
39 self.data.extend_from_slice(items);
40 self.entities
41 .allocate(offset, items.len() as u32, 0, false, 0)
42 }
43
44 pub fn allocate_from_with(
46 &mut self,
47 items: &[PsObject],
48 save_level: u16,
49 global: bool,
50 created_after_save: u32,
51 ) -> EntityId {
52 let offset = self.data.len() as u32;
53 self.data.extend_from_slice(items);
54 self.entities.allocate(
55 offset,
56 items.len() as u32,
57 save_level,
58 global,
59 created_after_save,
60 )
61 }
62
63 pub fn allocate_with(
65 &mut self,
66 len: usize,
67 save_level: u16,
68 global: bool,
69 created_after_save: u32,
70 ) -> EntityId {
71 let offset = self.data.len() as u32;
72 self.data.resize(self.data.len() + len, PsObject::null());
73 self.entities
74 .allocate(offset, len as u32, save_level, global, created_after_save)
75 }
76
77 pub fn get(&self, entity: EntityId, start: u32, len: u32) -> &[PsObject] {
79 let base = self.entities.get(entity).offset as usize + start as usize;
80 &self.data[base..base + len as usize]
81 }
82
83 pub fn get_mut(&mut self, entity: EntityId, start: u32, len: u32) -> &mut [PsObject] {
85 let base = self.entities.get(entity).offset as usize + start as usize;
86 &mut self.data[base..base + len as usize]
87 }
88
89 #[inline]
91 pub fn get_element(&self, entity: EntityId, index: u32) -> PsObject {
92 let base = self.entities.get(entity).offset as usize;
93 self.data[base + index as usize]
94 }
95
96 pub fn set_element(&mut self, entity: EntityId, index: u32, obj: PsObject) {
98 let base = self.entities.get(entity).offset as usize;
99 self.data[base + index as usize] = obj;
100 }
101
102 pub fn cow_copy(&mut self, entity: EntityId) -> EntityId {
106 let meta = self.entities.get(entity);
107 let old_offset = meta.offset as usize;
108 let len = meta.len;
109 let save_level = meta.save_level;
110 let is_global = meta.is_global();
111 let created_after_save = meta.created_after_save;
112
113 let temp: Vec<PsObject> = self.data[old_offset..old_offset + len as usize].to_vec();
114 let new_offset = self.data.len() as u32;
115 self.data.extend_from_slice(&temp);
116
117 let copy_id = self.entities.allocate(
119 meta.offset, len,
121 save_level,
122 is_global,
123 created_after_save,
124 );
125
126 self.entities.get_mut(entity).offset = new_offset;
128
129 copy_id
130 }
131
132 pub fn swap_offsets(&mut self, a: EntityId, b: EntityId) {
134 let off_a = self.entities.get(a).offset;
135 let off_b = self.entities.get(b).offset;
136 self.entities.get_mut(a).offset = off_b;
137 self.entities.get_mut(b).offset = off_a;
138 }
139}
140
141impl Default for ArrayStore {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use crate::object::PsValue;
151
152 #[test]
153 fn test_allocate_from() {
154 let mut store = ArrayStore::new();
155 let items = [PsObject::int(1), PsObject::int(2), PsObject::int(3)];
156 let id = store.allocate_from(&items);
157 assert_eq!(store.get_element(id, 0).as_i32(), Some(1));
158 assert_eq!(store.get_element(id, 1).as_i32(), Some(2));
159 assert_eq!(store.get_element(id, 2).as_i32(), Some(3));
160 }
161
162 #[test]
163 fn test_allocate_null_filled() {
164 let mut store = ArrayStore::new();
165 let id = store.allocate(3);
166 for i in 0..3 {
167 assert!(matches!(store.get_element(id, i).value, PsValue::Null));
168 }
169 }
170
171 #[test]
172 fn test_set_element() {
173 let mut store = ArrayStore::new();
174 let id = store.allocate(2);
175 store.set_element(id, 0, PsObject::int(42));
176 assert_eq!(store.get_element(id, 0).as_i32(), Some(42));
177 }
178
179 #[test]
180 fn test_subarray_view() {
181 let mut store = ArrayStore::new();
182 let items = [
183 PsObject::int(10),
184 PsObject::int(20),
185 PsObject::int(30),
186 PsObject::int(40),
187 ];
188 let id = store.allocate_from(&items);
189 let sub = store.get(id, 1, 2);
191 assert_eq!(sub[0].as_i32(), Some(20));
192 assert_eq!(sub[1].as_i32(), Some(30));
193 }
194
195 #[test]
196 fn test_cow_copy() {
197 let mut store = ArrayStore::new();
198 let items = [PsObject::int(1), PsObject::int(2), PsObject::int(3)];
199 let id = store.allocate_from(&items);
200
201 let backup = store.cow_copy(id);
202
203 store.set_element(id, 0, PsObject::int(99));
205 assert_eq!(store.get_element(id, 0).as_i32(), Some(99));
206 assert_eq!(store.get_element(backup, 0).as_i32(), Some(1));
207 }
208
209 #[test]
210 fn test_swap_offsets() {
211 let mut store = ArrayStore::new();
212 let id1 = store.allocate_from(&[PsObject::int(1)]);
213 let id2 = store.allocate_from(&[PsObject::int(2)]);
214
215 store.swap_offsets(id1, id2);
216 assert_eq!(store.get_element(id1, 0).as_i32(), Some(2));
217 assert_eq!(store.get_element(id2, 0).as_i32(), Some(1));
218 }
219}