diff --git a/Cargo.toml b/Cargo.toml index a826f1f..7917696 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,15 +7,13 @@ repository = "https://github.com/embassy-rs/atomic-pool" edition = "2021" readme = "README.md" license = "MIT OR Apache-2.0" -categories = [ - "embedded", - "no-std", - "concurrency", - "memory-management", -] +categories = ["embedded", "no-std", "concurrency", "memory-management"] [dependencies] atomic-polyfill = "1.0" as-slice-01 = { package = "as-slice", version = "0.1.5" } as-slice-02 = { package = "as-slice", version = "0.2.1" } stable_deref_trait = { version = "1.2.0", default-features = false } + +[features] +alloc_uninit = [] diff --git a/examples/simple.rs b/examples/simple.rs index 3e4a706..9f4666a 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,3 +1,4 @@ +#![allow(unused)] use std::mem; use atomic_pool::{pool, Box}; diff --git a/examples/uninit.rs b/examples/uninit.rs new file mode 100644 index 0000000..6660200 --- /dev/null +++ b/examples/uninit.rs @@ -0,0 +1,27 @@ +use atomic_pool::pool; + +pool!(TestPool: [u32; 3]); + +#[cfg(feature = "alloc_uninit")] +fn main() { + use atomic_pool::Box; + use std::mem; + let mut buffer = unsafe { Box::::new_uninit() }.unwrap(); + println!("Allocated new buffer."); + + *buffer = 0xf00dbabeu32; + + let _buffer_2 = unsafe { Box::::new_uninit() }.unwrap(); + let _buffer_3 = unsafe { Box::::new_uninit() }.unwrap(); + + mem::drop(buffer); + println!("Dropped buffer."); + + let reallocated_buffer = unsafe { Box::::new_uninit() }.unwrap(); + println!( + "Reallocated buffer, with contents: {:#x}", + *reallocated_buffer + ); +} +#[cfg(not(feature = "alloc_uninit"))] +fn main() {} diff --git a/src/lib.rs b/src/lib.rs index 66ad238..a2d2ffa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ where [AtomicU32; K]: Sized, { used: AtomicBitset, - data: [UnsafeCell>; N], + pub data: [UnsafeCell>; N], } unsafe impl Send for PoolStorageImpl {} @@ -44,7 +44,6 @@ where } } } - impl PoolStorage for PoolStorageImpl where [AtomicU32; K]: Sized, @@ -77,11 +76,13 @@ pub trait Pool: 'static { fn get() -> &'static Self::Storage; } +/// A statically allocated box. pub struct Box { ptr: NonNull, } impl Box

{ + /// Attempt to allocate a new item from the pool. pub fn new(item: P::Item) -> Option { let p = match P::get().alloc() { Some(p) => p, @@ -90,13 +91,34 @@ impl Box

{ unsafe { p.as_ptr().write(item) }; Some(Self { ptr: p }) } + /// Attempt to allocate a potentially unitialized item from the pool. + /// + /// # Safety + /// The area of memory, to which this box points, maybe uninitialized or contain data from a previous allocation. + /// You must ensure, that you handle this properly and initialize it yourself. + pub unsafe fn new_uninit() -> Option { + let p = match P::get().alloc() { + Some(p) => p, + None => return None, + }; + Some(Self { ptr: p }) + } + /// Turn this box into a raw pointer. + /// + /// Once you turn a box into a raw pointer, it becomes your responsibility to free it properly again. + /// This can be done, by creating a box from that raw pointer again, using [Self::from_raw]. pub fn into_raw(b: Self) -> NonNull { let res = b.ptr; mem::forget(b); res } + /// Create a box from a raw pointer. + /// + /// # Safety + /// You must ensure, that the pointer points to valid memory, which was allocated from the pool in the generic parameter. + /// If you fail to do so, this will trigger a panic, once this box is dropped. pub unsafe fn from_raw(ptr: NonNull) -> Self { Self { ptr } } @@ -232,6 +254,9 @@ where } #[macro_export] +/// Create a new pool. +/// +/// This macro has to variants, one where the pool is uninitialized and another, where it is initialized to some initial value. macro_rules! pool { ($vis:vis $name:ident: [$ty:ty; $n:expr]) => { $vis struct $name { _uninhabited: ::core::convert::Infallible }