use std::marker;
use crate::collections::{
self,
slab::{self, key, sealed::core},
};
pub struct Cell<T, Tag = (), const MAX: u32 = { u32::MAX }, const RECYCLE: bool = false> {
core: core::Core<T, key::Generation<MAX>, core::Interior<RECYCLE>>,
tag: marker::PhantomData<fn() -> Tag>,
}
pub struct CellSlots<'a, T, Tag = (), const MAX: u32 = { u32::MAX }, const RECYCLE: bool = false> {
slab: &'a Cell<T, Tag, MAX, RECYCLE>,
}
struct Keys<'a, T, Tag, const MAX: u32, const RECYCLE: bool> {
slab: &'a Cell<T, Tag, MAX, RECYCLE>,
position: usize,
remaining: usize,
}
impl<T, Tag, const MAX: u32, const RECYCLE: bool> Iterator for Keys<'_, T, Tag, MAX, RECYCLE> {
type Item = key::Handle<Tag, MAX>;
fn next(&mut self) -> Option<Self::Item> {
while self.remaining != 0 {
let position = self.position;
self.position += 1;
self.remaining -= 1;
if let Some((index, generation)) = self.slab.core.entries().occupied_at(position) {
return Some(key::Handle::new(index, generation));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.remaining))
}
}
impl<T, Tag, const MAX: u32> Cell<T, Tag, MAX, false> {
pub fn with_capacity(capacity: slab::Capacity) -> Self {
match Self::try_with_capacity(capacity) {
Ok(slab) => slab,
Err(error) => error.abort(),
}
}
pub fn try_with_capacity(
capacity: slab::Capacity,
) -> Result<Self, collections::AllocationError> {
Ok(Self {
core: core::Core::try_with_capacity(capacity)?,
tag: marker::PhantomData,
})
}
}
impl<T, Tag, const MAX: u32> slab::raw::Recycling<T, Tag, MAX> for Cell<T, Tag, MAX, true> {
unsafe fn try_with_capacity_recycling(
capacity: slab::Capacity,
) -> Result<Self, collections::AllocationError> {
Ok(Self {
core: core::Core::try_with_capacity(capacity)?,
tag: marker::PhantomData,
})
}
}
impl<T, Tag, const MAX: u32, const RECYCLE: bool> Cell<T, Tag, MAX, RECYCLE> {
pub fn capacity(&self) -> usize {
self.core.capacity()
}
pub fn grow_to(&mut self, capacity: slab::Capacity) {
self.core.grow_to(capacity)
}
pub fn len(&self) -> usize {
self.core.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn available(&self) -> usize {
self.core.available()
}
pub fn keys(&self) -> impl Iterator<Item = key::Handle<Tag, MAX>> + '_ {
Keys {
slab: self,
position: 0,
remaining: self.len(),
}
}
pub fn slots(&self) -> CellSlots<'_, T, Tag, MAX, RECYCLE> {
CellSlots { slab: self }
}
pub fn any_or_busy(&self, predicate: impl FnMut(&T) -> bool) -> bool {
self.core.any_or_busy(predicate)
}
pub fn insert(&self, value: T) -> Result<key::Handle<Tag, MAX>, T> {
use crate::collections::slab::sealed::pending::Pending;
let Some(ticket) = self.core.reservations().take_free() else {
return Err(value);
};
let pending = Pending::new(&self.core, ticket);
let key = key::Handle::new(ticket.index.get(), ticket.generation);
pending.commit(value);
Ok(key)
}
pub fn try_insert_with<R, E>(
&self,
value: T,
f: impl FnOnce(key::Handle<Tag, MAX>, &mut T) -> Result<R, E>,
) -> Result<(key::Handle<Tag, MAX>, R), slab::InsertError<T, E>> {
self.core
.try_insert_with(value, |ticket, value| {
f(
key::Handle::new(ticket.index.get(), ticket.generation),
value,
)
})
.map(|(ticket, result)| {
(
key::Handle::new(ticket.index.get(), ticket.generation),
result,
)
})
.map_err(|error| match error {
core::TryInsertError::Full(value) => slab::InsertError::Full(value),
core::TryInsertError::Rejected(value, error) => {
slab::InsertError::Rejected(value, error)
}
})
}
pub fn try_insert_build<I, R, E>(
&self,
input: I,
build: impl FnOnce(I) -> T,
f: impl FnOnce(key::Handle<Tag, MAX>, &mut T) -> Result<R, E>,
) -> Result<(key::Handle<Tag, MAX>, R), slab::BuildError<I, T, E>> {
self.core
.try_insert_build(input, build, |ticket, value| {
f(
key::Handle::new(ticket.index.get(), ticket.generation),
value,
)
})
.map(|(ticket, result)| {
(
key::Handle::new(ticket.index.get(), ticket.generation),
result,
)
})
.map_err(|error| match error {
core::TryBuildError::Full(input) => slab::BuildError::Full(input),
core::TryBuildError::Rejected(value, error) => {
slab::BuildError::Rejected(value, error)
}
})
}
pub fn update<R>(&self, key: key::Handle<Tag, MAX>, f: impl FnOnce(&mut T) -> R) -> Option<R> {
self.core.entries().update(key.index(), key.generation(), f)
}
pub fn remove(&self, key: key::Handle<Tag, MAX>) -> Option<T> {
self.core
.entries()
.remove(key.index(), key.generation())
.map(|(value, _)| value)
}
}
impl<T, Tag, const MAX: u32, const RECYCLE: bool> CellSlots<'_, T, Tag, MAX, RECYCLE> {
pub fn key_at(self, position: usize) -> Option<key::Handle<Tag, MAX>> {
let (index, generation) = self.slab.core.entries().occupied_at(position)?;
Some(key::Handle::new(index, generation))
}
pub fn update_index<R>(self, index: u32, f: impl FnOnce(&mut T) -> R) -> Option<R> {
self.slab.core.entries().update_index(index, f)
}
pub fn update_parts<R>(self, parts: key::Parts<MAX>, f: impl FnOnce(&mut T) -> R) -> Option<R> {
self.slab
.core
.entries()
.update(parts.index(), parts.generation(), f)
}
pub fn remove_parts(self, parts: key::Parts<MAX>) -> Option<T> {
self.slab
.core
.entries()
.remove(parts.index(), parts.generation())
.map(|(value, _)| value)
}
pub fn remove_parts_with<R>(
self,
parts: key::Parts<MAX>,
f: impl FnOnce(&mut T) -> Option<R>,
) -> Option<(T, R)> {
self.slab
.core
.entries()
.remove_with(parts.index(), parts.generation(), f)
}
pub fn remove_index_with<R>(
self,
index: u32,
f: impl FnOnce(&mut T) -> Option<R>,
) -> Option<(T, R)> {
self.slab
.core
.entries()
.remove_index_with(index, |value, _| f(value))
.map(|(value, result, _)| (value, result))
}
}