Crate poolshark

Crate poolshark 

Source
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 Poolable and IsoPoolable implementations.

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
LocationId
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