arms/adapters/storage/
memory.rs1use std::collections::HashMap;
12
13use crate::core::{Blob, Id, PlacedPoint, Point};
14use crate::ports::{Place, PlaceError, PlaceResult};
15
16pub struct MemoryStorage {
18 points: HashMap<Id, PlacedPoint>,
20
21 dimensionality: usize,
23
24 capacity: usize,
26
27 current_size: usize,
29}
30
31impl MemoryStorage {
32 pub fn new(dimensionality: usize) -> Self {
34 Self {
35 points: HashMap::new(),
36 dimensionality,
37 capacity: 0,
38 current_size: 0,
39 }
40 }
41
42 pub fn with_capacity(dimensionality: usize, capacity: usize) -> Self {
44 Self {
45 points: HashMap::new(),
46 dimensionality,
47 capacity,
48 current_size: 0,
49 }
50 }
51
52 fn point_size(point: &PlacedPoint) -> usize {
54 16 + (point.point.dimensionality() * 4) + point.blob.size() + 48
59 }
60}
61
62impl Place for MemoryStorage {
63 fn place(&mut self, point: Point, blob: Blob) -> PlaceResult<Id> {
64 if point.dimensionality() != self.dimensionality {
66 return Err(PlaceError::DimensionalityMismatch {
67 expected: self.dimensionality,
68 got: point.dimensionality(),
69 });
70 }
71
72 let id = Id::now();
73 let placed = PlacedPoint::new(id, point, blob);
74
75 let size = Self::point_size(&placed);
77 if self.capacity > 0 && self.current_size + size > self.capacity {
78 return Err(PlaceError::CapacityExceeded);
79 }
80
81 self.current_size += size;
82 self.points.insert(id, placed);
83
84 Ok(id)
85 }
86
87 fn place_with_id(&mut self, id: Id, point: Point, blob: Blob) -> PlaceResult<()> {
88 if point.dimensionality() != self.dimensionality {
90 return Err(PlaceError::DimensionalityMismatch {
91 expected: self.dimensionality,
92 got: point.dimensionality(),
93 });
94 }
95
96 if self.points.contains_key(&id) {
98 return Err(PlaceError::DuplicateId(id));
99 }
100
101 let placed = PlacedPoint::new(id, point, blob);
102
103 let size = Self::point_size(&placed);
105 if self.capacity > 0 && self.current_size + size > self.capacity {
106 return Err(PlaceError::CapacityExceeded);
107 }
108
109 self.current_size += size;
110 self.points.insert(id, placed);
111
112 Ok(())
113 }
114
115 fn remove(&mut self, id: Id) -> Option<PlacedPoint> {
116 if let Some(placed) = self.points.remove(&id) {
117 self.current_size -= Self::point_size(&placed);
118 Some(placed)
119 } else {
120 None
121 }
122 }
123
124 fn get(&self, id: Id) -> Option<&PlacedPoint> {
125 self.points.get(&id)
126 }
127
128 fn len(&self) -> usize {
129 self.points.len()
130 }
131
132 fn iter(&self) -> Box<dyn Iterator<Item = &PlacedPoint> + '_> {
133 Box::new(self.points.values())
134 }
135
136 fn size_bytes(&self) -> usize {
137 self.current_size
138 }
139
140 fn clear(&mut self) {
141 self.points.clear();
142 self.current_size = 0;
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn test_memory_storage_place() {
152 let mut storage = MemoryStorage::new(3);
153
154 let point = Point::new(vec![1.0, 2.0, 3.0]);
155 let blob = Blob::from_str("test");
156
157 let id = storage.place(point, blob).unwrap();
158
159 assert_eq!(storage.len(), 1);
160 assert!(storage.contains(id));
161 }
162
163 #[test]
164 fn test_memory_storage_get() {
165 let mut storage = MemoryStorage::new(3);
166
167 let point = Point::new(vec![1.0, 2.0, 3.0]);
168 let blob = Blob::from_str("hello");
169
170 let id = storage.place(point, blob).unwrap();
171
172 let retrieved = storage.get(id).unwrap();
173 assert_eq!(retrieved.blob.as_str(), Some("hello"));
174 }
175
176 #[test]
177 fn test_memory_storage_remove() {
178 let mut storage = MemoryStorage::new(3);
179
180 let point = Point::new(vec![1.0, 2.0, 3.0]);
181 let id = storage.place(point, Blob::empty()).unwrap();
182
183 assert_eq!(storage.len(), 1);
184
185 let removed = storage.remove(id);
186 assert!(removed.is_some());
187 assert_eq!(storage.len(), 0);
188 assert!(!storage.contains(id));
189 }
190
191 #[test]
192 fn test_memory_storage_dimensionality_check() {
193 let mut storage = MemoryStorage::new(3);
194
195 let wrong_dims = Point::new(vec![1.0, 2.0]); let result = storage.place(wrong_dims, Blob::empty());
198
199 match result {
200 Err(PlaceError::DimensionalityMismatch { expected, got }) => {
201 assert_eq!(expected, 3);
202 assert_eq!(got, 2);
203 }
204 _ => panic!("Expected DimensionalityMismatch error"),
205 }
206 }
207
208 #[test]
209 fn test_memory_storage_capacity() {
210 let mut storage = MemoryStorage::with_capacity(3, 150);
213
214 let point = Point::new(vec![1.0, 2.0, 3.0]);
215 let blob = Blob::new(vec![0u8; 10]); storage.place(point.clone(), blob.clone()).unwrap();
219
220 let result = storage.place(point, blob);
222 assert!(matches!(result, Err(PlaceError::CapacityExceeded)));
223 }
224
225 #[test]
226 fn test_memory_storage_clear() {
227 let mut storage = MemoryStorage::new(3);
228
229 for i in 0..10 {
230 let point = Point::new(vec![i as f32, 0.0, 0.0]);
231 storage.place(point, Blob::empty()).unwrap();
232 }
233
234 assert_eq!(storage.len(), 10);
235 assert!(storage.size_bytes() > 0);
236
237 storage.clear();
238
239 assert_eq!(storage.len(), 0);
240 assert_eq!(storage.size_bytes(), 0);
241 }
242
243 #[test]
244 fn test_memory_storage_iter() {
245 let mut storage = MemoryStorage::new(2);
246
247 storage.place(Point::new(vec![1.0, 0.0]), Blob::empty()).unwrap();
248 storage.place(Point::new(vec![0.0, 1.0]), Blob::empty()).unwrap();
249
250 let points: Vec<_> = storage.iter().collect();
251 assert_eq!(points.len(), 2);
252 }
253}