12 releases (6 breaking)

Uses old Rust 2015

0.6.1 Nov 21, 2020
0.6.0 Nov 13, 2018
0.5.2 Sep 25, 2015
0.4.0 Sep 2, 2015
0.0.3 May 27, 2015

#79 in Memory management

Download history 15082/week @ 2023-11-23 7548/week @ 2023-11-30 7299/week @ 2023-12-07 11908/week @ 2023-12-14 5970/week @ 2023-12-21 2812/week @ 2023-12-28 4073/week @ 2024-01-04 2051/week @ 2024-01-11 6307/week @ 2024-01-18 5796/week @ 2024-01-25 4856/week @ 2024-02-01 9803/week @ 2024-02-08 1992/week @ 2024-02-15 4375/week @ 2024-02-22 7001/week @ 2024-02-29 4182/week @ 2024-03-07

20,614 downloads per month
Used in 8 crates (6 directly)

MIT license

26KB
464 lines

lifeguard

Object Pool Manager

API Documentation

Examples

Pool issues owned values wrapped in smartpointers.

extern crate lifeguard;
use lifeguard::*;

fn main() {
    let pool : Pool<String> = pool().with(StartingSize(10)).build();
    {
        let string = pool.new_from("Hello, World!"); // Remove a value from the pool
        assert_eq!(9, pool.size());
    } // Values that have gone out of scope are automatically moved back into the pool.
    assert_eq!(10, pool.size());
}

Values taken from the pool can be dereferenced to access/mutate their contents.

extern crate lifeguard;
use lifeguard::*;

fn main() {
    let pool : Pool<String> = pool().with(StartingSize(10)).build();
    let mut string = pool.new_from("cat");
    string.push_str("s love eating mice"); //string.as_mut() also works
    assert_eq!("cats love eating mice", *string);
}

Values can be unwrapped, detaching them from the pool.

extern crate lifeguard;
use lifeguard::*;

fn main() {
    let pool : Pool<String> = pool().with(StartingSize(10)).build();
    {
        let string : String = pool.new().detach();
    } // The String goes out of scope and is dropped; it is not returned to the pool
    assert_eq!(9, pool.size());
}

Values can be manually entered into / returned to the pool.

extern crate lifeguard;
use lifeguard::*;

fn main() {
    let pool : Pool<String> = pool().with(StartingSize(10)).build();
    {
        let string : String = pool.detached(); // An unwrapped String, detached from the Pool
        assert_eq!(9, pool.size());
        let rstring : Recycled<String> = pool.attach(string); // The String is attached to the pool again
        assert_eq!(9, pool.size()); // but it is still checked out from the pool
    } // rstring goes out of scope and is added back to the pool
    assert_eq!(10, pool.size());
}

Pool's builder API can be used to customize the behavior of the pool.

extern crate lifeguard;
use lifeguard::*;

fn main() {
 let pool : Pool<String> = pool()
   // The pool will allocate 128 values for immediate use. More will be allocated on demand.
   .with(StartingSize(128))
   // The pool will only grow up to 4096 values. Further values will be dropped.
   .with(MaxSize(4096))
   // The pool will use this closure (or other object implementing Supply<T>) to allocate
   .with(Supplier(|| String::with_capacity(1024)))
   .build();
  // ...
}

Highly Unscientific Benchmarks

Benchmark source can be found here. Tests were run on an early 2015 MacBook Pro.

Each benchmark comes in three flavors:

  1. tests::*_standard: Uses the system allocator to create new values.
  2. tests::*_pooled_rc: Uses a Pool to create new values which hold Rc references to the Pool. These values can be freely passed to other scopes.
  3. tests::*_pooled: Uses a Pool to create new values which hold & locally-scoped references to the Pool. These values are the cheapest to create but are bound to the lifetime of the Pool.

Uninitialized Allocation

Compares the cost of allocating a new String (using String::with_capacity, as String::new does not allocate immediately) with the cost of retrieving a String from the pool.

tests::allocation_standard                          ... bench:   5,322,513 ns/iter (+/- 985,898)
tests::allocation_pooled_rc                         ... bench:     784,885 ns/iter (+/- 95,245)
tests::allocation_pooled                            ... bench:     565,864 ns/iter (+/- 66,036)

Initialized Allocation

Compares the cost of allocating a new String and initializing it to a given value (via &str::to_owned) with the cost of retrieving a String from the pool and initializing it to the same value.

tests::initialized_allocation_standard              ... bench:   5,329,948 ns/iter (+/- 547,725)
tests::initialized_allocation_pooled_rc             ... bench:   1,151,493 ns/iter (+/- 119,293)
tests::initialized_allocation_pooled                ... bench:     927,214 ns/iter (+/- 147,935)

Vec<Vec<String>> Allocation

Creates a two-dimensional vector of initialized Strings. All Vecs and Strings created are from a Pool where applicable. Adapted from this benchmark.

tests::vec_vec_str_standard                         ... bench:   1,353,906 ns/iter (+/- 142,094)
tests::vec_vec_str_pooled_rc                        ... bench:     298,087 ns/iter (+/- 168,703)
tests::vec_vec_str_pooled                           ... bench:     251,082 ns/iter (+/- 24,408)

Ideas and PRs welcome!

Inspired by frankmcsherry's recycler.

No runtime deps