option_block/
iter.rs

1//! By-value and by-reference iterator objects for the various block variants. Note that these
2//! types aren't meant to be used directly. They are simply part of the public interface just
3//! in case one needs to explicitly "name" the iterator object in their code.
4//!
5//! # Example
6//!
7//! ```rust
8//! let block: option_block::Block8<_> = [10, 8, 1].into_iter().enumerate().collect();
9//! assert_eq!(block.get(0), Some(&10));
10//! assert_eq!(block.get(1), Some(&8));
11//! assert_eq!(block.get(2), Some(&1));
12//! assert!(block.get(3).is_none());
13//! ```
14
15use core::{array, iter::Enumerate, mem::MaybeUninit, slice};
16
17macro_rules! impl_iterator_outer {
18	($name:ident $into_iter:ident $iter:ident $iter_mut:ident $int:ty) => {
19		/// By-value iterator that consumes the block allocation.
20		pub struct $into_iter<T> {
21			pub(crate) iter: Enumerate<array::IntoIter<MaybeUninit<T>, { <$int>::BITS as usize }>>,
22			pub(crate) mask: $int,
23		}
24
25		impl<T> Drop for $into_iter<T> {
26			fn drop(&mut self) {
27				// Drop any remaining initialized elements when the iterator is dropped early
28				for (i, item) in self.iter.by_ref() {
29					if self.mask & (1 << i) != 0 {
30						// SAFETY: The bitmask guarantees this slot is initialized.
31						drop(unsafe { item.assume_init() });
32						// The value is dropped immediately at the end of this scope
33					}
34					// Vacant slots don't need dropping
35				}
36			}
37		}
38
39		impl<T> Iterator for $into_iter<T> {
40			type Item = T;
41			fn next(&mut self) -> Option<Self::Item> {
42				loop {
43					let (i, item) = self.iter.next()?;
44					if self.mask & (1 << i) != 0 {
45						// SAFETY: The bitmask guarantees this slot is initialized.
46						return Some(unsafe { item.assume_init() });
47					}
48					// Skip vacant slots: `item` is uninitialized, so no drop needed.
49				}
50			}
51		}
52
53		/// By-reference iterator that borrows from the block allocation.
54		pub struct $iter<'a, T> {
55			pub(crate) iter: Enumerate<slice::Iter<'a, MaybeUninit<T>>>,
56			pub(crate) mask: $int,
57		}
58
59		impl<'a, T> Iterator for $iter<'a, T> {
60			type Item = &'a T;
61			fn next(&mut self) -> Option<Self::Item> {
62				loop {
63					let (i, item) = self.iter.next()?;
64					if self.mask & (1 << i) != 0 {
65						// SAFETY: The bitmask guarantees this slot is initialized.
66						return Some(unsafe { item.assume_init_ref() });
67					}
68				}
69			}
70		}
71
72		/// Mutable by-reference iterator that borrows mutably from the block allocation.
73		pub struct $iter_mut<'a, T> {
74			pub(crate) iter: Enumerate<slice::IterMut<'a, MaybeUninit<T>>>,
75			pub(crate) mask: $int,
76		}
77
78		impl<'a, T> Iterator for $iter_mut<'a, T> {
79			type Item = &'a mut T;
80			fn next(&mut self) -> Option<Self::Item> {
81				loop {
82					let (i, item) = self.iter.next()?;
83					if self.mask & (1 << i) != 0 {
84						// SAFETY: The bitmask guarantees this slot is initialized.
85						return Some(unsafe { item.assume_init_mut() });
86					}
87				}
88			}
89		}
90	};
91}
92
93impl_iterator_outer!(Block8 Block8IntoIter Block8Iter Block8IterMut u8);
94impl_iterator_outer!(Block16 Block16IntoIter Block16Iter Block16IterMut u16);
95impl_iterator_outer!(Block32 Block32IntoIter Block32Iter Block32IterMut u32);
96impl_iterator_outer!(Block64 Block64IntoIter Block64Iter Block64IterMut u64);
97impl_iterator_outer!(Block128 Block128IntoIter Block128Iter Block128IterMut u128);