1use core::{
2 fmt::{self, Debug},
3 marker::PhantomData,
4 mem::size_of,
5 ops::{Index, IndexMut},
6};
7#[cfg(feature = "std")]
8use std::vec::Vec;
9
10use zerocopy::{little_endian::U32, Ref};
11
12use crate::{add_padding, errors::ZeroCopyError, ZeroCopyTraits};
13
14pub type ZeroCopyCyclicVecU32<'a, T> = ZeroCopyCyclicVec<'a, u32, T>;
15pub type ZeroCopyCyclicVecU64<'a, T> = ZeroCopyCyclicVec<'a, u64, T>;
16pub type ZeroCopyCyclicVecU16<'a, T> = ZeroCopyCyclicVec<'a, u16, T>;
17pub type ZeroCopyCyclicVecU8<'a, T> = ZeroCopyCyclicVec<'a, u8, T>;
18pub type ZeroCopyCyclicVecBorsh<'a, T> = ZeroCopyCyclicVec<'a, U32, T>;
19
20pub struct ZeroCopyCyclicVec<'a, L, T, const PAD: bool = true>
21where
22 L: ZeroCopyTraits,
23 T: ZeroCopyTraits,
24 u64: From<L> + TryInto<L>,
25{
26 metadata: Ref<&'a mut [u8], [L; 3]>,
28 slice: Ref<&'a mut [u8], [T]>,
29}
30
31const CURRENT_INDEX_INDEX: usize = 0;
32const LENGTH_INDEX: usize = 1;
33const CAPACITY_INDEX: usize = 2;
34
35impl<'a, L, T, const PAD: bool> ZeroCopyCyclicVec<'a, L, T, PAD>
36where
37 L: ZeroCopyTraits,
38 T: ZeroCopyTraits,
39 u64: From<L> + TryInto<L>,
40{
41 pub fn new(capacity: L, bytes: &'a mut [u8]) -> Result<Self, ZeroCopyError> {
42 Ok(Self::new_at(capacity, bytes)?.0)
43 }
44
45 pub fn new_at(capacity: L, bytes: &'a mut [u8]) -> Result<(Self, &'a mut [u8]), ZeroCopyError> {
46 if u64::from(capacity) == 0 {
47 return Err(ZeroCopyError::InvalidCapacity);
48 }
49 let metadata_size = Self::metadata_size();
50 if bytes.len() < metadata_size {
51 return Err(ZeroCopyError::InsufficientMemoryAllocated(
52 bytes.len(),
53 metadata_size,
54 ));
55 }
56 let (meta_data, bytes) = bytes.split_at_mut(metadata_size);
57
58 let (mut metadata, _padding) = Ref::<&mut [u8], [L; 3]>::from_prefix(meta_data)?;
59
60 if u64::from(metadata[LENGTH_INDEX]) != 0
61 || u64::from(metadata[CURRENT_INDEX_INDEX]) != 0
62 || u64::from(metadata[CAPACITY_INDEX]) != 0
63 {
64 return Err(ZeroCopyError::MemoryNotZeroed);
65 }
66 metadata[CAPACITY_INDEX] = capacity;
67 let capacity_usize: usize = u64::from(metadata[CAPACITY_INDEX]) as usize;
68
69 let (slice, remaining_bytes) =
70 Ref::<&mut [u8], [T]>::from_prefix_with_elems(bytes, capacity_usize)?;
71 Ok((Self { metadata, slice }, remaining_bytes))
72 }
73
74 pub fn from_bytes(bytes: &'a mut [u8]) -> Result<Self, ZeroCopyError> {
75 Ok(Self::from_bytes_at(bytes)?.0)
76 }
77
78 #[inline]
79 pub fn from_bytes_at(bytes: &'a mut [u8]) -> Result<(Self, &'a mut [u8]), ZeroCopyError> {
80 let metadata_size = Self::metadata_size();
81 if bytes.len() < metadata_size {
82 return Err(ZeroCopyError::InsufficientMemoryAllocated(
83 bytes.len(),
84 metadata_size,
85 ));
86 }
87
88 let (meta_data, bytes) = bytes.split_at_mut(metadata_size);
89 let (metadata, _padding) = Ref::<&mut [u8], [L; 3]>::from_prefix(meta_data)?;
90 let usize_capacity: usize = u64::from(metadata[CAPACITY_INDEX]) as usize;
91 let usize_len: usize = u64::from(metadata[LENGTH_INDEX]) as usize;
92 let usize_current_index: usize = u64::from(metadata[CURRENT_INDEX_INDEX]) as usize;
93
94 if usize_len > usize_capacity {
95 return Err(ZeroCopyError::LengthGreaterThanCapacity);
96 }
97
98 if usize_current_index > usize_len {
99 return Err(ZeroCopyError::CurrentIndexGreaterThanLength);
100 }
101
102 let full_vector_size = Self::data_size(metadata[CAPACITY_INDEX]);
103 if bytes.len() < full_vector_size {
104 return Err(ZeroCopyError::InsufficientMemoryAllocated(
105 bytes.len() + metadata_size,
106 full_vector_size + metadata_size,
107 ));
108 }
109 let (slice, remaining_bytes) =
110 Ref::<&mut [u8], [T]>::from_prefix_with_elems(bytes, usize_capacity)?;
111 Ok((Self { metadata, slice }, remaining_bytes))
112 }
113
114 #[inline]
116 fn get_current_index(&self) -> L {
117 self.metadata[CURRENT_INDEX_INDEX]
118 }
119
120 #[inline]
122 fn get_current_index_mut(&mut self) -> &mut L {
123 &mut self.metadata[CURRENT_INDEX_INDEX]
124 }
125
126 #[inline]
128 fn get_len(&self) -> L {
129 self.metadata[LENGTH_INDEX]
130 }
131
132 #[inline]
134 fn get_len_mut(&mut self) -> &mut L {
135 &mut self.metadata[LENGTH_INDEX]
136 }
137
138 #[inline]
140 fn get_capacity(&self) -> L {
141 self.metadata[CAPACITY_INDEX]
142 }
143
144 #[inline]
145 pub fn push(&mut self, value: T) {
146 if self.len() < self.capacity() {
147 let len = self.len();
148 self.slice[len] = value;
149 *self.get_len_mut() = (len as u64 + 1u64)
150 .try_into()
151 .map_err(|_| ZeroCopyError::InvalidConversion)
152 .unwrap();
153 } else {
154 let current_index = self.current_index();
155 self.slice[current_index] = value;
156 }
157 let new_index = (self.current_index() + 1) % self.capacity();
158 *self.get_current_index_mut() = (new_index as u64)
159 .try_into()
160 .map_err(|_| ZeroCopyError::InvalidConversion)
161 .unwrap();
162 }
163
164 #[inline]
165 pub fn clear(&mut self) {
166 *self.get_current_index_mut() = 0
167 .try_into()
168 .map_err(|_| ZeroCopyError::InvalidConversion)
169 .unwrap();
170 *self.get_len_mut() = self.get_current_index();
171 }
172
173 #[inline]
174 pub fn first(&self) -> Option<&T> {
175 self.get(self.first_index())
176 }
177
178 #[inline]
179 pub fn first_mut(&mut self) -> Option<&mut T> {
180 self.get_mut(self.first_index())
181 }
182
183 #[inline]
184 pub fn last(&self) -> Option<&T> {
185 self.get(self.last_index())
186 }
187
188 #[inline]
189 pub fn last_mut(&mut self) -> Option<&mut T> {
190 self.get_mut(self.last_index())
191 }
192
193 #[inline]
194 fn current_index(&self) -> usize {
195 u64::from(self.get_current_index()) as usize
196 }
197
198 #[inline]
200 pub fn first_index(&self) -> usize {
201 if self.len() < self.capacity() {
202 0
203 } else {
204 self.last_index().saturating_add(1) % (self.capacity())
205 }
206 }
207
208 #[inline]
209 pub fn last_index(&self) -> usize {
210 if self.current_index() == 0 && self.len() == self.capacity() {
211 self.capacity().saturating_sub(1)
212 } else {
213 self.current_index().saturating_sub(1) % self.capacity()
214 }
215 }
216
217 #[inline]
218 pub fn iter(&self) -> ZeroCopyCyclicVecIterator<'_, L, T, PAD> {
219 ZeroCopyCyclicVecIterator {
220 vec: self,
221 current: self.first_index(),
222 is_finished: false,
223 _marker: PhantomData,
224 }
225 }
226
227 #[inline]
228 pub fn iter_from(
229 &self,
230 start: usize,
231 ) -> Result<ZeroCopyCyclicVecIterator<'_, L, T, PAD>, ZeroCopyError> {
232 if start >= self.len() {
233 return Err(ZeroCopyError::IterFromOutOfBounds);
234 }
235 Ok(ZeroCopyCyclicVecIterator {
236 vec: self,
237 current: start,
238 is_finished: false,
239 _marker: PhantomData,
240 })
241 }
242
243 #[inline]
244 pub fn metadata_size() -> usize {
245 let mut size = size_of::<[L; 3]>();
246 if PAD {
247 add_padding::<[L; 3], T>(&mut size);
248 }
249 size
250 }
251
252 #[inline]
253 pub fn data_size(capacity: L) -> usize {
254 let usize_len: usize = u64::from(capacity) as usize;
255 usize_len.saturating_mul(size_of::<T>())
256 }
257
258 pub fn required_size_for_capacity(capacity: L) -> usize {
259 Self::metadata_size().saturating_add(Self::data_size(capacity))
260 }
261
262 #[inline]
263 pub fn len(&self) -> usize {
264 u64::from(self.get_len()) as usize
265 }
266
267 #[inline]
268 pub fn capacity(&self) -> usize {
269 u64::from(self.get_capacity()) as usize
270 }
271
272 #[inline]
273 pub fn is_empty(&self) -> bool {
274 self.len() == 0
275 }
276
277 #[inline]
278 pub fn get(&self, index: usize) -> Option<&T> {
279 if index >= self.len() {
280 return None;
281 }
282 Some(&self.slice[index])
283 }
284
285 #[inline]
286 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
287 if index >= self.len() {
288 return None;
289 }
290 Some(&mut self.slice[index])
291 }
292
293 #[inline]
294 pub fn as_slice(&self) -> &[T] {
295 &self.slice[..self.len()]
296 }
297
298 #[inline]
299 pub fn as_mut_slice(&mut self) -> &mut [T] {
300 let len = self.len();
301 &mut self.slice[..len]
302 }
303
304 #[cfg(feature = "std")]
305 pub fn try_into_array<const N: usize>(&self) -> Result<[T; N], ZeroCopyError> {
306 if self.len() != N {
307 return Err(ZeroCopyError::ArraySize(N, self.len()));
308 }
309 Ok(core::array::from_fn(|i| *self.get(i).unwrap()))
310 }
311
312 #[cfg(feature = "std")]
313 #[inline]
314 pub fn to_vec(&self) -> Vec<T> {
315 self.as_slice().to_vec()
316 }
317}
318
319pub struct ZeroCopyCyclicVecIterator<'a, L, T, const PAD: bool>
320where
321 L: ZeroCopyTraits,
322 T: ZeroCopyTraits,
323 u64: From<L> + TryInto<L>,
324{
325 vec: &'a ZeroCopyCyclicVec<'a, L, T, PAD>,
326 current: usize,
327 is_finished: bool,
328 _marker: PhantomData<T>,
329}
330
331impl<'a, L, T, const PAD: bool> Iterator for ZeroCopyCyclicVecIterator<'a, L, T, PAD>
332where
333 L: ZeroCopyTraits,
334 T: ZeroCopyTraits,
335 u64: From<L> + TryInto<L>,
336{
337 type Item = &'a T;
338
339 #[inline]
340 fn next(&mut self) -> Option<Self::Item> {
341 if self.vec.capacity() == 0 || self.is_finished {
342 None
343 } else {
344 if self.current == self.vec.last_index() {
346 self.is_finished = true;
347 }
348 let new_current = (self.current + 1) % self.vec.capacity();
349 let element = self.vec.get(self.current);
350 self.current = new_current;
351 element
352 }
353 }
354}
355
356impl<L, T, const PAD: bool> IndexMut<usize> for ZeroCopyCyclicVec<'_, L, T, PAD>
357where
358 L: ZeroCopyTraits,
359 T: ZeroCopyTraits,
360 u64: From<L> + TryInto<L>,
361{
362 #[inline]
363 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
364 &mut self.as_mut_slice()[index]
366 }
367}
368
369impl<L, T, const PAD: bool> Index<usize> for ZeroCopyCyclicVec<'_, L, T, PAD>
370where
371 L: ZeroCopyTraits,
372 T: ZeroCopyTraits,
373 u64: From<L> + TryInto<L>,
374{
375 type Output = T;
376
377 #[inline]
378 fn index(&self, index: usize) -> &Self::Output {
379 &self.as_slice()[index]
381 }
382}
383
384impl<L, T, const PAD: bool> PartialEq for ZeroCopyCyclicVec<'_, L, T, PAD>
385where
386 L: ZeroCopyTraits + PartialEq,
387 T: ZeroCopyTraits + PartialEq,
388 u64: From<L> + TryInto<L>,
389{
390 #[inline]
391 fn eq(&self, other: &Self) -> bool {
392 self.as_slice() == other.as_slice() && self.get_current_index() == other.get_current_index()
393 }
394}
395
396impl<L, T, const PAD: bool> fmt::Debug for ZeroCopyCyclicVec<'_, L, T, PAD>
397where
398 L: ZeroCopyTraits,
399 T: ZeroCopyTraits + Debug,
400 u64: From<L> + TryInto<L>,
401{
402 #[inline]
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 write!(f, "{:?}", self.as_slice())
405 }
406}
407
408#[test]
409fn test_private_getters() {
410 let mut backing_store = [0u8; 64];
411 let mut zcv = ZeroCopyCyclicVecU16::<u16>::new(5, &mut backing_store).unwrap();
412 assert_eq!(zcv.get_len(), 0);
413 assert_eq!(zcv.get_capacity(), 5);
414 for i in 0..5 {
415 zcv.push(i);
416 assert_eq!(zcv.get_len(), i + 1);
417 assert_eq!(zcv.get_len_mut(), &mut (i + 1));
418 }
419}