1use std::collections::HashMap;
4use std::time::{Duration, Instant};
5
6#[derive(Debug, Clone)]
8pub struct YamlProfiler {
9 timings: HashMap<String, Vec<Duration>>,
10 memory_usage: HashMap<String, usize>,
11 enabled: bool,
12}
13
14impl YamlProfiler {
15 pub fn new() -> Self {
17 Self {
18 timings: HashMap::new(),
19 memory_usage: HashMap::new(),
20 enabled: std::env::var("RUST_YAML_PROFILE").is_ok(),
21 }
22 }
23
24 pub const fn is_enabled(&self) -> bool {
26 self.enabled
27 }
28
29 pub const fn enable(&mut self) {
31 self.enabled = true;
32 }
33
34 pub const fn disable(&mut self) {
36 self.enabled = false;
37 }
38
39 pub fn time_operation<F, R>(&mut self, operation: &str, func: F) -> R
41 where
42 F: FnOnce() -> R,
43 {
44 if !self.enabled {
45 return func();
46 }
47
48 let start = Instant::now();
49 let result = func();
50 let duration = start.elapsed();
51
52 self.timings
53 .entry(operation.to_string())
54 .or_insert_with(Vec::new)
55 .push(duration);
56
57 result
58 }
59
60 pub fn record_memory(&mut self, operation: &str, bytes: usize) {
62 if !self.enabled {
63 return;
64 }
65
66 self.memory_usage.insert(operation.to_string(), bytes);
67 }
68
69 pub fn average_time(&self, operation: &str) -> Option<Duration> {
71 let timings = self.timings.get(operation)?;
72 if timings.is_empty() {
73 return None;
74 }
75
76 let total: Duration = timings.iter().sum();
77 Some(total / timings.len() as u32)
78 }
79
80 pub fn total_time(&self, operation: &str) -> Option<Duration> {
82 let timings = self.timings.get(operation)?;
83 Some(timings.iter().sum())
84 }
85
86 pub fn memory_usage(&self, operation: &str) -> Option<usize> {
88 self.memory_usage.get(operation).copied()
89 }
90
91 pub fn operations(&self) -> Vec<String> {
93 let mut ops: Vec<String> = self.timings.keys().cloned().collect();
94 ops.sort();
95 ops
96 }
97
98 pub fn clear(&mut self) {
100 self.timings.clear();
101 self.memory_usage.clear();
102 }
103
104 pub fn report(&self) -> String {
106 if !self.enabled {
107 return "Profiling disabled".to_string();
108 }
109
110 let mut report = String::new();
111 report.push_str("=== YAML Performance Report ===\n\n");
112
113 for operation in self.operations() {
114 report.push_str(&format!("Operation: {}\n", operation));
115
116 if let Some(avg_time) = self.average_time(&operation) {
117 report.push_str(&format!(" Average Time: {:?}\n", avg_time));
118 }
119
120 if let Some(total_time) = self.total_time(&operation) {
121 report.push_str(&format!(" Total Time: {:?}\n", total_time));
122 }
123
124 if let Some(memory) = self.memory_usage(&operation) {
125 report.push_str(&format!(" Memory Usage: {} bytes\n", memory));
126 }
127
128 if let Some(timings) = self.timings.get(&operation) {
129 report.push_str(&format!(" Sample Count: {}\n", timings.len()));
130 }
131
132 report.push('\n');
133 }
134
135 report
136 }
137}
138
139impl Default for YamlProfiler {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145#[derive(Debug)]
147pub struct StringInterner {
148 strings: HashMap<String, &'static str>,
149 enabled: bool,
150}
151
152impl StringInterner {
153 pub fn new() -> Self {
155 Self {
156 strings: HashMap::new(),
157 enabled: true,
158 }
159 }
160
161 pub const fn intern(&mut self, s: String) -> String {
163 if !self.enabled {
164 return s;
165 }
166
167 s
170 }
171
172 pub fn contains(&self, s: &str) -> bool {
174 if !self.enabled {
175 return false;
176 }
177 self.strings.contains_key(s)
178 }
179
180 pub fn stats(&self) -> (usize, usize) {
182 let count = self.strings.len();
183 let memory = self.strings.keys().map(|s| s.len()).sum::<usize>();
184 (count, memory)
185 }
186}
187
188impl Default for StringInterner {
189 fn default() -> Self {
190 Self::new()
191 }
192}
193
194#[derive(Debug)]
196pub struct ObjectPool<T> {
197 objects: Vec<T>,
198 enabled: bool,
199}
200
201impl<T> ObjectPool<T> {
202 pub const fn new() -> Self {
204 Self {
205 objects: Vec::new(),
206 enabled: true,
207 }
208 }
209
210 pub fn with_capacity(capacity: usize) -> Self {
212 Self {
213 objects: Vec::with_capacity(capacity),
214 enabled: true,
215 }
216 }
217
218 pub fn get<F>(&mut self, creator: F) -> T
220 where
221 F: FnOnce() -> T,
222 {
223 if self.enabled && !self.objects.is_empty() {
224 self.objects.pop().unwrap()
225 } else {
226 creator()
227 }
228 }
229
230 pub fn put(&mut self, object: T) {
232 if self.enabled {
233 self.objects.push(object);
234 }
235 }
236
237 pub const fn stats(&self) -> (usize, usize) {
239 (self.objects.len(), self.objects.capacity())
240 }
241}
242
243impl<T> Default for ObjectPool<T> {
244 fn default() -> Self {
245 Self::new()
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 #[test]
254 fn test_profiler_basic_functionality() {
255 let mut profiler = YamlProfiler::new();
256 profiler.enable();
257
258 let result = profiler.time_operation("test_op", || {
259 std::thread::sleep(Duration::from_millis(1));
260 42
261 });
262
263 assert_eq!(result, 42);
264 assert!(profiler.average_time("test_op").is_some());
265 assert!(profiler.total_time("test_op").is_some());
266 }
267
268 #[test]
269 fn test_profiler_memory_tracking() {
270 let mut profiler = YamlProfiler::new();
271 profiler.enable();
272
273 profiler.record_memory("allocation", 1024);
274 assert_eq!(profiler.memory_usage("allocation"), Some(1024));
275 }
276
277 #[test]
278 fn test_profiler_disabled() {
279 let mut profiler = YamlProfiler::new();
280 profiler.disable();
281
282 profiler.time_operation("test_op", || 42);
283 assert!(profiler.average_time("test_op").is_none());
284 }
285
286 #[test]
287 fn test_string_interner() {
288 let mut interner = StringInterner::new();
289 let s1 = interner.intern("test".to_string());
290 let s2 = interner.intern("test".to_string());
291
292 assert_eq!(s1, s2);
294 }
295
296 #[test]
297 fn test_object_pool() {
298 let mut pool = ObjectPool::new();
299
300 pool.put(String::from("test"));
302
303 let retrieved = pool.get(|| String::from("new"));
305 assert_eq!(retrieved, "test");
306
307 let new_obj = pool.get(|| String::from("fresh"));
309 assert_eq!(new_obj, "fresh");
310 }
311}