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}