excel_lib/
dependency.rs

1use petgraph::{
2    graphmap::DiGraphMap, 
3    algo::toposort, 
4    dot::{Dot, Config}
5}; 
6use std::{fmt, cmp::Ordering}; 
7use crate::{
8    workbook::Sheet,
9    parser::{
10        parse_str, 
11        ast::Expr
12    }, 
13    reference::Reference, 
14    errors::Error,
15}; 
16
17#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
18pub struct CellId {
19    pub sheet: usize, 
20    pub row: usize,
21    pub column: usize,
22    pub num_row: usize, 
23    pub num_col: usize, 
24    pub calculated: Option<bool>
25}
26
27impl PartialOrd for CellId {
28    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
29        Some(self.cmp(other))
30    }
31}
32
33impl Ord for CellId {
34    fn cmp(&self, other: &Self) -> Ordering {
35        if self.sheet == other.sheet {
36            if self.row != other.row {
37                self.row.cmp(&other.row)
38            } else {
39                self.column.cmp(&other.column)
40            }
41        } else {
42            self.sheet.cmp(&other.sheet)
43        }
44    }
45}
46
47impl From<(usize, usize, usize, usize, usize, Option<bool>)> for CellId {
48    fn from((sheet, row, column, num_row, num_col, calculated) : (usize, usize, usize, usize, usize, Option<bool>)) -> CellId {
49        CellId { sheet, row, column, num_row, num_col, calculated }
50    }
51}
52
53impl fmt::Display for CellId {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        write!(f, "{}.{}.{}", self.sheet, self.row, self.column)
56    }
57}
58
59pub struct DependencyTree {
60    tree: DiGraphMap<CellId, u8>, 
61    pub offsets: Vec<CellId>
62}
63
64/*
65Precedent cells — cells that are referred to by a formula in another cell. For example, if cell D10 contains the formula =B5, then cell B5 is a precedent to cell D10.
66
67Dependent cells — these cells contain formulas that refer to other cells. For example, if cell D10 contains the formula =B5, cell D10 is a dependent of cell B5.
68*/
69
70impl Default for DependencyTree {
71    fn default() -> Self {
72        Self::new()
73    }
74}
75
76impl DependencyTree {
77    pub fn new() -> DependencyTree {
78        DependencyTree { tree: DiGraphMap::new(), offsets: vec![] }
79    }
80
81    pub fn add_formula(&mut self, cell: CellId, formula_text: &str, sheets: &Vec<Sheet>) -> Result<(), Error> {
82        let mut chars = formula_text.chars();
83        chars.next(); // FIXME: Parse can't handle the = in the front of a formula
84        let expression: Expr = parse_str(chars.as_str())?;
85        self.add_expression(cell, expression, sheets)?; 
86        Ok(())
87    }
88
89    pub fn add_expression(&mut self, cell: CellId, expression: Expr, sheets: &Vec<Sheet>) -> Result<(), Error> {
90        match expression {
91            Expr::Reference { sheet, reference } => {
92                let sheet_id = match sheet {
93                    Some(s) => {
94                        sheets.iter().position(|x|  {
95                            x.name == s
96                        }).unwrap()
97                    }, 
98                    None => cell.sheet
99                }; 
100                let sheet: &Sheet = sheets.get(sheet_id).unwrap(); 
101                let reference = Reference::from(reference); 
102                let (mut start_row, mut start_col, mut num_rows, mut num_cols) = reference.get_dimensions(); 
103                start_row = start_row.max(1); 
104                start_col = start_col.max(1); 
105                num_rows = num_rows.min(sheet.max_rows);
106                num_cols = num_cols.min(sheet.max_columns); 
107                let pre_cell: CellId; 
108                if reference.is_multi_cell() {
109                    pre_cell = CellId::from((sheet_id, start_row, start_col, num_rows, num_cols, None)); 
110                    if ! self.cell_exists(&pre_cell) {
111                        for c in Reference::get_cells_from_dim(start_row, start_col, num_rows, num_cols) {
112                            let sub_cell = CellId::from((sheet_id, c.0, c.1, 1, 1, Some(false))); 
113                            if sub_cell != pre_cell {
114                                self.add_precedent(&sub_cell, &pre_cell); 
115                            }
116                        }
117                    }
118                } else {
119                    pre_cell = CellId::from((sheet_id, start_row, start_col, num_rows, num_cols, Some(false))); 
120                }
121                if pre_cell != cell {
122                    self.add_precedent(&pre_cell, &cell); 
123                }
124            },
125            Expr::Infix(_, a, b) => {
126                self.add_expression(cell, *a, sheets)?; 
127                self.add_expression(cell, *b, sheets)?; 
128            }, 
129            Expr::Prefix(_, a) => {
130                self.add_expression(cell, *a, sheets)?; 
131            }, 
132            Expr::Func { name, args } => {
133                if name.as_str() == "OFFSET" {
134                    let mut offset_args = args.clone(); 
135                    offset_args.remove(0); 
136                    self.add_expression(cell, Expr::Array(offset_args), sheets)?; 
137                }
138                for arg in args.into_iter() {
139                    self.add_expression(cell, arg, sheets)?; 
140                }
141            }, 
142            Expr::Array(arr) => {
143                for a in arr.into_iter() {
144                    self.add_expression(cell, a, sheets)?; 
145                }
146            }, 
147            _ => {}
148            
149        }
150        Ok(())
151    }
152
153    pub fn add_cell(&mut self, cell: CellId) {
154        self.tree.add_node(cell); 
155    }
156
157    pub fn cell_exists(&self, cell: &CellId) -> bool {
158        self.tree.contains_node(*cell)
159    }
160
161    pub fn add_cell_if_missing(&mut self, cell: &CellId) {
162        if self.tree.contains_node(*cell) {
163            self.add_cell(*cell); 
164        }
165    }
166
167    pub fn add_precedent(&mut self, precedent: &CellId, cell: &CellId) {
168        self.add_cell_if_missing(precedent);
169        self.add_cell_if_missing(cell);
170        if !self.tree.contains_edge(*cell, *precedent) {
171            self.tree.add_edge(*precedent, *cell, 0); 
172        }
173   } 
174
175    pub fn is_precedent_of(&self, cell1: &CellId, cell2: &CellId) -> bool {
176        self.tree.contains_edge(*cell1, *cell2)
177    }
178
179    pub fn is_dependent_of(&self, cell1: &CellId, cell2: &CellId) -> bool {
180        self.tree.contains_edge(*cell2, *cell1) 
181    } 
182
183    pub fn get_order(&self) -> Vec<CellId> {
184        match toposort(&self.tree, None) {
185            Ok(order) => {
186                order
187                // order.into_iter().rev().collect::<Vec<CellId>>()
188            }, 
189            Err(e) => panic!("{:?}", e) 
190        } 
191    } 
192}
193
194impl fmt::Display for DependencyTree {
195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196        write!(f, "{}", Dot::with_config(&self.tree, &[Config::EdgeNoLabel]))
197    }
198}
199
200#[cfg(test)]
201mod tests {
202    use crate::dependency::*; 
203
204    #[test]
205    fn test_precedent() {
206        let mut tree = DependencyTree::new(); 
207        let a = CellId::from((0,0,0,1,1, Some(false))); 
208        let b = CellId::from((1,0,0,1,1, Some(false))); 
209        let c = CellId::from((2,0,0,1,1, Some(false))); 
210        tree.add_precedent(&a, &b); // A must calculate before B 
211        tree.add_precedent(&c, &b); // C must calculate before B 
212        assert!(tree.is_dependent_of(&b, &a)); 
213        assert_eq!(tree.is_dependent_of(&a, &b), false); 
214    }
215
216    #[test]
217    fn test_order() {
218        let mut tree = DependencyTree::new(); 
219        let a = CellId::from((0,0,0,1,1, Some(false))); 
220        let b = CellId::from((1,0,0,1,1, Some(false))); 
221        let c = CellId::from((2,0,0,1,1, Some(false))); 
222        tree.add_precedent(&a, &b); // A must calculate before B 
223        tree.add_precedent(&b, &c); // B must calculate before C 
224        let mut order: Vec<CellId> = tree.get_order(); 
225        assert_eq!(order.pop().unwrap(), c);
226        assert_eq!(order.pop().unwrap(), b);
227        assert_eq!(order.pop().unwrap(), a);
228    }
229}
230