dynamic_pooling/
pool.rs

1use crate::{Pooled, Reset};
2use alloc::sync::Arc;
3use crossbeam_queue::ArrayQueue;
4
5/// A lock-free, thread-safe object pool.
6pub struct Pool<T: Default + Reset> {
7	/// A [`Pool`] is just a wrapper over this.
8	pub(super) inner: Arc<PoolInner<T>>,
9}
10
11// todo: don't show ArrayQueue to the rest of the crate
12pub(super) type PoolInner<T> = ArrayQueue<T>;
13
14impl<T: Default + Reset> Pool<T> {
15	/// Create a new pool with the specified capacity.
16	///
17	/// Note: The capacity will be fully allocated.
18	///
19	/// # Panics
20	/// Panics if the capacity is `0`.
21	pub fn new(capacity: usize) -> Self {
22		assert!(capacity > 0, "capacity must be more than 0");
23		Self {
24			inner: Arc::new(PoolInner::new(capacity)),
25		}
26	}
27
28	/// Take an object from the pool, creating a new one if none are available.
29	///
30	/// ```
31	/// # use dynamic_pooling::{Pool, Pooled};
32	/// let pool: Pool<String> = Pool::new(69);
33	/// let mut string: Pooled<String> = pool.take();
34	/// // do something with it...
35	/// ```
36	pub fn take(&self) -> Pooled<T> {
37		Pooled::new(self.inner.pop().unwrap_or_default(), self)
38	}
39
40	/// Take an object from the pool, returning [`None`] if none are available.
41	///
42	/// This will never allocate.
43	///
44	/// ```
45	/// # use dynamic_pooling::Pool as HiddenPool;
46	/// # type Pool = HiddenPool<String>;
47	/// let pool = Pool::new(69);
48	/// assert!(pool.try_take().is_none());
49	///
50	/// // add an object to the pool
51	/// let foo = pool.take();
52	/// drop(foo);
53	///
54	/// assert!(pool.try_take().is_some());
55	/// ```
56	pub fn try_take(&self) -> Option<Pooled<T>> {
57		self.inner.pop().map(|object| Pooled::new(object, self))
58	}
59
60	/// The number of available objects in the pool.
61	///
62	/// ```
63	/// # use dynamic_pooling::Pool as HiddenPool;
64	/// # type Pool = HiddenPool<String>;
65	/// let pool = Pool::new(69);
66	///
67	/// // add 3 objects to the pool
68	/// let foo = pool.take();
69	/// let bar = pool.take();
70	/// let baz = pool.take();
71	/// drop((foo, bar, baz));
72	///
73	/// assert_eq!(pool.len(), 3);
74	/// ```
75	pub fn len(&self) -> usize {
76		self.inner.len()
77	}
78
79	/// The number of objects currently being used.
80	///
81	/// ```
82	/// # use dynamic_pooling::Pool as HiddenPool;
83	/// # type Pool = HiddenPool<String>;
84	/// let pool = Pool::new(69);
85	///
86	/// // use 3 objects
87	/// let foo = pool.take();
88	/// let bar = pool.take();
89	/// let baz = pool.take();
90	///
91	/// assert_eq!(pool.in_use(), 3);
92	///
93	/// // return them
94	/// drop((foo, bar, baz));
95	///
96	/// assert_eq!(pool.in_use(), 0);
97	/// ```
98	pub fn in_use(&self) -> usize {
99		Arc::weak_count(&self.inner)
100	}
101
102	/// Whether the pool is empty.
103	///
104	/// ```
105	/// # use dynamic_pooling::Pool as HiddenPool;
106	/// # type Pool = HiddenPool<String>;
107	/// let pool = Pool::new(69);
108	/// assert!(pool.is_empty());
109	///
110	/// // add an object to the pool
111	/// let foo = pool.take();
112	/// drop(foo);
113	/// assert_eq!(pool.is_empty(), false);
114	///
115	/// // take it back out
116	/// let foo = pool.take();
117	/// assert!(pool.is_empty());
118	/// ```
119	pub fn is_empty(&self) -> bool {
120		self.inner.is_empty()
121	}
122
123	/// Whether the pool is full.
124	///
125	/// ```
126	/// # use dynamic_pooling::Pool as HiddenPool;
127	/// # type Pool = HiddenPool<String>;
128	/// let pool = Pool::new(1);
129	/// assert_eq!(pool.is_full(), false);
130	///
131	/// // add an object to the pool
132	/// let foo = pool.take();
133	/// drop(foo);
134	/// assert!(pool.is_full());
135	///
136	/// // take it back out
137	/// let foo = pool.take();
138	/// assert_eq!(pool.is_full(), false);
139	/// ```
140	pub fn is_full(&self) -> bool {
141		self.inner.is_full()
142	}
143
144	/// The maximum capacity of the pool.
145	///
146	/// ```
147	/// # use dynamic_pooling::Pool as HiddenPool;
148	/// # type Pool = HiddenPool<String>;
149	/// let pool = Pool::new(69);
150	/// assert_eq!(pool.capacity(), 69);
151	/// ```
152	pub fn capacity(&self) -> usize {
153		self.inner.capacity()
154	}
155
156	/// The spare capacity of the pool.
157	pub fn spare_capacity(&self) -> usize {
158		self.capacity() - self.len()
159	}
160
161	/// Attach an object to the pool.
162	pub fn attach(&self, object: T) -> Pooled<T> {
163		Pooled::new(object, self)
164	}
165}
166
167/// This returns a reference to the same [`Pool`].
168impl<T: Default + Reset> Clone for Pool<T> {
169	fn clone(&self) -> Self {
170		Self {
171			inner: Arc::clone(&self.inner),
172		}
173	}
174}