1use super::*;
5use crate::error::{ OfficeError, Result, XlsxError };
6use crate::xlsx::cell::{ CellReference, CellValue };
7use std::collections::{ HashMap, HashSet, VecDeque };
8
9impl FormulaDependency {
10 pub fn new(cell: CellReference, depends_on: Vec<CellReference>) -> Self {
12 let mut dependent_cells = HashSet::new();
13 for dep in depends_on {
14 dependent_cells.insert(dep);
15 }
16 Self {
17 formula_cell: cell,
18 dependent_cells,
19 }
20 }
21}
22
23impl FormulaManager {
24 pub fn new(cell_provider: Box<dyn CellProvider>) -> Self {
26 Self {
27 formulas: HashMap::new(),
28 dependencies: HashMap::new(),
29 calculator: FormulaCalculator::new(cell_provider),
30 }
31 }
32
33 pub fn set_formula(&mut self, cell: &CellReference, formula: &str) -> Result<()> {
35 let expr = parse_formula(formula)?;
37
38 let dependencies = self.extract_dependencies(&expr);
40
41 self.formulas.insert(cell.clone(), expr);
43
44 if !dependencies.is_empty() {
46 let dependency = FormulaDependency::new(cell.clone(), dependencies);
47 self.dependencies.insert(cell.clone(), dependency);
48 }
49
50 Ok(())
51 }
52
53 pub fn remove_formula(&mut self, cell: &CellReference) {
55 self.formulas.remove(cell);
56 self.dependencies.remove(cell);
57 }
58
59 pub fn calculate_cell(&mut self, cell: &CellReference) -> Result<FormulaValue> {
61 if let Some(expr) = self.formulas.get(cell).cloned() {
62 self.calculator.evaluate(&expr)
63 } else {
64 Err(
65 OfficeError::Xlsx(XlsxError::InvalidFormula {
66 formula: format!("No formula found for cell {}", cell.to_a1()),
67 })
68 )
69 }
70 }
71
72 pub fn recalculate_all(&mut self) -> Result<HashMap<CellReference, FormulaValue>> {
74 let mut results = HashMap::new();
75
76 for cell in self.formulas.keys().cloned().collect::<Vec<_>>() {
78 let result = self.calculate_cell(&cell)?;
79 results.insert(cell, result);
80 }
81
82 Ok(results)
83 }
84
85 pub fn get_dependents(&self, _cell: &CellReference) -> Vec<CellReference> {
87 Vec::new()
90 }
91
92 pub fn get_dependencies(&self, cell: &CellReference) -> Vec<CellReference> {
94 self.dependencies
95 .get(cell)
96 .map(|dep| dep.dependent_cells.iter().cloned().collect())
97 .unwrap_or_default()
98 }
99
100 pub fn has_circular_dependency(&self, _cell: &CellReference) -> bool {
102 false
105 }
106
107 pub fn mark_dirty(&mut self, _cell: &CellReference) {
109 }
112
113 pub fn clear_cache(&mut self) {
115 self.formulas.clear();
117 self.dependencies.clear();
118 }
119
120 fn get_calculation_order(&self) -> Result<Vec<CellReference>> {
122 Ok(self.formulas.keys().cloned().collect())
124 }
125
126 fn extract_dependencies(&self, expr: &FormulaExpression) -> Vec<CellReference> {
128 let mut dependencies = Vec::new();
129 self.extract_dependencies_recursive(expr, &mut dependencies);
130 dependencies
131 }
132
133 fn extract_dependencies_recursive(
135 &self,
136 expr: &FormulaExpression,
137 dependencies: &mut Vec<CellReference>
138 ) {
139 match expr {
140 FormulaExpression::CellRef(cell_ref) => {
141 dependencies.push(cell_ref.clone());
142 }
143
144 FormulaExpression::RangeRef(start, end) => {
145 for row in start.row..=end.row {
147 for col in start.column..=end.column {
148 dependencies.push(CellReference::new(col, row));
149 }
150 }
151 }
152
153 FormulaExpression::Function { args, .. } => {
154 for arg in args {
155 self.extract_dependencies_recursive(arg, dependencies);
156 }
157 }
158
159 FormulaExpression::BinaryOp { left, right, .. } => {
160 self.extract_dependencies_recursive(left, dependencies);
161 self.extract_dependencies_recursive(right, dependencies);
162 }
163
164 FormulaExpression::UnaryOp { operand, .. } => {
165 self.extract_dependencies_recursive(operand, dependencies);
166 }
167
168 FormulaExpression::Constant(_) => {
169 }
171 }
172 }
173
174 }
176
177pub struct FormulaCacheManager {
179 cache: HashMap<String, FormulaValue>,
180 max_size: usize,
181 access_order: VecDeque<String>,
182}
183
184impl FormulaCacheManager {
185 pub fn new(max_size: usize) -> Self {
187 Self {
188 cache: HashMap::new(),
189 max_size,
190 access_order: VecDeque::new(),
191 }
192 }
193
194 pub fn get(&mut self, key: &str) -> Option<&FormulaValue> {
196 if self.cache.contains_key(key) {
197 self.access_order.retain(|k| k != key);
199 self.access_order.push_back(key.to_string());
200
201 self.cache.get(key)
202 } else {
203 None
204 }
205 }
206
207 pub fn set(&mut self, key: String, value: FormulaValue) {
209 if self.cache.contains_key(&key) {
211 self.cache.insert(key.clone(), value);
212 self.access_order.retain(|k| k != &key);
213 self.access_order.push_back(key);
214 return;
215 }
216
217 if self.cache.len() >= self.max_size {
219 if let Some(oldest_key) = self.access_order.pop_front() {
220 self.cache.remove(&oldest_key);
221 }
222 }
223
224 self.cache.insert(key.clone(), value);
226 self.access_order.push_back(key);
227 }
228
229 pub fn remove(&mut self, key: &str) {
231 self.cache.remove(key);
232 self.access_order.retain(|k| k != key);
233 }
234
235 pub fn clear(&mut self) {
237 self.cache.clear();
238 self.access_order.clear();
239 }
240
241 pub fn size(&self) -> usize {
243 self.cache.len()
244 }
245
246 pub fn get_stats(&self) -> CacheStats {
248 CacheStats {
249 size: self.cache.len(),
250 max_size: self.max_size,
251 }
253 }
254}
255
256#[derive(Debug, Clone)]
258pub struct CacheStats {
259 pub size: usize,
260 pub max_size: usize,
261}
262
263pub struct FormulaProfiler {
265 execution_times: HashMap<String, Vec<std::time::Duration>>,
266 call_counts: HashMap<String, usize>,
267}
268
269impl FormulaProfiler {
270 pub fn new() -> Self {
272 Self {
273 execution_times: HashMap::new(),
274 call_counts: HashMap::new(),
275 }
276 }
277
278 pub fn record_execution(&mut self, function_name: &str, duration: std::time::Duration) {
280 self.execution_times
281 .entry(function_name.to_string())
282 .or_insert_with(Vec::new)
283 .push(duration);
284
285 *self.call_counts.entry(function_name.to_string()).or_insert(0) += 1;
286 }
287
288 pub fn get_average_time(&self, function_name: &str) -> Option<std::time::Duration> {
290 if let Some(times) = self.execution_times.get(function_name) {
291 if !times.is_empty() {
292 let total: std::time::Duration = times.iter().sum();
293 Some(total / (times.len() as u32))
294 } else {
295 None
296 }
297 } else {
298 None
299 }
300 }
301
302 pub fn get_call_count(&self, function_name: &str) -> usize {
304 self.call_counts.get(function_name).copied().unwrap_or(0)
305 }
306
307 pub fn get_performance_report(&self) -> Vec<PerformanceReport> {
309 let mut reports = Vec::new();
310
311 for (function_name, times) in &self.execution_times {
312 if !times.is_empty() {
313 let total: std::time::Duration = times.iter().sum();
314 let average = total / (times.len() as u32);
315 let min = *times.iter().min().unwrap();
316 let max = *times.iter().max().unwrap();
317 let call_count = self.get_call_count(function_name);
318
319 reports.push(PerformanceReport {
320 function_name: function_name.clone(),
321 call_count,
322 total_time: total,
323 average_time: average,
324 min_time: min,
325 max_time: max,
326 });
327 }
328 }
329
330 reports.sort_by(|a, b| b.total_time.cmp(&a.total_time));
332 reports
333 }
334
335 pub fn clear(&mut self) {
337 self.execution_times.clear();
338 self.call_counts.clear();
339 }
340}
341
342#[derive(Debug, Clone)]
344pub struct PerformanceReport {
345 pub function_name: String,
346 pub call_count: usize,
347 pub total_time: std::time::Duration,
348 pub average_time: std::time::Duration,
349 pub min_time: std::time::Duration,
350 pub max_time: std::time::Duration,
351}
352
353#[cfg(test)]
354mod tests {
355 use super::*;
356 use crate::xlsx::cell::CellValue;
357
358 struct MockCellProvider;
359
360 impl CellProvider for MockCellProvider {
361 fn get_cell_value(&self, _reference: &CellReference) -> Result<CellValue> {
362 Ok(CellValue::Number(10.0))
363 }
364
365 fn get_range_values(
366 &self,
367 _start: &CellReference,
368 _end: &CellReference
369 ) -> Result<Vec<Vec<CellValue>>> {
370 Ok(vec![vec![CellValue::Number(10.0)]])
371 }
372 }
373
374 #[test]
375 fn test_formula_manager_dependencies() {
376 let provider = Box::new(MockCellProvider);
377 let mut manager = FormulaManager::new(provider);
378
379 let cell_a1 = CellReference::new(0, 0); let cell_b1 = CellReference::new(1, 0); manager.set_formula(&cell_a1, "=B1+1").unwrap();
384
385 let deps = manager.get_dependencies(&cell_a1);
387 assert_eq!(deps.len(), 1);
388 assert_eq!(deps[0], cell_b1);
389
390 let dependents = manager.get_dependents(&cell_b1);
392 assert_eq!(dependents.len(), 0);
393 }
394
395 #[test]
396 fn test_formula_storage() {
397 let provider = Box::new(MockCellProvider);
398 let mut manager = FormulaManager::new(provider);
399 let cell_a1 = CellReference::new(0, 0); manager.set_formula(&cell_a1, "=42").unwrap();
403
404 assert!(manager.formulas.contains_key(&cell_a1));
406
407 manager.remove_formula(&cell_a1);
409 assert!(!manager.formulas.contains_key(&cell_a1));
410 }
411
412 #[test]
413 fn test_cache_manager() {
414 let mut cache = FormulaCacheManager::new(2);
415
416 cache.set("key1".to_string(), FormulaValue::Number(1.0));
418 cache.set("key2".to_string(), FormulaValue::Number(2.0));
419
420 assert!(cache.get("key1").is_some());
422 assert!(cache.get("key2").is_some());
423
424 cache.set("key3".to_string(), FormulaValue::Number(3.0));
426
427 assert!(cache.get("key1").is_none());
429 assert!(cache.get("key2").is_some());
430 assert!(cache.get("key3").is_some());
431 }
432
433 #[test]
434 fn test_profiler() {
435 let mut profiler = FormulaProfiler::new();
436
437 profiler.record_execution("SUM", std::time::Duration::from_millis(10));
439 profiler.record_execution("SUM", std::time::Duration::from_millis(20));
440 profiler.record_execution("AVERAGE", std::time::Duration::from_millis(15));
441
442 assert_eq!(profiler.get_call_count("SUM"), 2);
444 assert_eq!(profiler.get_call_count("AVERAGE"), 1);
445
446 let avg_time = profiler.get_average_time("SUM").unwrap();
447 assert_eq!(avg_time, std::time::Duration::from_millis(15));
448
449 let reports = profiler.get_performance_report();
451 assert_eq!(reports.len(), 2);
452 }
453}