1use crossbeam_queue::ArrayQueue;
2use std::fmt::{Debug, Formatter};
3use std::ops::{Deref, DerefMut};
4use std::sync::{Arc, Weak};
5
6use crate::DynamicReset;
7
8#[derive(Debug)]
17pub struct DynamicPool<T: DynamicReset> {
18 data: Arc<PoolData<T>>,
19}
20
21impl<T: DynamicReset> DynamicPool<T> {
22 pub fn new<F: Fn() -> T + Sync + Send + 'static>(
29 initial_capacity: usize,
30 maximum_capacity: usize,
31 create: F,
32 ) -> DynamicPool<T> {
33 assert![initial_capacity <= maximum_capacity];
34
35 let items = ArrayQueue::new(maximum_capacity);
36
37 for x in (0..initial_capacity).map(|_| create()) {
38 items
39 .push(x)
40 .expect("invariant: items.len() always less than initial_capacity.");
41 }
42
43 let data = PoolData {
44 items,
45 create: Box::new(create),
46 };
47 let data = Arc::new(data);
48
49 DynamicPool { data }
50 }
51
52 pub fn take(&self) -> DynamicPoolItem<T> {
54 let object = self
55 .data
56 .items
57 .pop()
58 .unwrap_or_else(|_| (self.data.create)());
59
60 DynamicPoolItem {
61 data: Arc::downgrade(&self.data),
62 object: Some(object),
63 }
64 }
65
66 pub fn try_take(&self) -> Option<DynamicPoolItem<T>> {
68 let object = self.data.items.pop().ok()?;
69 let data = Arc::downgrade(&self.data);
70
71 Some(DynamicPoolItem {
72 data,
73 object: Some(object),
74 })
75 }
76
77 #[inline]
79 pub fn available(&self) -> usize {
80 self.data.items.len()
81 }
82
83 #[inline]
85 pub fn used(&self) -> usize {
86 Arc::weak_count(&self.data)
87 }
88
89 #[inline]
90 pub fn capacity(&self) -> usize {
91 self.data.items.capacity()
92 }
93}
94
95impl<T: DynamicReset> Clone for DynamicPool<T> {
96 fn clone(&self) -> Self {
97 Self {
98 data: self.data.clone(),
99 }
100 }
101}
102
103struct PoolData<T> {
105 items: ArrayQueue<T>,
106 create: Box<dyn Fn() -> T + Sync + Send + 'static>,
107}
108
109impl<T: DynamicReset + Debug> Debug for PoolData<T> {
110 fn fmt(&self, formatter: &mut Formatter) -> Result<(), std::fmt::Error> {
111 formatter
112 .debug_struct("PoolData")
113 .field("items", &self.items)
114 .field("create", &"Box<dyn Fn() -> T>")
115 .finish()
116 }
117}
118
119#[derive(Debug)]
121pub struct DynamicPoolItem<T: DynamicReset> {
122 data: Weak<PoolData<T>>,
123 object: Option<T>,
124}
125
126impl<T: DynamicReset> DynamicPoolItem<T> {
127 pub fn detach(mut self) -> T {
129 self.object
130 .take()
131 .expect("invariant: object is always `some`.")
132 }
133}
134
135impl<T: DynamicReset> AsRef<T> for DynamicPoolItem<T> {
136 fn as_ref(&self) -> &T {
137 self.object
138 .as_ref()
139 .expect("invariant: object is always `some`.")
140 }
141}
142
143impl<T: DynamicReset> Deref for DynamicPoolItem<T> {
144 type Target = T;
145
146 fn deref(&self) -> &T {
147 self.object
148 .as_ref()
149 .expect("invariant: object is always `some`.")
150 }
151}
152
153impl<T: DynamicReset> DerefMut for DynamicPoolItem<T> {
154 fn deref_mut(&mut self) -> &mut T {
155 self.object
156 .as_mut()
157 .expect("invariant: object is always `some`.")
158 }
159}
160
161impl<T: DynamicReset> Drop for DynamicPoolItem<T> {
162 fn drop(&mut self) {
163 if let Some(mut object) = self.object.take() {
164 object.reset();
165 if let Some(pool) = self.data.upgrade() {
166 pool.items.push(object).ok();
167 }
168 }
169 }
170}