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}