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}