diff --git a/examples/usage.rs b/examples/usage.rs index a7268d07973c95c1bdba5ddf9f2a106d80f961a1..2749788edc7ad49c722598c74b80d5c529fb81e7 100644 --- a/examples/usage.rs +++ b/examples/usage.rs @@ -1,5 +1,5 @@ use core::mem; -use poolman::PoolMan; +use poolman::{PoolMan, P}; #[derive(Debug)] struct IDrop(u32); diff --git a/src/lib.rs b/src/lib.rs index 9b7a0398e436a805d8b4b79082ff7aeef8a62fce..1d3c384e56a6eee5a4e5527df34b6d166f00e538 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,37 +42,27 @@ pub enum Error { AlreadyInitialized, } -pub struct Box<T: 'static + Sized, const S: usize> { +pub struct Box<T: 'static + Sized> { index: usize, - allocator: &'static PoolMan<T, S>, + p: &'static dyn P<T>, } -impl<T: 'static, const S: usize> Drop for Box<T, S> { +impl<T: 'static> Drop for Box<T> { fn drop(&mut self) { - self.allocator.dealloc(self.index) + self.p.dealloc(self.index) } } -impl<T: 'static, const S: usize> Deref for Box<T, S> { +impl<T: 'static> Deref for Box<T> { type Target = T; fn deref(&self) -> &T { - unsafe { - self.allocator - .data /* RacyCell */ - .get_mut_unchecked() /* Array */ - .get_unchecked(self.index) - } + self.p.deref_index(self.index) } } -impl<T: 'static, const S: usize> DerefMut for Box<T, S> { +impl<T: 'static> DerefMut for Box<T> { fn deref_mut(&mut self) -> &mut T { - unsafe { - self.allocator - .data /* RacyCell */ - .get_mut_unchecked() /* Array */ - .get_unchecked_mut(self.index) - } + self.p.deref_mut_index(self.index) } } @@ -83,6 +73,50 @@ pub struct PoolMan<T: 'static, const S: usize> { init: RacyCell<bool>, } +pub trait P<T> { + fn deref_index(&self, index: usize) -> &T; + fn deref_mut_index(&self, index: usize) -> &mut T; + fn dealloc(&self, index: usize); +} + +impl<T: 'static, const S: usize> P<T> for PoolMan<T, S> { + #[inline] + fn deref_index(&self, index: usize) -> &T { + unsafe { + self.data /* RacyCell */ + .get_mut_unchecked() /* Array */ + .get_unchecked(index) + } + } + + #[inline] + fn deref_mut_index(&self, index: usize) -> &mut T { + unsafe { + self.data /* RacyCell */ + .get_mut_unchecked() /* Array */ + .get_unchecked_mut(index) + } + } + + // Safety: + // dealloc can only be called by dropping Box + // which can happen only if already initialized + // thus it is safe to assume init == true + // + // not accissible from user code + #[inline] + fn dealloc(&self, index: usize) { + interrupt_free(|| unsafe { + *self.free.get_mut_unchecked().get_unchecked_mut(index) = + *self.head.get_mut_unchecked(); + *self.head.get_mut_unchecked() = index; + }); + } +} + +unsafe impl<T: 'static, const S: usize> Sync for PoolMan<T, S> {} +unsafe impl<T: 'static, const S: usize> Send for PoolMan<T, S> {} + impl<T, const S: usize> PoolMan<T, S> where T: Sized, @@ -115,38 +149,26 @@ where }) } - // Safety: - // dealloc can only be called by dropping Box - // which can happen only if already initialized - // thus it is safe to assume init == true - // - // not accissible from user code - #[inline] - fn dealloc(&self, index: usize) { - interrupt_free(|| unsafe { - *self.free.get_mut_unchecked().get_unchecked_mut(index) = - *self.head.get_mut_unchecked(); - *self.head.get_mut_unchecked() = index; - }); - } - #[inline] - pub fn alloc(&'static self) -> Result<Box<T, S>, Error> { + pub fn alloc(&'static self) -> Result<Box<T>, Error> { // this check does not need to be inside of critical section // as initialization is monotonic, cannot be undone if !unsafe { *self.init.get_mut_unchecked() } { Err(Error::Uninitialized) } else { interrupt_free(|| unsafe { - let index = *self.head.get_mut_unchecked(); - *self.head.get_mut_unchecked() = - *self.free.get_mut_unchecked().get_unchecked(index); - if *self.head.get_mut_unchecked() > S { + // head of free list + let head = *self.head.get_mut_unchecked(); + if head >= S { Err(Error::OutOfMemory) } else { + // update head to `next` free + *self.head.get_mut_unchecked() = + *self.free.get_mut_unchecked().get_unchecked(head); Ok(Box { - index, - allocator: self, + index: head, + // allocator: self, + p: self, }) } })