remem/
lib.rs

1//! # Thread-safe object reuse
2//!
3//! In many programs the allocator can be a bottleneck, especially when
4//! allocating larger structures in a short amount of time. The allocator will
5//! have to spend time finding free memory to fit new allocations, and
6//! defragmenting memory to free up new space for new ones.
7//!
8//! However often we'll be allocating in a loop, and right after we drop an
9//! object we'll want a new object of the same size. This is where `remem` comes
10//! in: it allows you to reuse memory in a thread-safe way.
11//!
12//! This is useful when writing networked services, performing file reads, or
13//! anything else that might allocate a lot. Internally it's implemented using a
14//! "Treiber stack" which is a really fast algorithm that makes `remem` safe to
15//! use between threads!
16//!
17//! # Example
18//!
19//! ```rust
20//! use remem::Pool;
21//! use std::thread;
22//!
23//! let p = Pool::new(|| vec![0usize; 1024]);
24//!
25//! // Create a new handle onto the pool and send it to a new thread.
26//! let p2 = p.clone();
27//! let t = thread::spawn(move || {
28//!     // Get a new vec from the pool and push two values into it.
29//!     let mut v = p2.get();
30//!     v.push(1);
31//!     v.push(2);
32//! });
33//!
34//! // Meanwhile we can still access the original handle from the main
35//! // thread and use it to get new vecs from.
36//! let mut v = p.get();
37//! v.push(1);
38//! v.push(2);
39//!
40//! // Wait for the other thread to complete
41//! t.join().unwrap();
42//!
43//! // When the vec is dropped, it's returned to the pool and is ready to be
44//! // used again from a next call to `p.get()`.
45//! drop(v);
46//! ```
47use std::ops::{Deref, DerefMut};
48use std::sync::Arc;
49use treiber_stack::TreiberStack as Stack;
50
51mod treiber_stack;
52
53struct Internal<T> {
54    stack: Stack<T>,
55    create: Box<dyn Fn() -> T + Send + Sync>,
56    clear: Box<dyn Fn(&mut T) + Send + Sync>,
57}
58
59impl<T> Internal<T> {
60    fn new<C, D>(create: C, clear: D) -> Self
61    where
62        C: Fn() -> T + Send + Sync + 'static,
63        D: Fn(&mut T) -> () + Send + Sync + 'static,
64    {
65        Internal {
66            stack: Stack::new(),
67            create: Box::new(create),
68            clear: Box::new(clear),
69        }
70    }
71}
72
73/// A pool of reusable memory.
74pub struct Pool<T> {
75    internal: Arc<Internal<T>>,
76}
77
78impl<T> Pool<T> {
79    /// Create a new Pool from an initializer function.
80    pub fn new<C>(create: C) -> Pool<T>
81    where
82        C: Fn() -> T + Send + Sync + 'static,
83    {
84        Pool {
85            internal: Arc::new(Internal::new(create, |_| {})),
86        }
87    }
88
89    /// Create a new Pool from an initializer function and a clear function.
90    ///
91    /// The clear function will be called whenever the `ItemGuard` is dropped,
92    /// and provides an opportunity to clear values and remove potentially
93    /// sensitive information from the items before returning it to the memory
94    /// pool.
95    ///
96    /// Note that `drop` in Rust is not guaranteed to run, so this function
97    /// is not a replacement for proper security measures.
98    pub fn with_clear<C, D>(create: C, clear: D) -> Pool<T>
99    where
100        C: Fn() -> T + Send + Sync + 'static,
101        D: Fn(&mut T) -> () + Send + Sync + 'static,
102    {
103        Pool {
104            internal: Arc::new(Internal::new(create, clear)),
105        }
106    }
107
108    /// Get an item from the pool.
109    pub fn get<'a>(&'a self) -> ItemGuard<'a, T> {
110        let pool = &self.internal;
111        let item = pool.stack.pop();
112        ItemGuard {
113            item: Some(item.unwrap_or_else(|| (*self.internal.create)())),
114            pool: self,
115        }
116    }
117
118    /// Store an item back inside the pool.
119    fn push(&self, mut item: T) {
120        (*self.internal.clear)(&mut item);
121        self.internal.stack.push(item);
122    }
123}
124
125impl<T> Clone for Pool<T> {
126    fn clone(&self) -> Self {
127        Pool {
128            internal: self.internal.clone(),
129        }
130    }
131}
132
133/// RAII structure used to reintroduce an item into the pool when dropped.
134pub struct ItemGuard<'a, T> {
135    item: Option<T>,
136    pool: &'a Pool<T>,
137}
138
139impl<'a, T> Drop for ItemGuard<'a, T> {
140    fn drop(&mut self) {
141        self.pool.push(self.item.take().unwrap())
142    }
143}
144
145impl<'a, T> Deref for ItemGuard<'a, T> {
146    type Target = T;
147
148    fn deref(&self) -> &Self::Target {
149        self.item.as_ref().unwrap()
150    }
151}
152
153impl<'a, T> DerefMut for ItemGuard<'a, T> {
154    fn deref_mut(&mut self) -> &mut Self::Target {
155        self.item.as_mut().unwrap()
156    }
157}