Box {
+ /// Returns an item from the data pool, if available.
+ /// Returns None if the data pool is full.
pub fn new(item: P::Item) -> Option {
let p = match P::get().alloc() {
Some(p) => p,
@@ -91,6 +158,18 @@ impl Box {
Some(Self { ptr: p })
}
+ /// Wait until an item is available in the data pool, then return it.
+ /// Returns None if the waker pool is full.
+ #[cfg(feature = "async")]
+ pub async fn new_async(item: P::Item) -> Option {
+ let p = match P::get().alloc_async().await {
+ Some(p) => p,
+ None => return None,
+ };
+ unsafe { p.as_ptr().write(item) };
+ Some(Self { ptr: p })
+ }
+
pub fn into_raw(b: Self) -> NonNull {
let res = b.ptr;
mem::forget(b);
@@ -231,25 +310,55 @@ where
}
}
+/// Create a item pool of a given type and size.
+/// If the `async` feature is enabled, a waker pool is also created with a given size.
+/// The waker pool is used to wake up tasks waiting for an item to become available in the data pool.
+/// The waker pool size should be at least the number of tasks that can be waiting for an item at the same time.
+/// The default waker pool size is zero, changing it without the `async` feature enabled will have no effect.
+/// Example:
+/// ```
+/// use atomic_pool::{pool, Box};
+///
+/// #[derive(Debug)]
+/// #[allow(dead_code)]
+/// struct Packet(u32);
+///
+/// // pool!(PacketPool: [Packet; 4], 2); // This would create a waker pool of size 2
+/// pool!(PacketPool: [Packet; 4]);
+/// ```
#[macro_export]
macro_rules! pool {
($vis:vis $name:ident: [$ty:ty; $n:expr]) => {
$vis struct $name { _uninhabited: ::core::convert::Infallible }
impl $crate::Pool for $name {
type Item = $ty;
- type Storage = $crate::PoolStorageImpl<$ty, {$n}, {($n+31)/32}>;
+ type Storage = $crate::PoolStorageImpl<$ty, {$n}, {($n+31)/32}, 0, 0>;
fn get() -> &'static Self::Storage {
- static POOL: $crate::PoolStorageImpl<$ty, {$n}, {($n+31)/32}> = $crate::PoolStorageImpl::new();
+ static POOL: $crate::PoolStorageImpl<$ty, {$n}, {($n+31)/32}, 0, 0> = $crate::PoolStorageImpl::new();
+ &POOL
+ }
+ }
+ };
+ ($vis:vis $name:ident: [$ty:ty; $n:expr], $wn:expr) => {
+ $vis struct $name { _uninhabited: ::core::convert::Infallible }
+ impl $crate::Pool for $name {
+ type Item = $ty;
+ type Storage = $crate::PoolStorageImpl<$ty, {$n}, {($n+31)/32}, {$wn}, {($wn+31)/32}>;
+ fn get() -> &'static Self::Storage {
+ static POOL: $crate::PoolStorageImpl<$ty, {$n}, {($n+31)/32}, {$wn}, {($wn+31)/32}> = $crate::PoolStorageImpl::new();
&POOL
}
}
};
}
+
#[cfg(test)]
mod test {
use super::*;
+ use core::mem;
pool!(TestPool: [u32; 4]);
+ pool!(TestPool2: [u32; 4], 2);
#[test]
fn test_pool() {
@@ -270,4 +379,20 @@ mod test {
assert_eq!(*b4, 444);
assert_eq!(*b5, 555);
}
+
+ #[cfg(not(feature = "async"))]
+ #[test]
+ fn test_sync_sizes() {
+ let pool1 = ::get();
+ let pool2 = ::get();
+ assert_eq!(mem::size_of_val(pool1), mem::size_of_val(pool2));
+ }
+
+ #[cfg(feature = "async")]
+ #[test]
+ fn test_async_sizes() {
+ let pool1 = ::get();
+ let pool2 = ::get();
+ assert!(mem::size_of_val(pool1) < mem::size_of_val(pool2));
+ }
}