1#[macro_export]
3macro_rules! declare_fixed_array {
4 ($Name:ident, $T:ty, $SIZE:expr) => {
5 #[derive(Clone, Copy, Debug, PartialEq, Eq, bytemuck::Pod, bytemuck::Zeroable)]
6 #[repr(C)]
7 pub struct $Name {
8 items: [$T; $SIZE],
9 count: u16, _padding: [u8; 14],
11 }
12
13 const _: () = {
14 use core::mem::{align_of, size_of};
15
16 const _ALIGN: usize = align_of::<$Name>();
17 const _SIZE: usize = size_of::<$Name>();
18 const _ITEM_SIZE: usize = size_of::<$T>() * $SIZE;
19 const _EXPECTED_SIZE: usize = _ITEM_SIZE + 2 + 14;
20 const _: () = assert!(
21 _SIZE == _EXPECTED_SIZE,
22 "Size mismatch in FixedArray struct!"
23 );
24 };
25
26 impl $Name {
27 pub fn new() -> Self {
41 assert!(
45 $SIZE <= u16::MAX as usize,
46 "Capacity N exceeds u16 for count field"
47 );
48
49 unsafe { core::mem::zeroed() }
54 }
55
56 #[cfg(not(target_os = "solana"))]
63 pub fn from_slice(input_slice: &[$T]) -> Self {
64 let mut fa = Self::new(); let num_to_copy = core::cmp::min(input_slice.len(), $SIZE);
66
67 for i in 0..num_to_copy {
68 fa.add(input_slice[i].clone());
70 }
71 fa
72 }
73
74 pub fn len(&self) -> usize {
76 self.count as usize
77 }
78
79 pub fn is_empty(&self) -> bool {
81 self.count == 0
82 }
83
84 pub fn capacity(&self) -> usize {
86 $SIZE
87 }
88
89 pub fn is_full(&self) -> bool {
91 (self.count as usize) == $SIZE
92 }
93
94 pub fn get(&self, index: usize) -> Option<&$T> {
96 if index < self.len() {
97 Some(&self.items[index])
98 } else {
99 None
100 }
101 }
102
103 pub fn get_mut(&mut self, index: usize) -> Option<&mut $T> {
105 if index < self.len() {
106 Some(&mut self.items[index])
107 } else {
108 None
109 }
110 }
111
112 pub fn add(&mut self, item: $T) -> Option<usize> {
117 if self.is_full() {
118 None
119 } else {
120 let index = self.count as usize;
121 self.items[index] = item;
122 self.count += 1;
123 Some(index)
124 }
125 }
126
127 pub fn remove_at(&mut self, index: usize) -> Option<$T> {
133 if index >= self.len() {
134 return None;
135 }
136
137 let removed_item = self.items[index].clone();
138
139 for i in index..(self.len() - 1) {
140 self.items[i] = self.items[i + 1].clone();
141 }
142
143 self.count -= 1; if $SIZE > 0 {
147 self.items[self.len()] = <$T>::default(); }
150
151 Some(removed_item)
152 }
153
154 pub fn remove_item(&mut self, item_to_remove: &$T) -> bool {
159 let mut found_index: Option<usize> = None;
160 for i in 0..self.len() {
161 if self.items[i] == *item_to_remove {
162 found_index = Some(i);
163 break;
164 }
165 }
166
167 if let Some(index) = found_index {
168 self.remove_at(index);
169 true
170 } else {
171 false
172 }
173 }
174
175 pub fn iter(&self) -> impl Iterator<Item = &$T> + '_ {
177 self.items.iter().take(self.len())
178 }
179
180 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut $T> + '_ {
182 let len = self.len();
183 self.items.iter_mut().take(len)
184 }
185
186 pub fn clear(&mut self) {
188 for i in 0..self.len() {
189 self.items[i] = <$T>::default();
190 }
191 self.count = 0;
192 }
193
194 pub fn as_slice(&self) -> &[$T] {
196 &self.items[0..self.len()]
197 }
198
199 pub fn as_mut_slice(&mut self) -> &mut [$T] {
201 let len = self.len();
202 &mut self.items[0..len]
203 }
204
205 pub fn retain<F>(&mut self, mut f: F)
214 where
215 F: FnMut(&$T) -> bool,
216 {
217 let original_len = self.len();
218 let mut write_idx = 0;
219 let mut read_idx = 0;
220
221 while read_idx < original_len {
223 if f(&self.items[read_idx]) {
225 if read_idx != write_idx {
227 self.items[write_idx] = self.items[read_idx].clone();
228 }
229 write_idx += 1;
230 }
231 read_idx += 1;
232 }
233
234 for i in write_idx..original_len {
236 self.items[i] = <$T>::default();
237 }
238
239 self.count = write_idx as u16;
240 }
241
242 pub fn as_vec(&self) -> Vec<$T> {
243 self.items
244 .iter()
245 .take(self.count as usize)
246 .cloned()
247 .collect()
248 }
249 }
250
251 impl Default for $Name {
252 fn default() -> Self {
253 Self::new()
254 }
255 }
256 };
257}
258
259#[cfg(test)]
260mod tests {
261
262 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, bytemuck::Pod, bytemuck::Zeroable)]
263 #[repr(C)]
264 struct TestItem {
265 id: u32,
266 data: [u8; 4], }
268
269 const TEST_CAPACITY: usize = 3;
270 const LARGE_CAPACITY: usize = 50; const OVER_U16_MAX_CAPACITY: usize = (u16::MAX as usize) + 1;
272
273 declare_fixed_array!(FixedArrayTestItemNone, TestItem, 0);
274 declare_fixed_array!(FixedArrayTestItemSingle, TestItem, 1);
275 declare_fixed_array!(FixedArrayTestItemThree, TestItem, 3);
276 declare_fixed_array!(FixedArrayTestItemFive, TestItem, 5);
277 declare_fixed_array!(FixedArrayTestItemTest, TestItem, TEST_CAPACITY);
278 declare_fixed_array!(FixedArrayTestItemLarge, TestItem, LARGE_CAPACITY);
279 declare_fixed_array!(FixedArrayTestItemOversized, TestItem, OVER_U16_MAX_CAPACITY);
280
281 #[test]
282 fn test_new_empty_full_capacity() {
283 let fa = FixedArrayTestItemTest::new();
284 assert_eq!(fa.len(), 0);
285 assert!(fa.is_empty());
286 assert!(!fa.is_full());
287 assert_eq!(fa.capacity(), TEST_CAPACITY);
288 }
289
290 #[test]
291 fn test_add_and_get() {
292 let mut fa = FixedArrayTestItemTest::new();
293 let item1 = TestItem {
294 id: 1,
295 data: [1; 4],
296 };
297 let item2 = TestItem {
298 id: 2,
299 data: [2; 4],
300 };
301
302 assert_eq!(fa.add(item1.clone()), Some(0));
303 assert_eq!(fa.len(), 1);
304 assert!(!fa.is_empty());
305 assert_eq!(fa.get(0), Some(&item1));
306 assert_eq!(fa.get(1), None); assert_eq!(fa.add(item2.clone()), Some(1));
309 assert_eq!(fa.len(), 2);
310 assert_eq!(fa.get(1), Some(&item2));
311 }
312
313 #[test]
314 fn test_add_to_full_array() {
315 let mut fa = FixedArrayTestItemSingle::new();
316 let item1 = TestItem {
317 id: 1,
318 data: [1; 4],
319 };
320 let item2 = TestItem {
321 id: 2,
322 data: [2; 4],
323 };
324
325 assert_eq!(fa.add(item1.clone()), Some(0));
326 assert!(fa.is_full());
327 assert_eq!(fa.len(), 1);
328
329 match fa.add(item2.clone()) {
330 None => {}
331 Some(_) => panic!("Should not be able to add to a full array."),
332 }
333 assert_eq!(fa.len(), 1); }
335
336 #[test]
337 fn test_remove_at_and_shifting() {
338 let mut fa = FixedArrayTestItemTest::new();
339 let item1 = TestItem {
340 id: 1,
341 data: [1; 4],
342 };
343 let item2 = TestItem {
344 id: 2,
345 data: [2; 4],
346 };
347 let item3 = TestItem {
348 id: 3,
349 data: [3; 4],
350 };
351
352 fa.add(item1.clone()).unwrap();
353 fa.add(item2.clone()).unwrap();
354 fa.add(item3.clone()).unwrap();
355 assert!(fa.is_full());
356
357 assert_eq!(fa.remove_at(1), Some(item2.clone()));
359 assert_eq!(fa.len(), 2);
360 assert!(!fa.is_full());
361 assert_eq!(fa.get(0), Some(&item1));
362 assert_eq!(fa.get(1), Some(&item3)); assert_eq!(fa.items[2], TestItem::default()); assert_eq!(fa.remove_at(0), Some(item1.clone()));
367 assert_eq!(fa.len(), 1);
368 assert_eq!(fa.get(0), Some(&item3));
369 assert_eq!(fa.items[1], TestItem::default()); assert_eq!(fa.remove_at(0), Some(item3.clone()));
373 assert_eq!(fa.len(), 0);
374 assert!(fa.is_empty());
375 assert_eq!(fa.items[0], TestItem::default()); assert_eq!(fa.remove_at(0), None);
379 }
380
381 #[test]
382 fn test_remove_at_clears_slot() {
383 let mut fa = FixedArrayTestItemTest::new();
384 let item1 = TestItem {
385 id: 1,
386 data: [1; 4],
387 };
388 fa.add(item1.clone()).unwrap();
389
390 assert_eq!(fa.items[0], item1);
392 assert_eq!(fa.items[1], TestItem::default());
393
394 fa.remove_at(0).unwrap();
395 assert_eq!(fa.len(), 0);
396 assert_eq!(
397 fa.items[0],
398 TestItem::default(),
399 "Slot should be cleared to default"
400 );
401 }
402
403 #[test]
404 fn test_remove_item() {
405 let mut fa = FixedArrayTestItemTest::new();
406 let item1 = TestItem {
407 id: 1,
408 data: [1; 4],
409 };
410 let item2 = TestItem {
411 id: 2,
412 data: [2; 4],
413 };
414 let item3 = TestItem {
415 id: 3,
416 data: [3; 4],
417 }; fa.add(item1.clone()).unwrap();
420 fa.add(item2.clone()).unwrap();
421
422 assert!(fa.remove_item(&item1));
423 assert_eq!(fa.len(), 1);
424 assert_eq!(fa.get(0), Some(&item2));
425 assert_eq!(fa.items[1], TestItem::default()); assert!(!fa.remove_item(&item1)); assert!(!fa.remove_item(&item3)); assert_eq!(fa.len(), 1);
430 }
431
432 #[test]
433 fn test_iter_and_iter_mut() {
434 let mut fa = FixedArrayTestItemTest::new();
435 let item1 = TestItem {
436 id: 1,
437 data: [1; 4],
438 };
439 let item2 = TestItem {
440 id: 2,
441 data: [2; 4],
442 };
443
444 fa.add(item1.clone()).unwrap();
445 fa.add(item2.clone()).unwrap();
446
447 let collected_items: Vec<&TestItem> = fa.iter().collect();
448 assert_eq!(collected_items, vec![&item1, &item2]);
449
450 for item_ref in fa.iter_mut() {
451 item_ref.id += 10;
452 }
453
454 assert_eq!(fa.get(0).unwrap().id, 11);
455 assert_eq!(fa.get(1).unwrap().id, 12);
456 }
457
458 #[test]
459 fn test_clear() {
460 let mut fa = FixedArrayTestItemTest::new();
461 fa.add(TestItem {
462 id: 1,
463 data: [1; 4],
464 })
465 .unwrap();
466 fa.add(TestItem {
467 id: 2,
468 data: [2; 4],
469 })
470 .unwrap();
471 assert_eq!(fa.len(), 2);
472
473 fa.clear();
474 assert_eq!(fa.len(), 0);
475 assert!(fa.is_empty());
476 assert_eq!(fa.items[0], TestItem::default());
478 assert_eq!(fa.items[1], TestItem::default());
479 }
480
481 #[test]
482 fn test_as_slice() {
483 let mut fa = FixedArrayTestItemTest::new();
484 let item1 = TestItem {
485 id: 1,
486 data: [1; 4],
487 };
488 let item2 = TestItem {
489 id: 2,
490 data: [2; 4],
491 };
492
493 fa.add(item1.clone()).unwrap();
494 fa.add(item2.clone()).unwrap();
495
496 let slice = fa.as_slice();
497 assert_eq!(slice.len(), 2);
498 assert_eq!(slice[0], item1);
499 assert_eq!(slice[1], item2);
500
501 fa.as_mut_slice()[0].id = 100;
502 assert_eq!(fa.get(0).unwrap().id, 100);
503 }
504
505 #[test]
506 fn test_default_impl() {
507 let fa = FixedArrayTestItemTest::default();
508 assert_eq!(fa.len(), 0);
509 assert!(fa.is_empty());
510 assert_eq!(fa.capacity(), TEST_CAPACITY);
511 }
512
513 #[test]
514 fn test_from_slice() {
515 let item1 = TestItem {
516 id: 1,
517 data: [1; 4],
518 };
519 let item2 = TestItem {
520 id: 2,
521 data: [2; 4],
522 };
523 let item3 = TestItem {
524 id: 3,
525 data: [3; 4],
526 };
527 let item4 = TestItem {
528 id: 4,
529 data: [4; 4],
530 };
531
532 let slice_empty: &[TestItem] = &[];
534 let fa_empty = FixedArrayTestItemTest::from_slice(slice_empty);
535 assert_eq!(fa_empty.len(), 0);
536 assert!(fa_empty.is_empty());
537
538 let slice_small = &[item1.clone(), item2.clone()];
540 let fa_small = FixedArrayTestItemTest::from_slice(slice_small);
541 assert_eq!(fa_small.len(), 2);
542 assert_eq!(fa_small.get(0), Some(&item1));
543 assert_eq!(fa_small.get(1), Some(&item2));
544 assert_eq!(fa_small.get(2), None);
545
546 let slice_exact = &[item1.clone(), item2.clone(), item3.clone()];
548 let fa_exact = FixedArrayTestItemTest::from_slice(slice_exact);
549 assert_eq!(fa_exact.len(), TEST_CAPACITY);
550 assert!(fa_exact.is_full());
551 assert_eq!(fa_exact.get(0), Some(&item1));
552 assert_eq!(fa_exact.get(1), Some(&item2));
553 assert_eq!(fa_exact.get(2), Some(&item3));
554
555 let slice_large = &[item1.clone(), item2.clone(), item3.clone(), item4.clone()];
557 let fa_large = FixedArrayTestItemTest::from_slice(slice_large);
558 assert_eq!(fa_large.len(), TEST_CAPACITY);
559 assert!(fa_large.is_full());
560 assert_eq!(fa_large.get(0), Some(&item1));
561 assert_eq!(fa_large.get(1), Some(&item2));
562 assert_eq!(fa_large.get(2), Some(&item3));
563 assert_eq!(fa_large.get(3), None); let fa_zero_cap = FixedArrayTestItemNone::from_slice(slice_small);
567 assert_eq!(fa_zero_cap.len(), 0);
568 assert!(fa_zero_cap.is_empty());
569 assert!(fa_zero_cap.is_full()); let fa_zero_cap_empty_slice = FixedArrayTestItemNone::from_slice(slice_empty);
573 assert_eq!(fa_zero_cap_empty_slice.len(), 0);
574 assert!(fa_zero_cap_empty_slice.is_empty());
575 assert!(fa_zero_cap_empty_slice.is_full());
576 }
577
578 #[test]
579 fn test_retain() {
580 let item1 = TestItem {
581 id: 1,
582 data: [1; 4],
583 };
584 let item2 = TestItem {
585 id: 2,
586 data: [2; 4],
587 };
588 let item3 = TestItem {
589 id: 3,
590 data: [3; 4],
591 };
592 let item4 = TestItem {
593 id: 4,
594 data: [4; 4],
595 };
596 let item5 = TestItem {
597 id: 5,
598 data: [5; 4],
599 };
600
601 let mut fa1 =
603 FixedArrayTestItemFive::from_slice(&[item1.clone(), item2.clone(), item3.clone()]);
604 fa1.retain(|item| item.id > 0); assert_eq!(fa1.len(), 3);
606 assert_eq!(
607 fa1.as_slice(),
608 &[item1.clone(), item2.clone(), item3.clone()]
609 );
610
611 let mut fa2 =
613 FixedArrayTestItemFive::from_slice(&[item1.clone(), item2.clone(), item3.clone()]);
614 fa2.retain(|item| item.id > 10); assert_eq!(fa2.len(), 0);
616 assert!(fa2.is_empty());
617 assert_eq!(fa2.items[0], TestItem::default()); assert_eq!(fa2.items[1], TestItem::default());
619 assert_eq!(fa2.items[2], TestItem::default());
620
621 let mut fa3 = FixedArrayTestItemFive::from_slice(&[
623 item1.clone(),
624 item2.clone(),
625 item3.clone(),
626 item4.clone(),
627 item5.clone(),
628 ]);
629 fa3.retain(|item| item.id % 2 == 0); assert_eq!(fa3.len(), 2);
631 assert_eq!(fa3.as_slice(), &[item2.clone(), item4.clone()]);
632 assert_eq!(fa3.items[2], TestItem::default()); assert_eq!(fa3.items[3], TestItem::default());
634 assert_eq!(fa3.items[4], TestItem::default());
635
636 let mut fa4 = FixedArrayTestItemFive::new();
638 fa4.retain(|item| item.id > 0);
639 assert_eq!(fa4.len(), 0);
640 assert!(fa4.is_empty());
641
642 let mut fa5 =
644 FixedArrayTestItemThree::from_slice(&[item1.clone(), item2.clone(), item3.clone()]);
645 fa5.retain(|item| item.id > 1); assert_eq!(fa5.len(), 2);
647 assert_eq!(fa5.as_slice(), &[item2.clone(), item3.clone()]);
648 assert_eq!(fa5.items[2], TestItem::default());
649
650 let mut fa6 =
652 FixedArrayTestItemThree::from_slice(&[item1.clone(), item2.clone(), item3.clone()]);
653 fa6.retain(|item| item.id < 3); assert_eq!(fa6.len(), 2);
655 assert_eq!(fa6.as_slice(), &[item1.clone(), item2.clone()]);
656 assert_eq!(fa6.items[2], TestItem::default());
657
658 let mut fa7 =
660 FixedArrayTestItemThree::from_slice(&[item1.clone(), item2.clone(), item3.clone()]);
661 fa7.retain(|item| item.id == 1 || item.id == 3); assert_eq!(fa7.len(), 2);
663 assert_eq!(fa7.as_slice(), &[item1.clone(), item3.clone()]);
664 assert_eq!(fa7.items[2], TestItem::default());
665
666 let mut fa8 =
668 FixedArrayTestItemThree::from_slice(&[item1.clone(), item2.clone(), item3.clone()]);
669 assert!(fa8.is_full());
670 fa8.retain(|item| item.id < 2); assert_eq!(fa8.len(), 1);
672 assert_eq!(fa8.as_slice(), &[item1.clone()]);
673 assert!(!fa8.is_full());
674 assert_eq!(fa8.items[1], TestItem::default());
675 assert_eq!(fa8.items[2], TestItem::default());
676 }
677
678 #[test]
705 #[should_panic(expected = r#"Capacity N exceeds u16 for count field"#)]
706 fn test_new_panics_on_too_large_n() {
707 struct MockU16MaxTest; FixedArrayTestItemOversized::new(); }
740}