opaque_pool/
lib.rs

1//! A type-erased, pinned object pool with stable memory addresses and efficient typed access.
2//!
3//! This crate provides [`OpaquePool`], a dynamically growing pool that can store objects of any
4//! type as long as they match a [`std::alloc::Layout`] defined at pool creation. The pool provides
5//! stable memory addresses, automatic value dropping, and two handle types for different usage
6//! patterns.
7//!
8//! # Key Features
9//!
10//! - **Type-erased storage**: Works with any type matching the pool's [`std::alloc::Layout`]
11//! - **Stable memory addresses**: Items never move once inserted (always pinned)
12//! - **Two handle types**: [`PooledMut<T>`] for exclusive access, [`Pooled<T>`] for shared access
13//! - **Safe removal patterns**: [`PooledMut<T>`] prevents double-use
14//! - **Automatic value dropping**: Values are properly dropped when removed or pool is dropped
15//! - **Dynamic growth**: Pool capacity expands automatically as needed
16//! - **Memory efficiency**: High-density slab allocation minimizes overhead
17//! - **Trait object support**: Built-in support for casting to trait objects
18//! - **Pinning support**: Safe [`std::pin::Pin<&T>`] and [`std::pin::Pin<&mut T>`] access to pooled values
19//! - **Flexible drop policies**: Configure behavior when pool is dropped with remaining items
20//! - **Thread mobility**: Pool can be moved between threads (but not shared without synchronization)
21//!
22//! # Handle Types
23//!
24//! ## [`PooledMut<T>`] - Exclusive Access
25//!
26//! Returned by insertion methods, provides exclusive ownership and prevents accidental double-use:
27//! - Cannot be copied or cloned
28//! - Safe removal methods that consume the handle
29//! - Can be converted to [`Pooled<T>`] for sharing via [`into_shared()`](PooledMut::into_shared)
30//! - Implements [`std::ops::Deref`] and [`std::ops::DerefMut`] for direct value access
31//!
32//! ## [`Pooled<T>`] - Shared Access
33//!
34//! Created from [`PooledMut<T>`] or returned by some methods, allows multiple references:
35//! - Can be copied and cloned freely
36//! - Multiple handles can refer to the same pooled value
37//! - Removal requires `unsafe` code to prevent use-after-free
38//! - Implements [`std::ops::Deref`] for direct shared value access
39//!
40//! The pool itself never holds references to its contents, allowing you to control
41//! aliasing and ensure Rust's borrowing rules are respected.
42//!
43//! # Examples
44//!
45//! ## Basic Usage with Exclusive Handles
46//!
47//! ```rust
48//! use opaque_pool::OpaquePool;
49//!
50//! // Create a pool for String values
51//! let mut pool = OpaquePool::builder().layout_of::<String>().build();
52//!
53//! // Insert a value and get an exclusive handle
54//! // SAFETY: String matches the layout used to create the pool
55//! let item = unsafe { pool.insert("Hello, World!".to_string()) };
56//!
57//! // Access the value safely through Deref
58//! assert_eq!(&*item, "Hello, World!");
59//! assert_eq!(item.len(), 13);
60//!
61//! // Remove the value (consumes the handle, preventing reuse)
62//! pool.remove_mut(item);
63//! ```
64//!
65//! ## Shared Access Pattern
66//!
67//! ```rust
68//! use opaque_pool::OpaquePool;
69//!
70//! let mut pool = OpaquePool::builder().layout_of::<String>().build();
71//!
72//! // SAFETY: String matches the layout used to create the pool
73//! let item = unsafe { pool.insert("Shared".to_string()) };
74//!
75//! // Convert to shared handle for copying
76//! let shared = item.into_shared();
77//! let shared_copy = shared; // Can copy freely
78//!
79//! // Access the value
80//! assert_eq!(&*shared_copy, "Shared");
81//!
82//! // Removal requires unsafe (caller ensures no other copies are used)
83//! // SAFETY: No other copies of the handle will be used after this call
84//! unsafe { pool.remove(&shared_copy) };
85//! ```
86//!
87//! ## Working with Different Types (Same Layout)
88//!
89//! ```rust
90//! use std::alloc::Layout;
91//!
92//! use opaque_pool::OpaquePool;
93//!
94//! // Create a pool for u64-sized values
95//! let layout = Layout::new::<u64>();
96//! let mut pool = OpaquePool::builder().layout(layout).build();
97//!
98//! // Insert different types with the same layout
99//! // SAFETY: u64 matches the pool's layout
100//! let num = unsafe { pool.insert(42_u64) };
101//! // SAFETY: i64 has the same layout as u64
102//! let signed = unsafe { pool.insert(-123_i64) };
103//!
104//! // Access the values using modern Deref patterns
105//! assert_eq!(*num, 42);
106//! assert_eq!(*signed, -123);
107//!
108//! pool.remove_mut(num);
109//! pool.remove_mut(signed);
110//! ```
111
112mod builder;
113mod coordinates;
114mod drop_policy;
115mod dropper;
116mod pool;
117mod pooled;
118mod pooled_mut;
119mod slab;
120
121pub use builder::*;
122pub(crate) use coordinates::*;
123pub use drop_policy::*;
124pub(crate) use dropper::*;
125pub use pool::OpaquePool;
126pub use pooled::Pooled;
127pub use pooled_mut::PooledMut;
128pub(crate) use slab::*;