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                Self::new()
58            }
59        }
60
61        /// Create a fully initialized direct-access table.
62        impl<T> From<[T; <$int>::BITS as usize]> for $name<T> {
63            fn from(vals: [T; <$int>::BITS as usize]) -> Self {
64                Self {
65                    data: vals.map(MaybeUninit::new),
66                    mask: <$int>::MAX,
67                }
68            }
69        }
70
71        impl<T> Index<usize> for $name<T> {
72            type Output = T;
73            fn index(&self, idx: usize) -> &Self::Output {
74                self.get(idx).expect("slot is vacant")
75            }
76        }
77
78        impl<T> IndexMut<usize> for $name<T> {
79            fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
80                self.get_mut(idx).expect("slot is vacant")
81            }
82        }
83
84        impl<T> FromIterator<(usize, T)> for $name<T> {
85            fn from_iter<I>(iter: I) -> Self
86            where
87                I: IntoIterator<Item = (usize, T)>
88            {
89                let mut block = Self::default();
90
91                for (idx, val) in iter {
92                    // SAFETY: The `insert` method internally invokes `MaybeUninit::assume_init`.
93                    // Since it returns the old data by-value (if any), the `Drop` implementation
94                    // should be implicitly invoked. No resources can be leaked here.
95                    block.insert(idx, val);
96                }
97
98                block
99            }
100        }
101
102        impl<T> IntoIterator for $name<T> {
103            type Item = T;
104            type IntoIter = iter::$into_iter<T>;
105            fn into_iter(self) -> Self::IntoIter {
106                // We need to prevent `self` from invoking `Drop` prematurely when this scope
107                // finishes. We thus wrap `self` in `ManuallyDrop` to progressively drop
108                // each element as the iterator is consumed.
109                let this = ManuallyDrop::new(self);
110                let mask = this.mask;
111
112                // SAFETY: Reading the data pointer effectively "moves" the data out of `this`,
113                // which allows us to pass ownership of the `data` to `Self::IntoIter` without
114                // invoking the `Drop` impl prematurely (thanks to `ManuallyDrop` from earlier).
115                let iter = unsafe { ptr::read(&this.data) }.into_iter().enumerate();
116                Self::IntoIter { iter, mask }
117            }
118        }
119
120        impl<'a, T> IntoIterator for &'a $name<T> {
121            type Item = &'a T;
122            type IntoIter = iter::$iter<'a, T>;
123            fn into_iter(self) -> Self::IntoIter {
124                Self::IntoIter {
125                    iter: self.data.iter().enumerate(),
126                    mask: self.mask,
127                }
128            }
129        }
130
131        impl<'a, T> IntoIterator for &'a mut $name<T> {
132            type Item = &'a mut T;
133            type IntoIter = iter::$iter_mut<'a, T>;
134            fn into_iter(self) -> Self::IntoIter {
135                Self::IntoIter {
136                    iter: self.data.iter_mut().enumerate(),
137                    mask: self.mask,
138                }
139            }
140        }
141
142        impl<T> $name<T> {
143            /// Maximum capacity of the fixed-size block.
144            pub const CAPACITY: u32 = <$int>::BITS;
145
146            /// Creates a new empty block. Useful in `const` contexts.
147            pub const fn new() -> Self {
148                let block = MaybeUninit::<[MaybeUninit<T>; <$int>::BITS as usize]>::uninit();
149                Self {
150                    // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
151                    // This is supported by the nightly feature: `maybe_uninit_uninit_array`.
152                    // When this feature stabilizes, we may use the `MaybeUninit::uninit_array`
153                    // wrapper method instead, which effectively does the same transformation.
154                    data: unsafe { block.assume_init() },
155                    mask: 0,
156                }
157            }
158
159            /// Checks whether the item at the `index` is vacant (i.e. contains `None`).
160            ///
161            /// # Panic
162            /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
163            pub const fn is_vacant(&self, index: usize) -> bool {
164                assert!(index < Self::CAPACITY as usize);
165                self.mask & (1 << index) == 0
166            }
167
168            /// Returns the number of non-null elements in the block.
169            pub const fn len(&self) -> u32 {
170                self.mask.count_ones()
171            }
172
173            /// Returns `true` if the block contains zero elements.
174            pub const fn is_empty(&self) -> bool {
175                self.mask == 0
176            }
177
178            /// Returns an immutable reference to the value at `index`.
179            /// See the [`get`](Self::get) method for the safe, checked
180            /// version of this method.
181            ///
182            /// # Safety
183            /// The queried value **must** be properly initialized. Otherwise,
184            /// the behavior is undefined.
185            pub const unsafe fn get_unchecked(&self, index: usize) -> &T {
186                unsafe { self.data[index].assume_init_ref() }
187            }
188
189            /// Attempts to retrieve a shared reference to the element at `index`.
190            /// Returns `None` if the slot is vacant (i.e. uninitialized).
191            ///
192            /// # Panic
193            /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
194            pub const fn get(&self, index: usize) -> Option<&T> {
195                if self.is_vacant(index) {
196                    None
197                } else {
198                    // SAFETY: We have already verified that the current `index` is not vacant.
199                    Some(unsafe { self.get_unchecked(index) })
200                }
201            }
202
203            /// Returns a mutable reference to the value at `index`.
204            /// See the [`get_mut`](Self::get_mut) method for the safe,
205            /// checked version of this method.
206            ///
207            /// # Safety
208            /// The queried value **must** be properly initialized. Otherwise,
209            /// the behavior is undefined.
210            pub const unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
211                unsafe { self.data[index].assume_init_mut() }
212            }
213
214            /// Attempts to retrieve an exclusive reference to the element at
215            /// `index`. Returns `None` if the slot is vacant (i.e. uninitialized).
216            ///
217            /// # Panic
218            /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
219            pub const fn get_mut(&mut self, index: usize) -> Option<&mut T> {
220                if self.is_vacant(index) {
221                    None
222                } else {
223                    // SAFETY: We have already verified that the current `index` is not vacant.
224                    Some(unsafe { self.get_unchecked_mut(index) })
225                }
226            }
227
228            /// If the slot at the given `index` is already occupied, this method returns a mutable
229            /// reference to the inner data. Otherwise, if the slot is vacant, then this method
230            /// inserts the value constructed by `func`. A mutable reference to the inner data is
231            /// nevertheless returned.
232            pub fn get_or_else(&mut self, index: usize, func: impl FnOnce() -> T) -> &mut T {
233                if self.is_vacant(index) {
234                    // SAFETY: Since this slot is initially vacant, then there are no destructors
235                    // that need to be run. It should be impossible to leak resources here.
236                    self.mask |= 1 << index;
237                    self.data[index].write(func())
238                } else {
239                    // SAFETY: We have already verified that the current `index` is not vacant.
240                    unsafe { self.get_unchecked_mut(index) }
241                }
242            }
243
244            /// Convenience wrapper for the [`get_or_else`](Self::get_or_else) method.
245            pub fn get_or(&mut self, index: usize, val: T) -> &mut T {
246                self.get_or_else(index, || val)
247            }
248
249            const fn lowest_index(mask: $int) -> Option<u32> {
250                // TODO: Use `lowest_one` when that stabilizes.
251                let index = mask.trailing_zeros();
252                if index < Self::CAPACITY {
253                    Some(index)
254                } else {
255                    None
256                }
257            }
258
259            const fn highest_index(mask: $int) -> Option<u32> {
260                // TODO: Use `highest_one` when that stabilizes.
261                let index = Self::CAPACITY - mask.leading_zeros();
262                if index == 0 {
263                    None
264                } else {
265                    Some(index - 1)
266                }
267            }
268
269            /// Returns the index of the first (i.e., lowest index) non-vacant element in the block.
270            /// Note that a [`u32`] is returned for maximum flexibility, but its value will never
271            /// exceed [`Self::CAPACITY`]. It should be safe to cast to a [`usize`] without loss of
272            /// information. You may also safely `unwrap` the conversion via the [`TryFrom`] trait.
273            pub const fn lowest_occupied_index(&self) -> Option<u32> {
274                Self::lowest_index(self.mask)
275            }
276
277            /// Returns a shared reference to the first non-vacant element in the block.
278            /// Convenience wrapper around [`Self::lowest_occupied_index`] followed by [`Self::get_unchecked`].
279            pub const fn first_occupied(&self) -> Option<&T> {
280                if let Some(index) = self.lowest_occupied_index() {
281                    // SAFETY: This is a valid index according to the bitmask.
282                    Some(unsafe { self.get_unchecked(index as usize) })
283                } else {
284                    None
285                }
286            }
287
288            /// Returns an exclusive reference to the first non-vacant element in the block.
289            /// Convenience wrapper around [`Self::lowest_occupied_index`] followed by [`Self::get_unchecked_mut`].
290            pub const fn first_occupied_mut(&mut self) -> Option<&mut T> {
291                if let Some(index) = self.lowest_occupied_index() {
292                    // SAFETY: This is a valid index according to the bitmask.
293                    Some(unsafe { self.get_unchecked_mut(index as usize) })
294                } else {
295                    None
296                }
297            }
298
299            /// Returns the index of the last (i.e., highest index) non-vacant element in the block.
300            /// Note that a [`u32`] is returned for maximum flexibility, but its value will never
301            /// exceed [`Self::CAPACITY`]. It should be safe to cast to a [`usize`] without loss of
302            /// information. You may also safely `unwrap` the conversion via the [`TryFrom`] trait.
303            pub const fn highest_occupied_index(&self) -> Option<u32> {
304                Self::highest_index(self.mask)
305            }
306
307            /// Returns a shared reference to the last non-vacant element in the block.
308            /// Convenience wrapper around [`Self::highest_occupied_index`] followed by [`Self::get_unchecked`].
309            pub const fn last_occupied(&self) -> Option<&T> {
310                if let Some(index) = self.highest_occupied_index() {
311                    // SAFETY: This is a valid index according to the bitmask.
312                    Some(unsafe { self.get_unchecked(index as usize) })
313                } else {
314                    None
315                }
316            }
317
318            /// Returns an exclusive reference to the last non-vacant element in the block.
319            /// Convenience wrapper around [`Self::highest_occupied_index`] followed by [`Self::get_unchecked_mut`].
320            pub const fn last_occupied_mut(&mut self) -> Option<&mut T> {
321                if let Some(index) = self.highest_occupied_index() {
322                    // SAFETY: This is a valid index according to the bitmask.
323                    Some(unsafe { self.get_unchecked_mut(index as usize) })
324                } else {
325                    None
326                }
327            }
328
329            /// Returns the index of the first (i.e., lowest index) vacant element in the block.
330            /// Note that a [`u32`] is returned for maximum flexibility, but its value will never
331            /// exceed [`Self::CAPACITY`]. It should be safe to cast to a [`usize`] without loss of
332            /// information. You may also safely `unwrap` the conversion via the [`TryFrom`] trait.
333            pub const fn lowest_vacant_index(&self) -> Option<u32> {
334                Self::lowest_index(!self.mask)
335            }
336
337            /// Attempts to insert `value` at the first vacant slot in the block.
338            /// Convenience wrapper around [`Self::lowest_vacant_index`] followed by [`Self::insert`].
339            ///
340            /// # Return Value
341            /// - `Ok(option)` if a vacant slot was found, where `option` is the return value from [`Self::insert`].
342            /// - `Err(value)` if the block is full, returning the original `value` back to the caller.
343            pub const fn insert_at_first_vacancy(&mut self, value: T) -> Result<Option<T>, T> {
344                if let Some(index) = self.lowest_vacant_index() {
345                    Ok(self.insert(index as usize, value))
346                } else {
347                    Err(value)
348                }
349            }
350
351            /// Returns the index of the last (i.e., highest index) vacant element in the block.
352            /// Note that a [`u32`] is returned for maximum flexibility, but its value will never
353            /// exceed [`Self::CAPACITY`]. It should be safe to cast to a [`usize`] without loss of
354            /// information. You may also safely `unwrap` the conversion via the [`TryFrom`] trait.
355            pub const fn highest_vacant_index(&self) -> Option<u32> {
356                Self::highest_index(!self.mask)
357            }
358
359            /// Attempts to insert `value` at the last vacant slot in the block.
360            /// Convenience wrapper around [`Self::highest_vacant_index`] followed by [`Self::insert`].
361            ///
362            /// # Return Value
363            /// - `Ok(option)` if a vacant slot was found, where `option` is the return value from [`Self::insert`].
364            /// - `Err(value)` if the block is full, returning the original `value` back to the caller.
365            pub const fn insert_at_last_vacancy(&mut self, value: T) -> Result<Option<T>, T> {
366                if let Some(index) = self.highest_vacant_index() {
367                    Ok(self.insert(index as usize, value))
368                } else {
369                    Err(value)
370                }
371            }
372
373            /// Inserts the `value` at the `index`. If a value already exists, it returns `Some`
374            /// containing the old value. Otherwise, it returns `None`.
375            ///
376            /// # Panic
377            /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
378            pub const fn insert(&mut self, index: usize, value: T) -> Option<T> {
379                let vacant = self.is_vacant(index);
380                let uninit_value = core::mem::replace(&mut self.data[index], MaybeUninit::new(value));
381                self.mask |= 1 << index;
382
383                if vacant {
384                    None
385                } else {
386                    // SAFETY: The slot was occupied before replacement.
387                    // Therefore, it has been initialized properly.
388                    Some(unsafe { uninit_value.assume_init() })
389                }
390            }
391
392            /// Removes the value at the `index`. If a value already exists, it returns `Some`
393            /// containing that value. Otherwise, it returns `None`.
394            ///
395            /// # Panic
396            /// Panics if `index >= CAPACITY`. See the [maximum capacity](Self::CAPACITY).
397            pub const fn remove(&mut self, index: usize) -> Option<T> {
398                if self.is_vacant(index) {
399                    return None;
400                }
401
402                let uninit_val = core::mem::replace(&mut self.data[index], MaybeUninit::uninit());
403                self.mask &= !(1 << index);
404
405                // SAFETY: We have already verified that the current `index` is not vacant.
406                Some(unsafe { uninit_val.assume_init() })
407            }
408
409            /// Create a by-reference iterator for this block.
410            pub fn iter(&self) -> iter::$iter<'_, T> {
411                iter::$iter {
412                    iter: self.data.iter().enumerate(),
413                    mask: self.mask,
414                }
415            }
416
417            /// Create a mutable by-reference iterator for this block.
418            pub fn iter_mut(&mut self) -> iter::$iter_mut<'_, T> {
419                iter::$iter_mut {
420                    iter: self.data.iter_mut().enumerate(),
421                    mask: self.mask,
422                }
423            }
424        }
425
426        impl<T: Default> $name<T> {
427            /// Convenience wrapper for the [`get_or_else`](Self::get_or_else) method.
428            pub fn get_or_default(&mut self, index: usize) -> &mut T {
429                self.get_or_else(index, Default::default)
430            }
431        }
432    };
433}
434
435impl_blocked_optional! {
436	/// A fixed block of optionals masked by a [`u8`](u8),
437	/// which may thus contain at most 8 elements.
438	Block8 Block8IntoIter Block8Iter Block8IterMut u8
439}
440
441impl_blocked_optional! {
442	/// A fixed block of optionals masked by a [`u16`](u16),
443	/// which may thus contain at most 16 elements.
444	Block16 Block16IntoIter Block16Iter Block16IterMut u16
445}
446
447impl_blocked_optional! {
448	/// A fixed block of optionals masked by a [`u32`](u32),
449	/// which may thus contain at most 32 elements.
450	Block32 Block32IntoIter Block32Iter Block32IterMut u32
451}
452
453impl_blocked_optional! {
454	/// A fixed block of optionals masked by a [`u64`](u64),
455	/// which may thus contain at most 64 elements.
456	Block64 Block64IntoIter Block64Iter Block64IterMut u64
457}
458
459impl_blocked_optional! {
460	/// A fixed block of optionals masked by a [`u128`](u128),
461	/// which may thus contain at most 128 elements.
462	Block128 Block128IntoIter Block128Iter Block128IterMut u128
463}