From 68d9e9e23b521f6a00c66354191320eaf797fe40 Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Sat, 3 Apr 2021 15:27:51 +0200
Subject: [PATCH] pool trait

---
 examples/usage.rs |   9 +--
 src/lib.rs        | 153 +++++++++++++++++++++++++++++++++++-----------
 2 files changed, 122 insertions(+), 40 deletions(-)

diff --git a/examples/usage.rs b/examples/usage.rs
index a7268d0..f9c8d06 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 9b7a039..5f324ca 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) }
+    }
+}
-- 
GitLab