Expand description
A high-performance object pool that reuses allocations instead of freeing them.
§Quick Start
use poolshark::local::LPooled;
use std::collections::HashMap;
// Take a HashMap from the thread-local pool (or create new if empty)
let mut map: LPooled<HashMap<String, i32>> = LPooled::take();
map.insert("answer".to_string(), 42);
// When dropped, the HashMap is cleared and returned to the pool§Which Pool Should I Use?
- Use
local::LPooled(default choice): Faster, for objects created and dropped on the same thread(s) - Use
global::GPooled: When one thread creates objects and other threads drop them (producer-consumer)
§Why Poolshark?
- Reduce allocations: Reuse containers instead of repeatedly allocating and freeing
- Predictable performance: Consistent behavior across platforms, independent of allocator
- Fast: Local pools avoid atomic operations and are more ergonomic than
thread_local! - Flexible: Choose between fast thread-local pools or lock-free cross-thread pools
§Pool Types
§Global Pooling
Global pools share objects between threads (see global::GPooled).
An object taken from a global pool always returns to the pool it was
taken from, regardless of which thread drops it. Use this for producer-consumer
patterns where one thread creates objects and other threads consume them.
There are several different ways to use global pools. You can use take or take_any to just take objects from thread local global pools. If you need better performance you can use pool or pool_any and then store the pool somewhere. If you don’t have anywhere to store the pool you can use a static LazyLock for a truly global named pool. For example,
use std::{sync::LazyLock, collections::HashMap};
use poolshark::global::{Pool, GPooled};
type Widget = HashMap<usize, usize>;
// create a global static widget pool that will accept up to 1024 widgets with
// up to 64 elements of capacity each
static WIDGETS: LazyLock<Pool<Widget>> = LazyLock::new(|| Pool::new(1024, 64));
fn widget_maker() -> GPooled<Widget> {
let mut w = WIDGETS.take();
w.insert(42, 42);
w
}
fn widget_user(w: GPooled<Widget>) {
drop(w) // puts the widget back in the WIDGETS pool
}§Local Pooling
Local pools (see local::LPooled) always return dropped objects to a thread-local
pool on whichever thread drops them. They are significantly faster than global pools
because they avoid atomic operations. Use local pools by default unless you have
a cross-thread producer-consumer pattern.
Thread safety: LPooled<T> is Send + Sync whenever T is Send + Sync, so you can
safely pass pooled objects between threads.
Local pools require types to implement the unsafe trait IsoPoolable, but all
standard containers (Vec, HashMap, String, etc.) already implement it.
use poolshark::local::LPooled;
use std::collections::HashMap;
type Widget = HashMap<usize, usize>;
fn widget_maker() -> LPooled<Widget> {
let mut w = LPooled::<Widget>::default(); // takes from the local pool
w.insert(42, 42);
w
}
fn widget_user(w: LPooled<Widget>) {
drop(w) // puts the widget back in the local pool
}Modules§
- global
- Lock-free global object pools for cross-thread pooling.
- local
- Fast thread-local object pools.
- pooled
- Built-in
PoolableandIsoPoolableimplementations.
Macros§
- location_
id - Generate a globally unique identifier for a source code position
Structs§
- Discriminant
- Type describing the layout, alignment, and type of a container
- Location
Id - A globally unique id for a source code position
Traits§
- IsoPoolable
- Trait for isomorphicly poolable objects.
- Poolable
- Trait for poolable objects
- RawPoolable
- Low level global pool trait for maximum control