56 lines
1.5 KiB
Rust
56 lines
1.5 KiB
Rust
//! A table that grows as it fills, bounded by storage's memory rather than
|
|
//! a count: an entry keeps its index for life (a handle names it), and a
|
|
//! freed index is reused first. At most what a `FileHandle` can name.
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
pub const MAX: usize = u16::MAX as usize + 1;
|
|
|
|
pub struct Slots<T>(Vec<Option<T>>);
|
|
|
|
impl<T> Slots<T> {
|
|
pub const fn new() -> Self {
|
|
Self(Vec::new())
|
|
}
|
|
|
|
/// The index the next entry would get, if there is room for one.
|
|
pub fn free(&self) -> Option<usize> {
|
|
let i = self.0.iter().position(Option::is_none).unwrap_or(self.0.len());
|
|
(i < MAX).then_some(i)
|
|
}
|
|
|
|
/// Puts `value` at `index`, growing to it.
|
|
pub fn put(&mut self, index: usize, value: T) {
|
|
if index >= MAX {
|
|
return;
|
|
}
|
|
if self.0.len() <= index {
|
|
self.0.resize_with(index + 1, || None);
|
|
}
|
|
self.0[index] = Some(value);
|
|
}
|
|
|
|
pub fn get(&self, index: usize) -> Option<&T> {
|
|
self.0.get(index)?.as_ref()
|
|
}
|
|
|
|
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
|
|
self.0.get_mut(index)?.as_mut()
|
|
}
|
|
|
|
pub fn take(&mut self, index: usize) -> Option<T> {
|
|
self.0.get_mut(index)?.take()
|
|
}
|
|
|
|
/// Every entry, with its index.
|
|
pub fn iter(&self) -> impl Iterator<Item = (usize, &T)> {
|
|
self.0.iter().enumerate().filter_map(|(i, v)| v.as_ref().map(|v| (i, v)))
|
|
}
|
|
}
|
|
|
|
impl<T> Default for Slots<T> {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|