Files
k-os/crates/servers/storage-server/src/slots.rs

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()
}
}