rust_loguru/
record_pool.rs1use parking_lot::Mutex;
2use std::sync::atomic::{AtomicUsize, Ordering};
3use std::sync::Arc;
4
5use crate::level::LogLevel;
6use crate::record::Record;
7
8pub struct RecordPool {
10 pool: Arc<Mutex<Vec<Record>>>,
12 capacity: usize,
14 size: Arc<AtomicUsize>,
16}
17
18impl RecordPool {
19 pub fn new(capacity: usize) -> Self {
21 Self {
22 pool: Arc::new(Mutex::new(Vec::with_capacity(capacity))),
23 capacity,
24 size: Arc::new(AtomicUsize::new(0)),
25 }
26 }
27
28 pub fn acquire(&self) -> PooledRecord {
30 let record = {
31 let mut guard = self.pool.lock();
32 if let Some(record) = guard.pop() {
33 self.size.fetch_sub(1, Ordering::Relaxed);
34 record
35 } else {
36 Record::empty()
37 }
38 };
39
40 PooledRecord {
41 record: Some(record),
42 pool: self.pool.clone(),
43 size: self.size.clone(),
44 capacity: self.capacity,
45 }
46 }
47
48 pub fn size(&self) -> usize {
50 self.size.load(Ordering::Relaxed)
51 }
52
53 pub fn capacity(&self) -> usize {
55 self.capacity
56 }
57
58 pub fn clear(&self) {
60 let mut guard = self.pool.lock();
61 guard.clear();
62 self.size.store(0, Ordering::Relaxed);
63 }
64}
65
66impl Default for RecordPool {
67 fn default() -> Self {
68 Self::new(128)
69 }
70}
71
72pub struct PooledRecord {
74 record: Option<Record>,
76 pool: Arc<Mutex<Vec<Record>>>,
78 size: Arc<AtomicUsize>,
80 capacity: usize,
82}
83
84impl PooledRecord {
85 pub fn get_mut(&mut self) -> &mut Record {
87 self.record.as_mut().unwrap()
88 }
89
90 pub fn get(&self) -> &Record {
92 self.record.as_ref().unwrap()
93 }
94
95 pub fn into_record(mut self) -> Record {
97 self.record.take().unwrap()
98 }
99
100 pub fn set_level(&mut self, level: LogLevel) {
102 if let Some(record) = self.record.as_mut() {
103 *record = Record::new(
104 level,
105 record.message().to_string(),
106 Some(record.module().to_string()),
107 Some(record.file().to_string()),
108 Some(record.line()),
109 );
110 }
111 }
112
113 pub fn set_message(&mut self, message: impl Into<String>) {
115 if let Some(record) = self.record.as_mut() {
116 *record = Record::new(
117 record.level(),
118 message,
119 Some(record.module().to_string()),
120 Some(record.file().to_string()),
121 Some(record.line()),
122 );
123 }
124 }
125}
126
127impl Drop for PooledRecord {
128 fn drop(&mut self) {
129 if let Some(record) = self.record.take() {
131 let current_size = self.size.load(Ordering::Relaxed);
132 if current_size < self.capacity {
133 let mut guard = self.pool.lock();
134 guard.push(record);
135 self.size.fetch_add(1, Ordering::Relaxed);
136 }
137 }
138 }
139}
140
141impl std::ops::Deref for PooledRecord {
142 type Target = Record;
143
144 fn deref(&self) -> &Self::Target {
145 self.get()
146 }
147}
148
149impl std::ops::DerefMut for PooledRecord {
150 fn deref_mut(&mut self) -> &mut Self::Target {
151 self.get_mut()
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 #[test]
160 fn test_record_pool_basic() {
161 let pool = RecordPool::new(2);
162 assert_eq!(pool.size(), 0);
163
164 let mut record = pool.acquire();
165 record.set_level(LogLevel::Info);
166 record.set_message("test");
167 drop(record);
168
169 assert_eq!(pool.size(), 1);
170 }
171
172 #[test]
173 fn test_record_pool_capacity() {
174 let pool = RecordPool::new(1);
175
176 let record1 = pool.acquire();
177 let record2 = pool.acquire();
178
179 drop(record1);
180 assert_eq!(pool.size(), 1);
181
182 drop(record2);
183 assert_eq!(pool.size(), 1); }
185
186 #[test]
187 fn test_record_pool_clear() {
188 let pool = RecordPool::new(2);
189
190 let record1 = pool.acquire();
191 let record2 = pool.acquire();
192
193 drop(record1);
194 drop(record2);
195
196 assert_eq!(pool.size(), 2);
197 pool.clear();
198 assert_eq!(pool.size(), 0);
199 }
200
201 #[test]
202 fn test_pooled_record_into_record() {
203 let pool = RecordPool::new(1);
204
205 let record = pool.acquire();
206 let _owned = record.into_record();
207
208 assert_eq!(pool.size(), 0); }
210
211 #[test]
212 fn test_pooled_record() {
213 let pool = RecordPool::new(1);
214 let mut record = pool.acquire();
215
216 record.set_level(LogLevel::Info);
217 record.set_message("test");
218
219 let owned = record.into_record();
220 assert_eq!(owned.level(), LogLevel::Info);
221 assert_eq!(owned.message(), "test");
222 }
223}