1use crate::storable::{bounds, bytes_to_store_size_bounded};
35use crate::{
36 read_to_vec, read_u32, read_u64, safe_write, write, write_u32, write_u64, Address, GrowFailed,
37 Memory, Storable,
38};
39use std::borrow::{Borrow, Cow};
40use std::cmp::min;
41use std::fmt;
42use std::marker::PhantomData;
43use std::ops::Range;
44
45const LAYOUT_VERSION: u8 = 1;
46const DATA_OFFSET: u64 = 64;
48const LEN_OFFSET: u64 = 4;
50
51#[derive(Debug)]
52struct HeaderV1 {
53 magic: [u8; 3],
54 version: u8,
55 len: u64,
56 max_size: u32,
57 is_fixed_size: bool,
58}
59
60#[derive(PartialEq, Eq, Debug)]
61pub enum InitError {
62 BadMagic { actual: [u8; 3], expected: [u8; 3] },
65 IncompatibleVersion(u8),
68 IncompatibleElementType,
72 OutOfMemory,
74}
75
76impl fmt::Display for InitError {
77 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
78 match self {
79 Self::BadMagic{ actual, expected } => {
80 write!(fmt, "bad magic number {actual:?}, expected {expected:?}")
81 }
82 Self::IncompatibleVersion(version)
83 => write!(
84 fmt,
85 "unsupported layout version {version}; supported version numbers are 1..={LAYOUT_VERSION}"
86 ),
87 Self::IncompatibleElementType =>
88 write!(fmt, "the bounds (either max_size or is_fixed_size) of the element type do not match the persisted vector attributes"),
89 Self::OutOfMemory => write!(fmt, "failed to allocate memory for vector metadata"),
90 }
91 }
92}
93
94impl std::error::Error for InitError {}
95
96pub struct BaseVec<T: Storable, M: Memory> {
97 memory: M,
98 _marker: PhantomData<T>,
99}
100
101impl<T: Storable, M: Memory> BaseVec<T, M> {
102 pub fn new(memory: M, magic: [u8; 3]) -> Result<Self, GrowFailed> {
108 let t_bounds = bounds::<T>();
109
110 let header = HeaderV1 {
111 magic,
112 version: LAYOUT_VERSION,
113 len: 0,
114 max_size: t_bounds.max_size,
115 is_fixed_size: t_bounds.is_fixed_size,
116 };
117 Self::write_header(&header, &memory)?;
118 Ok(Self {
119 memory,
120 _marker: PhantomData,
121 })
122 }
123
124 pub fn init(memory: M, magic: [u8; 3]) -> Result<Self, InitError> {
131 if memory.size() == 0 {
132 return Self::new(memory, magic).map_err(|_| InitError::OutOfMemory);
133 }
134 let header = Self::read_header(&memory);
135 if header.magic != magic {
136 return Err(InitError::BadMagic {
137 actual: header.magic,
138 expected: magic,
139 });
140 }
141 if header.version != LAYOUT_VERSION {
142 return Err(InitError::IncompatibleVersion(header.version));
143 }
144 let t_bounds = bounds::<T>();
145 if header.max_size != t_bounds.max_size || header.is_fixed_size != t_bounds.is_fixed_size {
146 return Err(InitError::IncompatibleElementType);
147 }
148
149 Ok(Self {
150 memory,
151 _marker: PhantomData,
152 })
153 }
154
155 pub fn into_memory(self) -> M {
157 self.memory
158 }
159
160 pub fn is_empty(&self) -> bool {
164 self.len() == 0
165 }
166
167 pub fn len(&self) -> u64 {
171 read_u64(&self.memory, Address::from(LEN_OFFSET))
172 }
173
174 pub fn set(&self, index: u64, item: &T) {
180 assert!(index < self.len());
181
182 let offset = DATA_OFFSET + slot_size::<T>() as u64 * index;
183 let bytes = item.to_bytes_checked();
184 let data_offset = self
185 .write_entry_size(offset, bytes.len() as u32)
186 .expect("unreachable: cannot fail to write to pre-allocated area");
187 write(&self.memory, data_offset, bytes.borrow());
188 }
189
190 pub fn get(&self, index: u64) -> Option<T> {
194 if index < self.len() {
195 Some(self.read_entry(index))
196 } else {
197 None
198 }
199 }
200
201 pub fn push(&self, item: &T) -> Result<(), GrowFailed> {
205 let index = self.len();
206 let offset = DATA_OFFSET + slot_size::<T>() as u64 * index;
207 let bytes = item.to_bytes_checked();
208 let data_offset = self.write_entry_size(offset, bytes.len() as u32)?;
209 safe_write(&self.memory, data_offset, bytes.borrow())?;
210 self.set_len(index + 1);
213 Ok(())
214 }
215
216 pub fn pop(&self) -> Option<T> {
220 let len = self.len();
221 if len == 0 {
222 return None;
223 }
224 let value = self.read_entry(len - 1);
225 self.set_len(len - 1);
226 Some(value)
227 }
228
229 pub fn iter(&self) -> Iter<'_, T, M> {
230 Iter {
231 vec: self,
232 buf: vec![],
233 range: Range {
234 start: 0,
235 end: self.len(),
236 },
237 }
238 }
239
240 fn read_entry(&self, index: u64) -> T {
242 let mut data = std::vec::Vec::new();
243 self.read_entry_to(index, &mut data);
244 T::from_bytes(Cow::Owned(data))
245 }
246
247 fn read_entry_to(&self, index: u64, buf: &mut Vec<u8>) {
249 let offset = DATA_OFFSET + slot_size::<T>() as u64 * index;
250 let (data_offset, data_size) = self.read_entry_size(offset);
251 read_to_vec(&self.memory, data_offset.into(), buf, data_size);
252 }
253
254 fn set_len(&self, new_len: u64) {
256 write_u64(&self.memory, Address::from(LEN_OFFSET), new_len);
257 }
258
259 fn write_entry_size(&self, offset: u64, size: u32) -> Result<u64, GrowFailed> {
261 let t_bounds = bounds::<T>();
262 debug_assert!(size <= t_bounds.max_size);
263
264 if t_bounds.is_fixed_size {
265 Ok(offset)
266 } else if t_bounds.max_size <= u8::MAX as u32 {
267 safe_write(&self.memory, offset, &[size as u8; 1])?;
268 Ok(offset + 1)
269 } else if t_bounds.max_size <= u16::MAX as u32 {
270 safe_write(&self.memory, offset, &(size as u16).to_le_bytes())?;
271 Ok(offset + 2)
272 } else {
273 safe_write(&self.memory, offset, &size.to_le_bytes())?;
274 Ok(offset + 4)
275 }
276 }
277
278 fn read_entry_size(&self, offset: u64) -> (u64, usize) {
280 let t_bounds = bounds::<T>();
281 if t_bounds.is_fixed_size {
282 (offset, t_bounds.max_size as usize)
283 } else if t_bounds.max_size <= u8::MAX as u32 {
284 let mut size = [0u8; 1];
285 self.memory.read(offset, &mut size);
286 (offset + 1, size[0] as usize)
287 } else if t_bounds.max_size <= u16::MAX as u32 {
288 let mut size = [0u8; 2];
289 self.memory.read(offset, &mut size);
290 (offset + 2, u16::from_le_bytes(size) as usize)
291 } else {
292 let size = read_u32(&self.memory, Address::from(offset));
293 (offset + 4, size as usize)
294 }
295 }
296
297 fn write_header(header: &HeaderV1, memory: &M) -> Result<(), GrowFailed> {
299 safe_write(memory, 0, &header.magic)?;
300 memory.write(3, &[header.version; 1]);
301 write_u64(memory, Address::from(4), header.len);
302 write_u32(memory, Address::from(12), header.max_size);
303 memory.write(16, &[if header.is_fixed_size { 1u8 } else { 0u8 }; 1]);
304 Ok(())
305 }
306
307 fn read_header(memory: &M) -> HeaderV1 {
311 debug_assert!(memory.size() > 0);
312
313 let mut magic = [0u8; 3];
314 let mut version = [0u8; 1];
315 let mut is_fixed_size = [0u8; 1];
316 memory.read(0, &mut magic);
317 memory.read(3, &mut version);
318 let len = read_u64(memory, Address::from(LEN_OFFSET));
319 let max_size = read_u32(memory, Address::from(12));
320 memory.read(16, &mut is_fixed_size);
321
322 HeaderV1 {
323 magic,
324 version: version[0],
325 len,
326 max_size,
327 is_fixed_size: is_fixed_size[0] != 0,
328 }
329 }
330
331 pub fn to_vec(&self) -> Vec<T> {
332 self.iter().collect()
333 }
334}
335
336impl<T: Storable + fmt::Debug, M: Memory> fmt::Debug for BaseVec<T, M> {
337 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
338 self.to_vec().fmt(fmt)
339 }
340}
341
342fn slot_size<T: Storable>() -> u32 {
343 let t_bounds = bounds::<T>();
344 t_bounds.max_size + bytes_to_store_size_bounded(&t_bounds)
345}
346
347pub struct Iter<'a, T, M>
348where
349 T: Storable,
350 M: Memory,
351{
352 vec: &'a BaseVec<T, M>,
353 buf: std::vec::Vec<u8>,
354 range: Range<u64>,
355}
356
357impl<T, M> Iterator for Iter<'_, T, M>
358where
359 T: Storable,
360 M: Memory,
361{
362 type Item = T;
363
364 fn next(&mut self) -> Option<T> {
365 if self.range.is_empty() || self.vec.len() <= self.range.start {
366 return None;
367 }
368
369 self.vec.read_entry_to(self.range.start, &mut self.buf);
370 self.range.start = self.range.start.saturating_add(1);
371 Some(T::from_bytes(Cow::Borrowed(&self.buf)))
372 }
373
374 fn size_hint(&self) -> (usize, Option<usize>) {
375 (
376 min(self.vec.len(), self.range.end).saturating_sub(self.range.start) as usize,
377 None,
378 )
379 }
380
381 fn count(self) -> usize {
382 min(self.vec.len(), self.range.end)
383 .saturating_sub(self.range.start)
384 .try_into()
385 .expect("Cannot express count as usize")
386 }
387
388 fn nth(&mut self, n: usize) -> Option<T> {
389 self.range.start = self.range.start.saturating_add(n as u64);
390 self.next()
391 }
392}
393
394impl<T, M> DoubleEndedIterator for Iter<'_, T, M>
395where
396 T: Storable,
397 M: Memory,
398{
399 fn next_back(&mut self) -> Option<Self::Item> {
400 if self.range.is_empty() || self.vec.len() < self.range.end {
401 return None;
402 }
403
404 self.vec.read_entry_to(self.range.end - 1, &mut self.buf);
405 self.range.end = self.range.end.saturating_sub(1);
406 Some(T::from_bytes(Cow::Borrowed(&self.buf)))
407 }
408
409 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
410 self.range.end = self.range.end.saturating_sub(n as u64);
411 self.next_back()
412 }
413}