1use crate::pool_object::PoolObject;
2use crate::Config;
3use parking_lot::{Condvar, Mutex};
4
5pub struct Pool<T: Send> {
23 config: Config,
24 storage: Mutex<Vec<T>>,
25 condvar: Condvar,
26}
27
28impl<T: Send + 'static> Pool<T> {
29 pub fn new(items: impl IntoIterator<Item = T>) -> Self {
30 Self::with_config(Config::default(), items)
31 }
32
33 pub fn with_config(config: Config, items: impl IntoIterator<Item = T>) -> Self {
34 let objects = items.into_iter().collect();
35 Self {
36 config,
37 storage: Mutex::new(objects),
38 condvar: Condvar::new(),
39 }
40 }
41
42 pub fn take(&self) -> Option<PoolObject<T>> {
46 let mut lock = self.storage.lock();
47 while lock.is_empty() {
48 let wait_res = self.condvar.wait_for(&mut lock, self.config.wait_duration);
49 if wait_res.timed_out() {
50 return None;
51 }
52 }
53 let inner = lock.pop().unwrap();
54 Some(PoolObject::new(inner, self))
55 }
56
57 pub fn add(&self, item: T) {
59 self.storage.lock().push(item);
60 }
61
62 pub fn size(&self) -> usize {
64 self.storage.lock().len()
65 }
66
67 pub(crate) fn put(&self, item: T) {
69 self.storage.lock().push(item);
70 self.condvar.notify_one();
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use crate::pool::Pool;
77 use crate::Config;
78 use std::ops::Deref;
79
80 #[test]
81 fn test_create() {
82 let pool = Pool::new([1, 2, 3]);
83 assert_eq!(pool.size(), 3);
84 }
85
86 #[test]
87 fn test_take() {
88 let pool = Pool::new([1, 2, 3]);
89 let obj1 = pool.take();
90 assert_eq!(pool.size(), 2);
91 assert_eq!(*obj1.as_ref().unwrap().deref(), 3);
92 }
93
94 #[test]
95 fn test_add() {
96 let pool = Pool::new([1]);
97 pool.add(2);
98 assert_eq!(pool.size(), 2);
99 }
100
101 #[test]
102 fn test_wait() {
103 let wait_time = std::time::Duration::from_millis(20);
104 let config = Config {
105 wait_duration: wait_time,
106 };
107 let pool = Pool::with_config(config, [1]);
108 let _obj1 = pool.take();
109 assert_eq!(pool.size(), 0);
110 let start_time = std::time::Instant::now();
111 let obj2 = pool.take();
112 assert!(start_time.elapsed() >= wait_time);
113 assert!(obj2.is_none());
114 }
115
116 #[test]
117 fn test_workflow() -> anyhow::Result<()> {
118 let config = Config {
119 wait_duration: std::time::Duration::from_millis(5),
120 };
121 let pool = Pool::with_config(config, [1, 2, 3]);
122 assert_eq!(pool.size(), 3);
123
124 let obj1 = pool.take();
125 assert_eq!(pool.size(), 2);
126 assert_eq!(*obj1.as_ref().unwrap().deref(), 3);
127
128 let obj2 = pool.take();
129 assert_eq!(*obj2.as_ref().unwrap().deref(), 2);
130 let obj3 = pool.take();
131 assert_eq!(pool.size(), 0);
132 assert_eq!(*obj3.as_ref().unwrap().deref(), 1);
133
134 let obj4 = pool.take();
135 assert!(obj4.is_none());
136
137 Ok(())
138 }
139}