diff --git a/examples/usage.rs b/examples/usage.rs index a7268d07973c95c1bdba5ddf9f2a106d80f961a1..f9c8d0611abb2dae400902647dd16e9fc0b95602 100644 --- a/examples/usage.rs +++ b/examples/usage.rs @@ -3,6 +3,7 @@ use poolman::PoolMan; #[derive(Debug)] struct IDrop(u32); +unsafe impl Sync for IDrop(u32) {} impl core::ops::Drop for IDrop { fn drop(&mut self) { @@ -15,17 +16,17 @@ static P: PoolMan<IDrop, 2> = PoolMan::new([IDrop(10), IDrop(11)]); fn main() { P.init(); { - let e = P.alloc().unwrap(); + let e = P.allocb().unwrap(); println!("e {:?}", *e); mem::drop(e); - let mut e1 = P.alloc().unwrap(); + let mut e1 = P.allocb().unwrap(); println!("e1 {:?}", *e1); *e1 = IDrop(2); println!("e1 {:?}", *e1); - let e2 = P.alloc().unwrap(); + let e2 = P.allocb().unwrap(); println!("e2 {:?}", *e2); } - let e = P.alloc().unwrap(); + let e = P.allocb().unwrap(); println!("e {:?}", *e); } diff --git a/src/lib.rs b/src/lib.rs index 9b7a0398e436a805d8b4b79082ff7aeef8a62fce..5f324cab271ec8f9614fce3cec11fd8988b95040 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] use core::cell::UnsafeCell; +// use core::marker::PhantomData; use core::ops::{Deref, DerefMut, Drop}; use cortex_m::interrupt; @@ -42,40 +43,73 @@ pub enum Error { AlreadyInitialized, } -pub struct Box<T: 'static + Sized, const S: usize> { +trait Pool<T> +where + T: Send + Sync, +{ + fn dealloc(&'static self, index: usize); + fn index_deref(&'static self, index: usize) -> &T; + fn index_deref_mut(&'static self, index: usize) -> &mut T; +} + +pub struct B<T: 'static + Sized + Send + Sync> { index: usize, - allocator: &'static PoolMan<T, S>, + allocator: &'static dyn Pool<T>, } -impl<T: 'static, const S: usize> Drop for Box<T, S> { +impl<T: 'static + Sized + Send + Sync> Drop for B<T> { fn drop(&mut self) { self.allocator.dealloc(self.index) } } -impl<T: 'static, const S: usize> Deref for Box<T, S> { +impl<T: 'static + Sized + Send + Sync> Deref for B<T> { type Target = T; fn deref(&self) -> &T { - unsafe { - self.allocator - .data /* RacyCell */ - .get_mut_unchecked() /* Array */ - .get_unchecked(self.index) - } + self.allocator.index_deref(self.index) } } -impl<T: 'static, const S: usize> DerefMut for Box<T, S> { +impl<T: 'static + Sized + Send + Sync> DerefMut for B<T> { fn deref_mut(&mut self) -> &mut T { - unsafe { - self.allocator - .data /* RacyCell */ - .get_mut_unchecked() /* Array */ - .get_unchecked_mut(self.index) - } + self.allocator.index_deref_mut(self.index) } } +// pub struct Box<T: 'static + Sized, const S: usize> { +// index: usize, +// allocator: &'static PoolMan<T, S>, +// } + +// impl<T: 'static, const S: usize> Drop for Box<T, S> { +// fn drop(&mut self) { +// self.allocator.dealloc(self.index) +// } +// } + +// impl<T: 'static, const S: usize> Deref for Box<T, S> { +// type Target = T; +// fn deref(&self) -> &T { +// unsafe { +// self.allocator +// .data /* RacyCell */ +// .get_mut_unchecked() /* Array */ +// .get_unchecked(self.index) +// } +// } +// } + +// impl<T: 'static, const S: usize> DerefMut for Box<T, S> { +// fn deref_mut(&mut self) -> &mut T { +// unsafe { +// self.allocator +// .data /* RacyCell */ +// .get_mut_unchecked() /* Array */ +// .get_unchecked_mut(self.index) +// } +// } +// } + pub struct PoolMan<T: 'static, const S: usize> { data: RacyCell<[T; S]>, free: RacyCell<[usize; S]>, @@ -83,13 +117,15 @@ pub struct PoolMan<T: 'static, const S: usize> { init: RacyCell<bool>, } + + impl<T, const S: usize> PoolMan<T, S> where - T: Sized, + T: Sized + Send + Sync, { pub const fn new(v: [T; S]) -> Self where - T: Sized, + T: Sized + Send + Sync, { Self { data: RacyCell::new(v), @@ -115,23 +151,45 @@ 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; - }); - } + // // 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 accessible 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> { + // #[inline] + // pub fn alloc(&'static self) -> Result<Box<T, S>, 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 { + // Err(Error::OutOfMemory) + // } else { + // Ok(Box { + // index, + // allocator: self, + // }) + // } + // }) + // } + // } + + pub fn allocb(&'static self) -> Result<B<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() } { @@ -144,7 +202,7 @@ where if *self.head.get_mut_unchecked() > S { Err(Error::OutOfMemory) } else { - Ok(Box { + Ok(B { index, allocator: self, }) @@ -153,3 +211,26 @@ where } } } + +// sealed, should only be externally accessible +impl<T, const S: usize> Pool<T> for PoolMan<T, S> +where + T: Sized + Send + Sync, +{ + #[inline] + fn dealloc(&'static 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; + }); + } + + fn index_deref(&'static self, index: usize) -> &'static T { + unsafe { self.data.get_mut_unchecked().get_unchecked(index) } + } + + fn index_deref_mut(&'static self, index: usize) -> &'static mut T { + unsafe { self.data.get_mut_unchecked().get_unchecked_mut(index) } + } +}