1use std::fmt;
7
8use crate::calc::CellRef;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum ArgType {
13 Unknown,
14 Number,
15 String,
16 List,
17 Matrix,
18 Error,
19 Empty,
20}
21
22#[derive(Debug, Clone)]
24pub struct FormulaArg {
25 pub sheet_name: String,
26 pub number: f64,
27 pub string: String,
28 pub list: Vec<FormulaArg>,
29 pub matrix: Vec<Vec<FormulaArg>>,
30 pub boolean: bool,
31 pub error: String,
32 pub cell_refs: Vec<CellRef>,
33 pub cell_ranges: Vec<(CellRef, CellRef)>,
34 pub typ: ArgType,
35}
36
37impl Default for FormulaArg {
38 fn default() -> Self {
39 new_empty_formula_arg()
40 }
41}
42
43pub fn new_empty_formula_arg() -> FormulaArg {
45 FormulaArg {
46 sheet_name: String::new(),
47 number: 0.0,
48 string: String::new(),
49 list: Vec::new(),
50 matrix: Vec::new(),
51 boolean: false,
52 error: String::new(),
53 cell_refs: Vec::new(),
54 cell_ranges: Vec::new(),
55 typ: ArgType::Empty,
56 }
57}
58
59pub fn new_number_formula_arg(n: f64) -> FormulaArg {
61 FormulaArg {
62 sheet_name: String::new(),
63 number: n,
64 string: String::new(),
65 list: Vec::new(),
66 matrix: Vec::new(),
67 boolean: false,
68 error: String::new(),
69 cell_refs: Vec::new(),
70 cell_ranges: Vec::new(),
71 typ: ArgType::Number,
72 }
73}
74
75pub fn new_string_formula_arg(s: impl Into<String>) -> FormulaArg {
77 FormulaArg {
78 sheet_name: String::new(),
79 number: 0.0,
80 string: s.into(),
81 list: Vec::new(),
82 matrix: Vec::new(),
83 boolean: false,
84 error: String::new(),
85 cell_refs: Vec::new(),
86 cell_ranges: Vec::new(),
87 typ: ArgType::String,
88 }
89}
90
91pub fn new_bool_formula_arg(b: bool) -> FormulaArg {
94 FormulaArg {
95 sheet_name: String::new(),
96 number: if b { 1.0 } else { 0.0 },
97 string: String::new(),
98 list: Vec::new(),
99 matrix: Vec::new(),
100 boolean: true,
101 error: String::new(),
102 cell_refs: Vec::new(),
103 cell_ranges: Vec::new(),
104 typ: ArgType::Number,
105 }
106}
107
108pub fn new_error_formula_arg(err: impl Into<String>) -> FormulaArg {
110 FormulaArg {
111 sheet_name: String::new(),
112 number: 0.0,
113 string: String::new(),
114 list: Vec::new(),
115 matrix: Vec::new(),
116 boolean: false,
117 error: err.into(),
118 cell_refs: Vec::new(),
119 cell_ranges: Vec::new(),
120 typ: ArgType::Error,
121 }
122}
123
124pub fn new_list_formula_arg(list: Vec<FormulaArg>) -> FormulaArg {
126 FormulaArg {
127 sheet_name: String::new(),
128 number: 0.0,
129 string: String::new(),
130 list,
131 matrix: Vec::new(),
132 boolean: false,
133 error: String::new(),
134 cell_refs: Vec::new(),
135 cell_ranges: Vec::new(),
136 typ: ArgType::List,
137 }
138}
139
140pub fn new_matrix_formula_arg(matrix: Vec<Vec<FormulaArg>>) -> FormulaArg {
142 FormulaArg {
143 sheet_name: String::new(),
144 number: 0.0,
145 string: String::new(),
146 list: Vec::new(),
147 matrix,
148 boolean: false,
149 error: String::new(),
150 cell_refs: Vec::new(),
151 cell_ranges: Vec::new(),
152 typ: ArgType::Matrix,
153 }
154}
155
156impl FormulaArg {
157 pub fn value(&self) -> String {
159 match self.typ {
160 ArgType::Number => {
161 if self.boolean {
162 if self.number == 0.0 {
163 "FALSE".to_string()
164 } else {
165 "TRUE".to_string()
166 }
167 } else {
168 format!("{}", self.number)
169 }
170 }
171 ArgType::String => self.string.clone(),
172 ArgType::Matrix => {
173 if let Some(first) = self.to_list().first() {
174 return first.value();
175 }
176 String::new()
177 }
178 ArgType::Error => self.error.clone(),
179 _ => String::new(),
180 }
181 }
182
183 pub fn to_number(&self) -> FormulaArg {
186 match self.typ {
187 ArgType::String => match self.string.parse::<f64>() {
188 Ok(n) => new_number_formula_arg(n),
189 Err(_) => new_error_formula_arg("#VALUE!"),
190 },
191 ArgType::Number => new_number_formula_arg(self.number),
192 ArgType::Matrix => {
193 if let Some(first) = self.to_list().first() {
194 return first.to_number();
195 }
196 new_number_formula_arg(0.0)
197 }
198 ArgType::Empty => new_number_formula_arg(0.0),
199 _ => new_error_formula_arg("#VALUE!"),
200 }
201 }
202
203 pub fn to_bool(&self) -> FormulaArg {
205 match self.typ {
206 ArgType::String => match self.string.to_lowercase().parse::<bool>() {
207 Ok(b) => new_bool_formula_arg(b),
208 Err(_) => new_error_formula_arg("#VALUE!"),
209 },
210 ArgType::Number => new_bool_formula_arg(self.number == 1.0),
211 ArgType::Matrix => {
212 if let Some(first) = self.to_list().first() {
213 return first.to_bool();
214 }
215 new_bool_formula_arg(false)
216 }
217 ArgType::Empty => new_bool_formula_arg(false),
218 _ => new_error_formula_arg("#VALUE!"),
219 }
220 }
221
222 pub fn to_list(&self) -> Vec<FormulaArg> {
224 match self.typ {
225 ArgType::Matrix => self
226 .matrix
227 .iter()
228 .flat_map(|row| row.iter().cloned())
229 .collect(),
230 ArgType::List => self.list.clone(),
231 ArgType::Empty => Vec::new(),
232 _ => vec![self.clone()],
233 }
234 }
235
236 pub fn as_number(&self) -> Option<f64> {
238 match self.typ {
239 ArgType::Number => Some(self.number),
240 ArgType::String => self.string.parse::<f64>().ok(),
241 ArgType::Empty => Some(0.0),
242 _ => None,
243 }
244 }
245
246 pub fn as_bool(&self) -> bool {
248 match self.typ {
249 ArgType::Empty => false,
250 ArgType::Number => self.number != 0.0,
251 ArgType::String => !self.string.is_empty(),
252 ArgType::Error => false,
253 ArgType::List => !self.list.is_empty(),
254 ArgType::Matrix => !self.matrix.is_empty(),
255 ArgType::Unknown => false,
256 }
257 }
258
259 pub fn as_string(&self) -> String {
261 match self.typ {
262 ArgType::Number => {
263 if self.number.is_nan() || self.number.is_infinite() {
264 return "#NUM!".to_string();
265 }
266 if self.boolean {
267 return self.value();
268 }
269 if self.number.fract() == 0.0 {
270 format!("{}", self.number as i64)
271 } else {
272 format!("{}", self.number)
273 }
274 }
275 ArgType::String => self.string.clone(),
276 ArgType::Empty => String::new(),
277 ArgType::Error => self.error.clone(),
278 ArgType::List | ArgType::Matrix => String::new(),
279 ArgType::Unknown => String::new(),
280 }
281 }
282
283 pub fn is_error(&self) -> bool {
285 self.typ == ArgType::Error
286 }
287}
288
289impl fmt::Display for FormulaArg {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 write!(f, "{}", self.value())
292 }
293}
294
295pub fn collect_numbers(arg: &FormulaArg, out: &mut Vec<f64>) -> Option<FormulaArg> {
299 match arg.typ {
300 ArgType::Number => out.push(arg.number),
301 ArgType::List => {
302 for x in &arg.list {
303 if let Some(e) = collect_numbers(x, out) {
304 return Some(e);
305 }
306 }
307 }
308 ArgType::Matrix => {
309 for row in &arg.matrix {
310 for x in row {
311 if let Some(e) = collect_numbers(x, out) {
312 return Some(e);
313 }
314 }
315 }
316 }
317 ArgType::Error => return Some(arg.clone()),
318 _ => {}
319 }
320 None
321}
322
323pub fn numbers_from_args(args: &[FormulaArg]) -> (Vec<f64>, Option<FormulaArg>) {
325 let mut out = Vec::new();
326 for a in args {
327 if let Some(e) = collect_numbers(a, &mut out) {
328 return (out, Some(e));
329 }
330 }
331 (out, None)
332}
333
334pub fn flatten_string(arg: &FormulaArg) -> String {
336 match arg.typ {
337 ArgType::String => arg.string.clone(),
338 ArgType::List => arg.list.iter().map(flatten_string).collect(),
339 ArgType::Matrix => arg
340 .matrix
341 .iter()
342 .flat_map(|r| r.iter().map(flatten_string))
343 .collect(),
344 _ => arg.as_string(),
345 }
346}
347
348pub fn compare_equal(a: &FormulaArg, b: &FormulaArg) -> bool {
351 if let (Some(a), Some(b)) = (a.as_number(), b.as_number()) {
352 return a == b;
353 }
354 a.as_string().to_uppercase() == b.as_string().to_uppercase()
355}
356
357pub const FORMULA_ERROR_DIV: &str = "#DIV/0!";
359pub const FORMULA_ERROR_NAME: &str = "#NAME?";
360pub const FORMULA_ERROR_NA: &str = "#N/A";
361pub const FORMULA_ERROR_NUM: &str = "#NUM!";
362pub const FORMULA_ERROR_VALUE: &str = "#VALUE!";
363pub const FORMULA_ERROR_REF: &str = "#REF!";
364pub const FORMULA_ERROR_NULL: &str = "#NULL!";
365pub const FORMULA_ERROR_SPILL: &str = "#SPILL!";
366pub const FORMULA_ERROR_CALC: &str = "#CALC!";
367pub const FORMULA_ERROR_GETTING_DATA: &str = "#GETTING_DATA";