1use crate::engine::VertexId;
2use crate::engine::VertexKind;
3use crate::engine::eval::Engine;
4use crate::traits::{
5 EvaluationContext, FunctionProvider, NamedRangeResolver, Range, RangeResolver,
6 ReferenceResolver, Resolver, SourceResolver, Table, TableResolver,
7};
8use formualizer_common::{ExcelError, LiteralValue};
9use formualizer_parse::parser::{ReferenceType, TableReference};
10use rustc_hash::FxHashSet;
11use std::sync::Mutex;
12
13use crate::interpreter::Interpreter;
14
15pub struct DynamicRefCollector<'a, R: EvaluationContext> {
16 pub engine: &'a Engine<R>,
17 pub current_sheet: &'a str,
18 pub collected: Mutex<FxHashSet<VertexId>>,
19}
20
21impl<'a, R: EvaluationContext> DynamicRefCollector<'a, R> {
22 pub fn new(engine: &'a Engine<R>, current_sheet: &'a str) -> Self {
23 Self {
24 engine,
25 current_sheet,
26 collected: Mutex::new(FxHashSet::default()),
27 }
28 }
29
30 fn collect_formula_vertices_in_rect(
31 &self,
32 sheet_name: &str,
33 sr: u32,
34 sc: u32,
35 er: u32,
36 ec: u32,
37 ) {
38 let Some(sheet_id) = self.engine.graph.sheet_id(sheet_name) else {
39 return;
40 };
41 let Some(index) = self.engine.graph.sheet_index(sheet_id) else {
42 return;
43 };
44
45 let sr0 = sr.saturating_sub(1);
46 let er0 = er.saturating_sub(1);
47 let sc0 = sc.saturating_sub(1);
48 let ec0 = ec.saturating_sub(1);
49
50 let mut out = self.collected.lock().unwrap();
51 for u in index.vertices_in_col_range(sc0, ec0) {
52 let row0 = self.engine.graph.vertex_coord(u).row();
53 if row0 < sr0 || row0 > er0 {
54 continue;
55 }
56 match self.engine.graph.get_vertex_kind(u) {
57 VertexKind::FormulaScalar | VertexKind::FormulaArray => {
58 if self.engine.graph.is_dirty(u) || self.engine.graph.is_volatile(u) {
59 out.insert(u);
60 }
61 }
62 _ => {}
63 }
64 }
65 }
66}
67
68impl<'a, R: EvaluationContext> ReferenceResolver for DynamicRefCollector<'a, R> {
69 fn resolve_cell_reference(
70 &self,
71 sheet: Option<&str>,
72 row: u32,
73 col: u32,
74 ) -> Result<LiteralValue, ExcelError> {
75 let sheet_name = sheet.unwrap_or(self.current_sheet);
76 if let Some(&vid) = self
77 .engine
78 .graph
79 .get_vertex_id_for_address(&self.engine.graph.make_cell_ref(sheet_name, row, col))
80 {
81 self.collected.lock().unwrap().insert(vid);
82 }
83 self.engine.resolve_cell_reference(sheet, row, col)
84 }
85}
86
87impl<'a, R: EvaluationContext> RangeResolver for DynamicRefCollector<'a, R> {
88 fn resolve_range_reference(
89 &self,
90 sheet: Option<&str>,
91 sr: Option<u32>,
92 sc: Option<u32>,
93 er: Option<u32>,
94 ec: Option<u32>,
95 ) -> Result<Box<dyn Range>, ExcelError> {
96 let sheet_name = sheet.unwrap_or(self.current_sheet);
97 let srv = sr.unwrap_or(1u32);
98 let scv = sc.unwrap_or(1u32);
99 let erv = er.unwrap_or(srv);
100 let ecv = ec.unwrap_or(scv);
101
102 self.collect_formula_vertices_in_rect(sheet_name, srv, scv, erv, ecv);
103
104 self.engine.resolve_range_reference(sheet, sr, sc, er, ec)
105 }
106}
107
108impl<'a, R: EvaluationContext> NamedRangeResolver for DynamicRefCollector<'a, R> {
109 fn resolve_named_range_reference(
110 &self,
111 name: &str,
112 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError> {
113 self.engine.resolve_named_range_reference(name)
114 }
115}
116
117impl<'a, R: EvaluationContext> TableResolver for DynamicRefCollector<'a, R> {
118 fn resolve_table_reference(&self, tref: &TableReference) -> Result<Box<dyn Table>, ExcelError> {
119 self.engine.resolve_table_reference(tref)
120 }
121}
122
123impl<'a, R: EvaluationContext> SourceResolver for DynamicRefCollector<'a, R> {
124 fn source_scalar_version(&self, name: &str) -> Option<u64> {
125 self.engine.source_scalar_version(name)
126 }
127 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
128 self.engine.resolve_source_scalar(name)
129 }
130 fn source_table_version(&self, name: &str) -> Option<u64> {
131 self.engine.source_table_version(name)
132 }
133 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
134 self.engine.resolve_source_table(name)
135 }
136}
137
138impl<'a, R: EvaluationContext> Resolver for DynamicRefCollector<'a, R> {}
139
140impl<'a, R: EvaluationContext> FunctionProvider for DynamicRefCollector<'a, R> {
141 fn get_function(
142 &self,
143 ns: &str,
144 name: &str,
145 ) -> Option<std::sync::Arc<dyn crate::traits::Function>> {
146 self.engine.get_function(ns, name)
147 }
148}
149
150impl<'a, R: EvaluationContext> EvaluationContext for DynamicRefCollector<'a, R> {
151 fn resolve_range_view<'c>(
152 &'c self,
153 reference: &ReferenceType,
154 current_sheet: &str,
155 ) -> Result<crate::engine::range_view::RangeView<'c>, ExcelError> {
156 match reference {
158 ReferenceType::Cell {
159 sheet, row, col, ..
160 } => {
161 let sheet_name = sheet.as_deref().unwrap_or(current_sheet);
162 self.collect_formula_vertices_in_rect(sheet_name, *row, *col, *row, *col);
163 }
164 ReferenceType::Range {
165 sheet,
166 start_row,
167 start_col,
168 end_row,
169 end_col,
170 ..
171 } => {
172 let sheet_name = sheet.as_deref().unwrap_or(current_sheet);
173
174 let srv = start_row.unwrap_or(1u32);
175 let scv = start_col.unwrap_or(1u32);
176 let erv = end_row.unwrap_or(srv);
177 let ecv = end_col.unwrap_or(scv);
178
179 self.collect_formula_vertices_in_rect(sheet_name, srv, scv, erv, ecv);
180 }
181 ReferenceType::NamedRange(name) => {
182 let sid = self.engine.sheet_id(current_sheet);
183 if let Some(s) = sid
184 && let Some(nr) = self.engine.graph.resolve_name_entry(name, s)
185 {
186 let vid = nr.vertex;
187 self.collected.lock().unwrap().insert(vid);
188 }
189 }
190 ReferenceType::Table(_) => {
191 }
193 _ => {}
194 }
195
196 self.engine.resolve_range_view(reference, current_sheet)
197 }
198}
199
200pub struct RangeVirtualDepProvider;
201
202impl RangeVirtualDepProvider {
203 pub fn get_virtual_deps<R: EvaluationContext>(
204 engine: &Engine<R>,
205 v: VertexId,
206 ) -> Vec<VertexId> {
207 let mut deps = Vec::new();
208 if let Some(ranges) = engine.graph.get_range_dependencies(v) {
209 let current_sheet_id = engine.graph.get_vertex_sheet_id(v);
210 for r in ranges {
211 let sheet_id = match r.sheet {
212 formualizer_common::SheetLocator::Id(id) => id,
213 _ => current_sheet_id,
214 };
215 let sheet_name = engine.graph.sheet_name(sheet_id);
216
217 let mut sr = r.start_row.map(|b| b.index + 1);
218 let mut sc = r.start_col.map(|b| b.index + 1);
219 let mut er = r.end_row.map(|b| b.index + 1);
220 let mut ec = r.end_col.map(|b| b.index + 1);
221
222 if sr.is_none() && er.is_none() {
223 let scv = sc.unwrap_or(1u32);
224 let ecv = ec.unwrap_or(scv);
225 if let Some((min_r, max_r)) = engine.used_rows_for_columns(sheet_name, scv, ecv)
226 {
227 sr = Some(min_r);
228 er = Some(max_r);
229 } else if let Some((_max_rows, _)) = engine.sheet_bounds(sheet_name) {
230 sr = Some(1);
231 er = Some(engine.config.max_open_ended_rows);
232 }
233 }
234 if sc.is_none() && ec.is_none() {
235 let srv = sr.unwrap_or(1u32);
236 let erv = er.unwrap_or(srv);
237 if let Some((min_c, max_c)) = engine.used_cols_for_rows(sheet_name, srv, erv) {
238 sc = Some(min_c);
239 ec = Some(max_c);
240 } else if let Some((_, _max_cols)) = engine.sheet_bounds(sheet_name) {
241 sc = Some(1);
242 ec = Some(engine.config.max_open_ended_cols);
243 }
244 }
245 if sr.is_some() && er.is_none() {
246 let scv = sc.unwrap_or(1u32);
247 let ecv = ec.unwrap_or(scv);
248 if let Some((_, max_r)) = engine.used_rows_for_columns(sheet_name, scv, ecv) {
249 er = Some(max_r);
250 } else if let Some((_max_rows, _)) = engine.sheet_bounds(sheet_name) {
251 er = Some(engine.config.max_open_ended_rows);
252 }
253 }
254 if er.is_some() && sr.is_none() {
255 let scv = sc.unwrap_or(1u32);
256 let ecv = ec.unwrap_or(scv);
257 if let Some((min_r, _)) = engine.used_rows_for_columns(sheet_name, scv, ecv) {
258 sr = Some(min_r);
259 } else {
260 sr = Some(1);
261 }
262 }
263 if sc.is_some() && ec.is_none() {
264 let srv = sr.unwrap_or(1u32);
265 let erv = er.unwrap_or(srv);
266 if let Some((_, max_c)) = engine.used_cols_for_rows(sheet_name, srv, erv) {
267 ec = Some(max_c);
268 } else if let Some((_, _max_cols)) = engine.sheet_bounds(sheet_name) {
269 ec = Some(engine.config.max_open_ended_cols);
270 }
271 }
272 if ec.is_some() && sc.is_none() {
273 let srv = sr.unwrap_or(1u32);
274 let erv = er.unwrap_or(srv);
275 if let Some((min_c, _)) = engine.used_cols_for_rows(sheet_name, srv, erv) {
276 sc = Some(min_c);
277 } else {
278 sc = Some(1);
279 }
280 }
281
282 let sr = sr.unwrap_or(1);
283 let sc = sc.unwrap_or(1);
284 let er = er.unwrap_or(sr.saturating_sub(1));
285 let ec = ec.unwrap_or(sc.saturating_sub(1));
286 if er < sr || ec < sc {
287 continue;
288 }
289
290 if let Some(index) = engine.graph.sheet_index(sheet_id) {
291 let sr0 = sr.saturating_sub(1);
292 let er0 = er.saturating_sub(1);
293 let sc0 = sc.saturating_sub(1);
294 let ec0 = ec.saturating_sub(1);
295 for u in index.vertices_in_col_range(sc0, ec0) {
296 let pc = engine.graph.vertex_coord(u);
297 let row0 = pc.row();
298 if row0 < sr0 || row0 > er0 {
299 continue;
300 }
301 match engine.graph.get_vertex_kind(u) {
302 VertexKind::FormulaScalar | VertexKind::FormulaArray => {
303 if (engine.graph.is_dirty(u) || engine.graph.is_volatile(u))
304 && u != v
305 {
306 deps.push(u);
307 }
308 }
309 _ => {}
310 }
311 }
312 }
313 }
314 }
315 deps
316 }
317}
318
319pub struct VirtualDepBuilder<'a, R: EvaluationContext> {
320 engine: &'a Engine<R>,
321}
322
323impl<'a, R: EvaluationContext> VirtualDepBuilder<'a, R> {
324 pub fn new(engine: &'a Engine<R>) -> Self {
325 Self { engine }
326 }
327 pub fn build(
328 &self,
329 candidates: &[VertexId],
330 ) -> (
331 rustc_hash::FxHashMap<VertexId, Vec<VertexId>>,
332 Vec<VertexId>,
333 ) {
334 let mut vdeps: rustc_hash::FxHashMap<VertexId, Vec<VertexId>> =
335 rustc_hash::FxHashMap::default();
336 let augmented_vertices: Vec<VertexId> = Vec::new(); for &v in candidates {
339 let mut deps = RangeVirtualDepProvider::get_virtual_deps(self.engine, v);
340 let dynamic_deps = DynamicRefVirtualDepProvider::get_virtual_deps(self.engine, v);
341
342 deps.extend(dynamic_deps);
343 deps.sort_unstable();
344 deps.dedup();
345
346 if !deps.is_empty() {
347 vdeps.insert(v, deps);
348 }
349 }
350
351 (vdeps, augmented_vertices)
352 }
353}
354
355pub struct DynamicRefVirtualDepProvider;
356
357impl DynamicRefVirtualDepProvider {
358 pub fn get_virtual_deps<R: EvaluationContext>(
359 engine: &Engine<R>,
360 v: VertexId,
361 ) -> Vec<VertexId> {
362 let mut deps = Vec::new();
363
364 if engine.graph.is_dynamic(v) {
365 if let Some(ast_id) = engine.graph.get_formula_id(v) {
367 let sheet_id = engine.graph.get_vertex_sheet_id(v);
368 let sheet_name = engine.graph.sheet_name(sheet_id);
369
370 let collector = DynamicRefCollector::new(engine, sheet_name);
371
372 let cell_ref = engine
373 .graph
374 .get_cell_ref(v)
375 .unwrap_or_else(|| engine.graph.make_cell_ref(sheet_name, 0, 0));
376
377 let interpreter = Interpreter::new_with_cell(&collector, sheet_name, cell_ref);
378
379 let _ = interpreter.evaluate_arena_ast(
381 ast_id,
382 engine.graph.data_store(),
383 engine.graph.sheet_reg(),
384 );
385
386 deps.extend(
387 collector
388 .collected
389 .lock()
390 .unwrap()
391 .iter()
392 .copied()
393 .filter(|&u| u != v),
394 );
395 }
396 }
397
398 deps
399 }
400}