option_block/lib.rs
1#![no_std]
2#![deny(warnings)]
3#![doc = include_str!("../README.md")]
4
5/// By-value and by-reference iterator objects for the various block variants.
6pub mod iter;
7
8use core::{
9 mem::{ManuallyDrop, MaybeUninit},
10 ops::{Index, IndexMut},
11 ptr,
12};
13
14macro_rules! impl_blocked_optional {
15 ($(#[$attrs:meta])* $name:ident $into_iter:ident $iter:ident $iter_mut:ident $int:ty) => {
16 $(#[$attrs])*
17 #[derive(Debug)]
18 pub struct $name<T> {
19 data: [MaybeUninit<T>; <$int>::BITS as usize],
20 mask: $int,
21 }
22
23 /// Ensure that all remaining items in the block are dropped. Since the implementation
24 /// internally uses [`MaybeUninit`](MaybeUninit), we **must** manually drop the valid
25 /// (i.e., initialized) contents ourselves.
26 impl<T> Drop for $name<T> {
27 fn drop(&mut self) {
28 for i in 0..Self::CAPACITY as usize {
29 self.remove(i); // No memory leaks!
30 }
31 }
32 }
33
34 impl<T: Clone> Clone for $name<T> {
35 fn clone(&self) -> Self {
36 let mut block = Self::default();
37 block.mask = self.mask;
38
39 for idx in 0..Self::CAPACITY as usize {
40 if self.is_vacant(idx) {
41 continue;
42 }
43
44 // SAFETY: This slot is not vacant, and hence initialized.
45 // To ensure that no resources are leaked or aliased, we
46 // must manually invoke the `clone` method ourselves.
47 let data = unsafe { self.get_unchecked(idx) };
48 block.data[idx] = MaybeUninit::new(data.clone());
49 }
50
51 block
52 }
53 }
54
55 impl<T> Default for $name<T> {
56 fn default() -> Self {
57 let block = MaybeUninit::<[MaybeUninit<T>; <$int>::BITS as usize]>::uninit();
58 Self {
59 // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
60 // This is supported by the nightly feature: `maybe_uninit_uninit_array`.
61 // When this feature stabilizes, we may use the `MaybeUninit::uninit_array`
62 // wrapper method instead, which effectively does the same transformation.
63 data: unsafe { block.assume_init() },
64 mask: 0,
65 }
66 }
67 }
68
69 /// Create a fully initialized direct-access table.
70 impl<T> From<[T; <$int>::BITS as usize]> for $name<T> {
71 fn from(vals: [T; <$int>::BITS as usize]) -> Self {
72 Self {
73 data: vals.map(MaybeUninit::new),
74 mask: <$int>::MAX,
75 }
76 }
77 }
78
79 impl<T> Index<usize> for $name<T> {
80 type Output = T;
81 fn index(&self, idx: usize) -> &Self::Output {
82 self.get(idx).expect("slot is vacant")
83 }
84 }
85
86 impl<T> IndexMut<usize> for $name<T> {
87 fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
88 self.get_mut(idx).expect("slot is vacant")
89 }
90 }
91
92 impl<T> FromIterator<(usize, T)> for $name<T> {
93 fn from_iter<I>(iter: I) -> Self
94 where
95 I: IntoIterator<Item = (usize, T)>
96 {
97 let mut block = Self::default();
98
99 for (idx, val) in iter {
100 // SAFETY: The `insert` method internally invokes `MaybeUninit::assume_init`.
101 // Since it returns the old data by-value (if any), the `Drop` implementation
102 // should be implicitly invoked. No resources can be leaked here.
103 block.insert(idx, val);
104 }
105
106 block
107 }
108 }
109
110 impl<T> IntoIterator for $name<T> {
111 type Item = T;
112 type IntoIter = iter::$into_iter<T>;
113 fn into_iter(self) -> Self::IntoIter {
114 // We need to prevent `self` from invoking `Drop` prematurely when this scope
115 // finishes. We thus wrap `self` in `ManuallyDrop` to progressively drop
116 // each element as the iterator is consumed.
117 let this = ManuallyDrop::new(self);
118 let mask = this.mask;
119
120 // SAFETY: Reading the data pointer effectively "moves" the data out of `this`,
121 // which allows us to pass ownership of the `data` to `Self::IntoIter` without
122 // invoking the `Drop` impl prematurely (thanks to `ManuallyDrop` from earlier).
123 let iter = unsafe { ptr::read(&this.data) }.into_iter().enumerate();
124 Self::IntoIter { iter, mask }
125 }
126 }
127
128 impl<'a, T> IntoIterator for &'a $name<T> {
129 type Item = &'a T;
130 type IntoIter = iter::$iter<'a, T>;
131 fn into_iter(self) -> Self::IntoIter {
132 Self::IntoIter {
133 iter: self.data.iter().enumerate(),
134 mask: self.mask,
135 }
136 }
137 }
138
139 impl<'a, T> IntoIterator for &'a mut $name<T> {
140 type Item = &'a mut T;
141 type IntoIter = iter::$iter_mut<'a, T>;
142 fn into_iter(self) -> Self::IntoIter {
143 Self::IntoIter {
144 iter: self.data.iter_mut().enumerate(),
145 mask: self.mask,
146 }
147 }
148 }
149
150 impl<T> $name<T> {
151 /// Maximum capacity of the fixed-size block.
152 pub const CAPACITY: u32 = <$int>::BITS;
153
154 /// Checks whether the item at the `index` is vacant (i.e. contains `None`).
155 ///
156 /// # Panic
157 /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
158 pub const fn is_vacant(&self, index: usize) -> bool {
159 assert!(index < Self::CAPACITY as usize);
160 self.mask & (1 << index) == 0
161 }
162
163 /// Returns the number of non-null elements in the block.
164 pub const fn len(&self) -> u32 {
165 self.mask.count_ones()
166 }
167
168 /// Returns `true` if the block contains zero elements.
169 pub const fn is_empty(&self) -> bool {
170 self.mask == 0
171 }
172
173 /// Returns an immutable reference to the value at `index`.
174 /// See the [`get`](Self::get) method for the safe, checked
175 /// version of this method.
176 ///
177 /// # Safety
178 /// The queried value **must** be properly initialized. Otherwise,
179 /// the behavior is undefined.
180 pub const unsafe fn get_unchecked(&self, index: usize) -> &T {
181 unsafe { self.data[index].assume_init_ref() }
182 }
183
184 /// Attempts to retrieve a shared reference to the element at `index`.
185 /// Returns `None` if the slot is vacant (i.e. uninitialized).
186 ///
187 /// # Panic
188 /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
189 pub fn get(&self, index: usize) -> Option<&T> {
190 if self.is_vacant(index) {
191 None
192 } else {
193 // SAFETY: We have already verified that the current `index` is not vacant.
194 Some(unsafe { self.get_unchecked(index) })
195 }
196 }
197
198 /// Returns a mutable reference to the value at `index`.
199 /// See the [`get_mut`](Self::get_mut) method for the safe,
200 /// checked version of this method.
201 ///
202 /// # Safety
203 /// The queried value **must** be properly initialized. Otherwise,
204 /// the behavior is undefined.
205 pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
206 unsafe { self.data[index].assume_init_mut() }
207 }
208
209 /// Attempts to retrieve an exclusive reference to the element at
210 /// `index`. Returns `None` if the slot is vacant (i.e. uninitialized).
211 ///
212 /// # Panic
213 /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
214 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
215 if self.is_vacant(index) {
216 None
217 } else {
218 // SAFETY: We have already verified that the current `index` is not vacant.
219 Some(unsafe { self.get_unchecked_mut(index) })
220 }
221 }
222
223 /// If the slot at the given `index` is already occupied, this method returns a mutable
224 /// reference to the inner data. Otherwise, if the slot is vacant, then this method
225 /// inserts the value constructed by `func`. A mutable reference to the inner data is
226 /// nevertheless returned.
227 pub fn get_or_else(&mut self, index: usize, func: impl FnOnce() -> T) -> &mut T {
228 if self.is_vacant(index) {
229 // SAFETY: Since this slot is initially vacant, then there are no destructors
230 // that need to be run. It should be impossible to leak resources here.
231 self.mask |= 1 << index;
232 self.data[index].write(func())
233 } else {
234 // SAFETY: We have already verified that the current `index` is not vacant.
235 unsafe { self.get_unchecked_mut(index) }
236 }
237 }
238
239 /// Convenience wrapper for the [`get_or_else`](Self::get_or_else) method.
240 pub fn get_or(&mut self, index: usize, val: T) -> &mut T {
241 self.get_or_else(index, || val)
242 }
243
244 /// Inserts the `val` at the `index`. If a value already exists, it returns `Some`
245 /// containing the old value. Otherwise, it returns `None`.
246 ///
247 /// # Panic
248 /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
249 pub fn insert(&mut self, index: usize, val: T) -> Option<T> {
250 let vacant = self.is_vacant(index);
251 let uninit_val = core::mem::replace(&mut self.data[index], MaybeUninit::new(val));
252 self.mask |= 1 << index;
253
254 if vacant {
255 None
256 } else {
257 // SAFETY: The slot was occupied before replacement.
258 // Therefore, it has been initialized properly.
259 Some(unsafe { uninit_val.assume_init() })
260 }
261 }
262
263 /// Removes the value at the `index`. If a value already exists, it returns `Some`
264 /// containing that value. Otherwise, it returns `None`.
265 ///
266 /// # Panic
267 /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
268 pub fn remove(&mut self, index: usize) -> Option<T> {
269 if self.is_vacant(index) {
270 return None;
271 }
272
273 let uninit_val = core::mem::replace(&mut self.data[index], MaybeUninit::uninit());
274 self.mask &= !(1 << index);
275
276 // SAFETY: We have already verified that the current `index` is not vacant.
277 Some(unsafe { uninit_val.assume_init() })
278 }
279
280 /// Create a by-reference iterator for this block.
281 pub fn iter(&self) -> iter::$iter<'_, T> {
282 iter::$iter {
283 iter: self.data.iter().enumerate(),
284 mask: self.mask,
285 }
286 }
287
288 /// Create a mutable by-reference iterator for this block.
289 pub fn iter_mut(&mut self) -> iter::$iter_mut<'_, T> {
290 iter::$iter_mut {
291 iter: self.data.iter_mut().enumerate(),
292 mask: self.mask,
293 }
294 }
295 }
296
297 impl<T: Default> $name<T> {
298 /// Convenience wrapper for the [`get_or_else`](Self::get_or_else) method.
299 pub fn get_or_default(&mut self, index: usize) -> &mut T {
300 self.get_or_else(index, Default::default)
301 }
302 }
303 };
304}
305
306impl_blocked_optional! {
307 /// A fixed block of optionals masked by a [`u8`](u8),
308 /// which may thus contain at most 8 elements.
309 Block8 Block8IntoIter Block8Iter Block8IterMut u8
310}
311
312impl_blocked_optional! {
313 /// A fixed block of optionals masked by a [`u16`](u16),
314 /// which may thus contain at most 16 elements.
315 Block16 Block16IntoIter Block16Iter Block16IterMut u16
316}
317
318impl_blocked_optional! {
319 /// A fixed block of optionals masked by a [`u32`](u32),
320 /// which may thus contain at most 32 elements.
321 Block32 Block32IntoIter Block32Iter Block32IterMut u32
322}
323
324impl_blocked_optional! {
325 /// A fixed block of optionals masked by a [`u64`](u64),
326 /// which may thus contain at most 64 elements.
327 Block64 Block64IntoIter Block64Iter Block64IterMut u64
328}
329
330impl_blocked_optional! {
331 /// A fixed block of optionals masked by a [`u128`](u128),
332 /// which may thus contain at most 128 elements.
333 Block128 Block128IntoIter Block128Iter Block128IterMut u128
334}