infinity_pool/lib.rs
1//! Infinity pool: object pools with trait object support and multiple access models.
2//!
3//! This package provides several types of object pools designed for different use cases,
4//! from basic pooling to advanced memory layouts with custom drop policies.
5//!
6//! # Motivating scenario
7//!
8//! The primary characteristics of the target scenario are:
9//!
10//! * You need to create and destroy many objects on a regular basis.
11//! * These objects need to be pinned.
12//! * You want better performance than you get from `Box::pin()`.
13//! * Optionally, you may also want to store references to the objects in the form of
14//! trait object references (`&dyn Foo`), perhaps because you cannot name the type
15//! due to it being inferred.
16//! * Optionally, you may want to use reference counting to manage object lifetimes.
17//!
18//! It would be fair to say that this package essentially provides faster alternatives
19//! to `Box::pin()`, `Arc::pin()` and `Rc::pin()`.
20//!
21//! # Pool types
22//!
23//! * Pinned pool - the most basic object pool, resembling a `Vec<T>` that guarantees all its
24//! elements are pinned in memory.
25//! * Opaque pool - its type signature does not name the type of the object, allowing you to
26//! maintain a pool of objects with an unnameable type (e.g. the type behind an `impl Future`).
27//! * Blind pool - accepts any type of object, including multiple different types in the same pool,
28//! without requiring any of the types to be named (e.g. many different `impl Future` types).
29//!
30//! In addition to the above characteristics,
31//! [the objects in all the pools can be accessed as trait objects][casting],
32//! thereby ensuring you do not need to name any types even at point of use, and can pass
33//! objects around between APIs that extend beyond `impl Future` style type inference.
34//!
35//! # Access models
36//!
37//! Every pool offers three access models:
38//!
39//! * The default access model is thread-safe and uses reference counted handles (`Arc` style)
40//! to control inserted object lifetime.
41//! * A single-threaded access model is available as an alternative, offering better performance
42//! when you do not need thread safety. It also uses reference counted handles (`Rc` style)
43//! to control inserted object lifetime.
44//! * For advanced scenarios, a "raw" access model is available, which does not use
45//! reference counting and requires the user to manage object lifetimes manually using
46//! unsafe code.
47//!
48//! The raw access model offers maximum performance and efficiency but at the cost of requiring
49//! unsafe code to manage lifetimes and access the objects.
50//!
51//! # Pool choice matrix
52//!
53//! Select the appropriate type based on the pool characteristics and access model you need:
54//!
55//! | Pool Type / Access Model | `Arc`-like | `Rc`-like | Raw |
56//! |---------------------------|------------|-----------|-----|
57//! | Pinned Pool | [`PinnedPool<T>`] | [`LocalPinnedPool<T>`] | [`RawPinnedPool<T>`] |
58//! | Opaque Pool | [`OpaquePool`] | [`LocalOpaquePool`] | [`RawOpaquePool`] |
59//! | Blind Pool | [`BlindPool`] | [`LocalBlindPool`] | [`RawBlindPool`] |
60//!
61//! # Performance
62//!
63//! On an arbitrary x64 machine running Windows, the pools provided by this package offer better
64//! performance than the equivalent standard library primitives (`Box::pin()`, `Arc::pin()`, `Rc::pin()`).
65//!
66//! <img src="https://media.githubusercontent.com/media/folo-rs/folo/refs/heads/main/packages/infinity_pool/benchmark_results.png">
67//!
68//! # Examples
69//!
70//! ## Pinned pool (thread-safe, single type)
71//!
72//! ```
73//! use infinity_pool::PinnedPool;
74//!
75//! let pool = PinnedPool::<String>::new();
76//! let handle = pool.insert("Hello, world!".to_string());
77//! assert_eq!(&*handle, "Hello, world!");
78//! ```
79//!
80//! ## Opaque pool (thread-safe, unnamed type)
81//!
82//! ```
83//! use infinity_pool::OpaquePool;
84//!
85//! fn work_with_displayable<T: std::fmt::Display + Send + 'static>(value: T) {
86//! let pool = OpaquePool::with_layout_of::<T>();
87//! let handle = pool.insert(value);
88//! println!("Stored: {}", &*handle);
89//! }
90//!
91//! work_with_displayable("Hello, world!");
92//! work_with_displayable(42);
93//! ```
94//!
95//! ## Blind pool (thread-safe, multiple unnamed types)
96//!
97//! ```
98//! use infinity_pool::BlindPool;
99//!
100//! let pool = BlindPool::new();
101//! let string_handle = pool.insert("Hello, world!".to_string());
102//! let number_handle = pool.insert(42u32);
103//! assert_eq!(&*string_handle, "Hello, world!");
104//! assert_eq!(*number_handle, 42);
105//! ```
106//!
107//! ## Trait object usage with [`BlindPool`]
108//!
109//! ```
110//! use std::fmt::Display;
111//!
112//! use infinity_pool::{BlindPool, BlindPooledMut, define_pooled_dyn_cast};
113//!
114//! // Enable casting to Display trait objects
115//! define_pooled_dyn_cast!(Display);
116//!
117//! // Function that accepts trait object handles directly
118//! fn process_displayable(handle: BlindPooledMut<dyn Display>) {
119//! println!("Processing: {}", &*handle);
120//! }
121//!
122//! let pool = BlindPool::new();
123//! let string_handle = pool.insert("Hello, world!".to_string());
124//! let number_handle = pool.insert(42i32);
125//!
126//! // Cast to trait objects and pass to function
127//! process_displayable(string_handle.cast_display());
128//! process_displayable(number_handle.cast_display());
129//! ```
130//!
131//! [casting]: define_pooled_dyn_cast
132
133mod blind;
134mod builders;
135mod cast;
136mod drop_policy;
137mod handles;
138mod opaque;
139mod pinned;
140#[cfg(test)]
141mod thread_safety_types;
142
143pub use blind::*;
144pub use builders::*;
145pub use drop_policy::*;
146pub use handles::*;
147pub use opaque::*;
148// Re-export so we can use it without the consumer needing a reference.
149#[doc(hidden)]
150pub use pastey::paste as __private_paste;
151pub use pinned::*;
152#[cfg(test)]
153pub(crate) use thread_safety_types::*;