#![warn(
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
#![allow(clippy::single_match, rustdoc::bare_urls)]
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
#![doc = include_str!("../README.md")]
pub trait Slabbable<Slabber, T> {
type Error;
fn with_fixed_capacity(_: usize) -> Result<Slabber, Self::Error>;
fn reserve_next(&mut self) -> Result<ReservedSlot, Self::Error>;
fn take_reserved_with(&mut self, _: ReservedSlot, _: T) -> Result<usize, Self::Error>;
fn take_next_with(&mut self, _: T) -> Result<usize, Self::Error>;
fn mark_for_reuse(&mut self, _: usize) -> Result<T, Self::Error>;
fn slot_get_mut(&mut self, _: usize) -> Result<Option<&mut T>, Self::Error>;
fn slot_get_ref(&self, _: usize) -> Result<Option<&T>, Self::Error>;
fn capacity(&self) -> usize;
fn remaining(&self) -> Option<usize>;
fn reap(&mut self) -> Option<usize>;
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ReservedSlot {
taken: usize,
_priv: (),
}
impl ReservedSlot {
pub fn issue(id: usize) -> Self {
Self {
taken: id,
_priv: (),
}
}
pub fn id(&self) -> usize {
self.taken
}
}
mod error;
#[doc(inline)]
pub use error::SlabbableError;
#[cfg(test)]
mod testable;
#[cfg(test)]
mod test {
use super::testable::*;
use super::Slabbable;
use rstest::rstest;
#[repr(packed, C)]
#[derive(Debug, Clone)]
struct SomeCStruct {
forever: u8,
whatever: u16,
yet_another: u32,
}
#[rstest]
#[case(TestableSlab::<SomeCStruct>::with_fixed_capacity(10).unwrap())]
#[case(TestableSlab::<SomeCStruct>::with_fixed_capacity(100).unwrap())]
fn test_1_impl_stable_memory_init<ImplT, Slabber>(#[case] impl_ut_t: ImplT)
where
ImplT: core::fmt::Debug + Slabbable<Slabber, SomeCStruct>,
Slabber: core::fmt::Debug,
{
let mut impl_ut = impl_ut_t;
let cap = impl_ut.capacity();
let mut ptrs_chk = Vec::with_capacity(cap);
for _z in 0..cap {
let slot = impl_ut.take_next_with(SomeCStruct {
forever: 0,
whatever: 0,
yet_another: 0,
});
let slot = match slot {
Ok(slot) => slot,
_ => panic!("Could not take slot"),
};
let g = impl_ut.slot_get_ref(slot);
let g = match g {
Ok(g) => g,
_ => panic!("Error with slot_get_ref(slot)"),
};
let g = if let Some(g) = g {
g
} else {
panic!("Error finding reference back with slot_get_ref(slot)");
};
let ptr = std::ptr::addr_of!(*g);
ptrs_chk.push((slot, ptr));
}
for (slot, ptr) in ptrs_chk {
let chk = match impl_ut.slot_get_ref(slot) {
Ok(Some(chk)) => chk,
_ => panic!("Error with slot_get_ref(slot)"),
};
let chk_ptr = std::ptr::addr_of!(*chk);
assert_eq!(ptr, chk_ptr);
}
}
}