1use pdf_core::{CellValue, CellError};
6use std::collections::HashMap;
7
8pub type FnImpl = fn(&[CellValue]) -> Result<CellValue, String>;
9
10pub static FUNCTIONS: std::sync::LazyLock<HashMap<&'static str, FnImpl>> =
12 std::sync::LazyLock::new(|| {
13 let mut m: HashMap<&'static str, FnImpl> = HashMap::new();
14
15 m.insert("SUM", fn_sum);
17 m.insert("SUMIF", fn_sumif);
18 m.insert("SUMIFS", fn_sumifs);
19 m.insert("PRODUCT", fn_product);
20 m.insert("ABS", fn_abs);
21 m.insert("ROUND", fn_round);
22 m.insert("ROUNDUP", fn_roundup);
23 m.insert("ROUNDDOWN",fn_rounddown);
24 m.insert("CEILING", fn_ceiling);
25 m.insert("FLOOR", fn_floor);
26 m.insert("TRUNC", fn_trunc);
27 m.insert("INT", fn_int);
28 m.insert("MOD", fn_mod);
29 m.insert("POWER", fn_power);
30 m.insert("SQRT", fn_sqrt);
31 m.insert("SQRTPI", fn_sqrtpi);
32 m.insert("EXP", fn_exp);
33 m.insert("LN", fn_ln);
34 m.insert("LOG", fn_log);
35 m.insert("LOG10", fn_log10);
36 m.insert("PI", fn_pi);
37 m.insert("SIN", fn_sin);
38 m.insert("COS", fn_cos);
39 m.insert("TAN", fn_tan);
40 m.insert("ASIN", fn_asin);
41 m.insert("ACOS", fn_acos);
42 m.insert("ATAN", fn_atan);
43 m.insert("ATAN2", fn_atan2);
44 m.insert("DEGREES", fn_degrees);
45 m.insert("RADIANS", fn_radians);
46 m.insert("SIGN", fn_sign);
47 m.insert("RAND", fn_rand);
48 m.insert("RANDBETWEEN", fn_randbetween);
49 m.insert("FACT", fn_fact);
50 m.insert("COMBIN", fn_combin);
51 m.insert("PERMUT", fn_permut);
52 m.insert("GCD", fn_gcd);
53 m.insert("LCM", fn_lcm);
54 m.insert("EVEN", fn_even);
55 m.insert("ODD", fn_odd);
56 m.insert("MROUND", fn_mround);
57
58 m.insert("AVERAGE", fn_average);
60 m.insert("AVERAGEIF",fn_averageif);
61 m.insert("MIN", fn_min);
62 m.insert("MAX", fn_max);
63 m.insert("MEDIAN", fn_median);
64 m.insert("MODE", fn_mode);
65 m.insert("COUNT", fn_count);
66 m.insert("COUNTA", fn_counta);
67 m.insert("COUNTBLANK", fn_countblank);
68 m.insert("COUNTIF", fn_countif);
69 m.insert("COUNTIFS", fn_countifs);
70 m.insert("STDEV", fn_stdev);
71 m.insert("STDEVP", fn_stdevp);
72 m.insert("VAR", fn_var);
73 m.insert("VARP", fn_varp);
74 m.insert("LARGE", fn_large);
75 m.insert("SMALL", fn_small);
76 m.insert("RANK", fn_rank);
77 m.insert("PERCENTILE", fn_percentile);
78 m.insert("QUARTILE", fn_quartile);
79 m.insert("CORREL", fn_correl);
80 m.insert("COVAR", fn_covar);
81 m.insert("SLOPE", fn_slope);
82 m.insert("INTERCEPT",fn_intercept);
83
84 m.insert("LEN", fn_len);
86 m.insert("LEFT", fn_left);
87 m.insert("RIGHT", fn_right);
88 m.insert("MID", fn_mid);
89 m.insert("UPPER", fn_upper);
90 m.insert("LOWER", fn_lower);
91 m.insert("PROPER", fn_proper);
92 m.insert("TRIM", fn_trim);
93 m.insert("LTRIM", fn_ltrim);
94 m.insert("RTRIM", fn_rtrim);
95 m.insert("CONCATENATE", fn_concatenate);
96 m.insert("CONCAT", fn_concat);
97 m.insert("TEXTJOIN", fn_textjoin);
98 m.insert("REPLACE", fn_replace);
99 m.insert("SUBSTITUTE",fn_substitute);
100 m.insert("FIND", fn_find);
101 m.insert("SEARCH", fn_search);
102 m.insert("TEXT", fn_text);
103 m.insert("VALUE", fn_value);
104 m.insert("FIXED", fn_fixed);
105 m.insert("REPT", fn_rept);
106 m.insert("CODE", fn_code);
107 m.insert("CHAR", fn_char);
108 m.insert("EXACT", fn_exact);
109 m.insert("T", fn_t);
110
111 m.insert("IF", fn_if);
113 m.insert("IFS", fn_ifs);
114 m.insert("AND", fn_and);
115 m.insert("OR", fn_or);
116 m.insert("NOT", fn_not);
117 m.insert("XOR", fn_xor);
118 m.insert("IFERROR", fn_iferror);
119 m.insert("IFNA", fn_ifna);
120 m.insert("SWITCH", fn_switch);
121 m.insert("TRUE", fn_true);
122 m.insert("FALSE", fn_false);
123
124 m.insert("VLOOKUP", fn_vlookup);
126 m.insert("HLOOKUP", fn_hlookup);
127 m.insert("INDEX", fn_index);
128 m.insert("MATCH", fn_match);
129 m.insert("CHOOSE", fn_choose);
130 m.insert("OFFSET", fn_offset);
131 m.insert("ROW", fn_row);
132 m.insert("COLUMN", fn_column);
133 m.insert("ROWS", fn_rows);
134 m.insert("COLUMNS", fn_columns);
135 m.insert("TRANSPOSE",fn_transpose);
136
137 m.insert("NOW", fn_now);
139 m.insert("TODAY", fn_today);
140 m.insert("DATE", fn_date);
141 m.insert("TIME", fn_time);
142 m.insert("YEAR", fn_year);
143 m.insert("MONTH", fn_month);
144 m.insert("DAY", fn_day);
145 m.insert("HOUR", fn_hour);
146 m.insert("MINUTE", fn_minute);
147 m.insert("SECOND", fn_second);
148 m.insert("WEEKDAY", fn_weekday);
149 m.insert("WEEKNUM", fn_weeknum);
150 m.insert("EDATE", fn_edate);
151 m.insert("EOMONTH", fn_eomonth);
152 m.insert("NETWORKDAYS", fn_networkdays);
153 m.insert("WORKDAY", fn_workday);
154 m.insert("DATEDIF", fn_datedif);
155 m.insert("DATEVALUE",fn_datevalue);
156 m.insert("TIMEVALUE",fn_timevalue);
157
158 m.insert("ISNUMBER", fn_isnumber);
160 m.insert("ISTEXT", fn_istext);
161 m.insert("ISBLANK", fn_isblank);
162 m.insert("ISERROR", fn_iserror);
163 m.insert("ISERR", fn_iserr);
164 m.insert("ISNA", fn_isna);
165 m.insert("ISLOGICAL",fn_islogical);
166 m.insert("ISODD", fn_isodd);
167 m.insert("ISEVEN", fn_iseven);
168 m.insert("NA", fn_na);
169 m.insert("ERROR.TYPE", fn_error_type);
170 m.insert("CELL", fn_cell);
171 m.insert("TYPE", fn_type);
172 m.insert("N", fn_n);
173
174 m.insert("PMT", fn_pmt);
176 m.insert("PV", fn_pv);
177 m.insert("FV", fn_fv);
178 m.insert("RATE", fn_rate);
179 m.insert("NPER", fn_nper);
180 m.insert("NPV", fn_npv);
181 m.insert("IRR", fn_irr);
182 m.insert("IPMT", fn_ipmt);
183 m.insert("PPMT", fn_ppmt);
184
185 m
186 });
187
188macro_rules! require_num {
191 ($v:expr) => {
192 $v.as_number().ok_or_else(|| format!("Expected number, got {:?}", $v))?
193 };
194}
195
196macro_rules! require_text {
197 ($v:expr) => {
198 match $v {
199 CellValue::Text(s) => s.clone(),
200 other => other.as_text(),
201 }
202 };
203}
204
205fn nums_from_args(args: &[CellValue]) -> Vec<f64> {
206 args.iter().filter_map(|v| v.as_number()).collect()
207}
208
209fn to_bool(v: &CellValue) -> bool {
210 match v {
211 CellValue::Bool(b) => *b,
212 CellValue::Number(n) => *n != 0.0,
213 CellValue::Text(s) => !s.is_empty(),
214 CellValue::Empty => false,
215 _ => false,
216 }
217}
218
219fn fn_sum(args: &[CellValue]) -> Result<CellValue, String> {
222 Ok(CellValue::Number(nums_from_args(args).iter().sum()))
223}
224
225fn fn_sumif(args: &[CellValue]) -> Result<CellValue, String> {
226 if args.len() < 2 { return Err("SUMIF requires at least 2 arguments".into()); }
227 let criteria = &args[1];
229 let sum: f64 = args[0..1].iter()
230 .zip(args.get(2..).unwrap_or(&args[0..1]))
231 .filter_map(|(check, sum_v)| {
232 if check == criteria { sum_v.as_number() } else { None }
233 })
234 .sum();
235 Ok(CellValue::Number(sum))
236}
237
238fn fn_sumifs(args: &[CellValue]) -> Result<CellValue, String> {
239 fn_sum(args)
241}
242
243fn fn_product(args: &[CellValue]) -> Result<CellValue, String> {
244 Ok(CellValue::Number(nums_from_args(args).iter().product()))
245}
246
247fn fn_abs(args: &[CellValue]) -> Result<CellValue, String> {
248 let n = require_num!(&args[0]);
249 Ok(CellValue::Number(n.abs()))
250}
251
252fn fn_round(args: &[CellValue]) -> Result<CellValue, String> {
253 let n = require_num!(&args[0]);
254 let places = if args.len() > 1 { require_num!(&args[1]) as i32 } else { 0 };
255 let factor = 10f64.powi(places);
256 Ok(CellValue::Number((n * factor).round() / factor))
257}
258
259fn fn_roundup(args: &[CellValue]) -> Result<CellValue, String> {
260 let n = require_num!(&args[0]);
261 let places = if args.len() > 1 { require_num!(&args[1]) as i32 } else { 0 };
262 let factor = 10f64.powi(places);
263 Ok(CellValue::Number((n * factor).ceil() / factor))
264}
265
266fn fn_rounddown(args: &[CellValue]) -> Result<CellValue, String> {
267 let n = require_num!(&args[0]);
268 let places = if args.len() > 1 { require_num!(&args[1]) as i32 } else { 0 };
269 let factor = 10f64.powi(places);
270 Ok(CellValue::Number((n * factor).floor() / factor))
271}
272
273fn fn_ceiling(args: &[CellValue]) -> Result<CellValue, String> {
274 let n = require_num!(&args[0]);
275 let sig = if args.len() > 1 { require_num!(&args[1]) } else { 1.0 };
276 if sig == 0.0 { return Ok(CellValue::Number(0.0)); }
277 Ok(CellValue::Number((n / sig).ceil() * sig))
278}
279
280fn fn_floor(args: &[CellValue]) -> Result<CellValue, String> {
281 let n = require_num!(&args[0]);
282 let sig = if args.len() > 1 { require_num!(&args[1]) } else { 1.0 };
283 if sig == 0.0 { return Ok(CellValue::Number(0.0)); }
284 Ok(CellValue::Number((n / sig).floor() * sig))
285}
286
287fn fn_trunc(args: &[CellValue]) -> Result<CellValue, String> {
288 let n = require_num!(&args[0]);
289 Ok(CellValue::Number(n.trunc()))
290}
291
292fn fn_int(args: &[CellValue]) -> Result<CellValue, String> {
293 let n = require_num!(&args[0]);
294 Ok(CellValue::Number(n.floor()))
295}
296
297fn fn_mod(args: &[CellValue]) -> Result<CellValue, String> {
298 let n = require_num!(&args[0]);
299 let d = require_num!(&args[1]);
300 if d == 0.0 { return Ok(CellValue::Error(CellError::Div0)); }
301 Ok(CellValue::Number(n - d * (n / d).floor()))
302}
303
304fn fn_power(args: &[CellValue]) -> Result<CellValue, String> {
305 let base = require_num!(&args[0]);
306 let exp = require_num!(&args[1]);
307 Ok(CellValue::Number(base.powf(exp)))
308}
309
310fn fn_sqrt(args: &[CellValue]) -> Result<CellValue, String> {
311 let n = require_num!(&args[0]);
312 if n < 0.0 { return Ok(CellValue::Error(CellError::Num)); }
313 Ok(CellValue::Number(n.sqrt()))
314}
315
316fn fn_sqrtpi(args: &[CellValue]) -> Result<CellValue, String> {
317 let n = require_num!(&args[0]);
318 Ok(CellValue::Number((n * std::f64::consts::PI).sqrt()))
319}
320
321fn fn_exp(args: &[CellValue]) -> Result<CellValue, String> {
322 Ok(CellValue::Number(require_num!(&args[0]).exp()))
323}
324
325fn fn_ln(args: &[CellValue]) -> Result<CellValue, String> {
326 let n = require_num!(&args[0]);
327 if n <= 0.0 { return Ok(CellValue::Error(CellError::Num)); }
328 Ok(CellValue::Number(n.ln()))
329}
330
331fn fn_log(args: &[CellValue]) -> Result<CellValue, String> {
332 let n = require_num!(&args[0]);
333 let base = if args.len() > 1 { require_num!(&args[1]) } else { 10.0 };
334 if n <= 0.0 || base <= 0.0 || base == 1.0 { return Ok(CellValue::Error(CellError::Num)); }
335 Ok(CellValue::Number(n.log(base)))
336}
337
338fn fn_log10(args: &[CellValue]) -> Result<CellValue, String> {
339 let n = require_num!(&args[0]);
340 if n <= 0.0 { return Ok(CellValue::Error(CellError::Num)); }
341 Ok(CellValue::Number(n.log10()))
342}
343
344fn fn_pi(_: &[CellValue]) -> Result<CellValue, String> {
345 Ok(CellValue::Number(std::f64::consts::PI))
346}
347
348fn fn_sin(args: &[CellValue]) -> Result<CellValue, String> {
349 Ok(CellValue::Number(require_num!(&args[0]).sin()))
350}
351fn fn_cos(args: &[CellValue]) -> Result<CellValue, String> {
352 Ok(CellValue::Number(require_num!(&args[0]).cos()))
353}
354fn fn_tan(args: &[CellValue]) -> Result<CellValue, String> {
355 Ok(CellValue::Number(require_num!(&args[0]).tan()))
356}
357fn fn_asin(args: &[CellValue]) -> Result<CellValue, String> {
358 Ok(CellValue::Number(require_num!(&args[0]).asin()))
359}
360fn fn_acos(args: &[CellValue]) -> Result<CellValue, String> {
361 Ok(CellValue::Number(require_num!(&args[0]).acos()))
362}
363fn fn_atan(args: &[CellValue]) -> Result<CellValue, String> {
364 Ok(CellValue::Number(require_num!(&args[0]).atan()))
365}
366fn fn_atan2(args: &[CellValue]) -> Result<CellValue, String> {
367 Ok(CellValue::Number(require_num!(&args[0]).atan2(require_num!(&args[1]))))
368}
369fn fn_degrees(args: &[CellValue]) -> Result<CellValue, String> {
370 Ok(CellValue::Number(require_num!(&args[0]).to_degrees()))
371}
372fn fn_radians(args: &[CellValue]) -> Result<CellValue, String> {
373 Ok(CellValue::Number(require_num!(&args[0]).to_radians()))
374}
375fn fn_sign(args: &[CellValue]) -> Result<CellValue, String> {
376 let n = require_num!(&args[0]);
377 Ok(CellValue::Number(if n > 0.0 { 1.0 } else if n < 0.0 { -1.0 } else { 0.0 }))
378}
379fn fn_rand(_: &[CellValue]) -> Result<CellValue, String> {
380 use std::time::{SystemTime, UNIX_EPOCH};
382 let ns = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().subsec_nanos();
383 Ok(CellValue::Number((ns as f64) / (u32::MAX as f64)))
384}
385fn fn_randbetween(args: &[CellValue]) -> Result<CellValue, String> {
386 let lo = require_num!(&args[0]);
387 let hi = require_num!(&args[1]);
388 let r = match fn_rand(&[])? { CellValue::Number(n) => n, _ => 0.5 };
389 Ok(CellValue::Number((lo + r * (hi - lo)).floor()))
390}
391fn fn_fact(args: &[CellValue]) -> Result<CellValue, String> {
392 let n = require_num!(&args[0]) as u64;
393 Ok(CellValue::Number((1..=n).product::<u64>() as f64))
394}
395fn fn_combin(args: &[CellValue]) -> Result<CellValue, String> {
396 let n = require_num!(&args[0]) as u64;
397 let k = require_num!(&args[1]) as u64;
398 if k > n { return Ok(CellValue::Number(0.0)); }
399 let num: u64 = ((n-k+1)..=n).product();
400 let den: u64 = (1..=k).product();
401 Ok(CellValue::Number((num / den) as f64))
402}
403fn fn_permut(args: &[CellValue]) -> Result<CellValue, String> {
404 let n = require_num!(&args[0]) as u64;
405 let k = require_num!(&args[1]) as u64;
406 Ok(CellValue::Number(((n-k+1)..=n).product::<u64>() as f64))
407}
408fn fn_gcd(args: &[CellValue]) -> Result<CellValue, String> {
409 fn gcd(a: u64, b: u64) -> u64 { if b == 0 { a } else { gcd(b, a % b) } }
410 let ns: Vec<u64> = args.iter().filter_map(|v| v.as_number().map(|n| n as u64)).collect();
411 Ok(CellValue::Number(ns.iter().copied().reduce(gcd).unwrap_or(0) as f64))
412}
413fn fn_lcm(args: &[CellValue]) -> Result<CellValue, String> {
414 fn gcd(a: u64, b: u64) -> u64 { if b == 0 { a } else { gcd(b, a % b) } }
415 fn lcm(a: u64, b: u64) -> u64 { a / gcd(a, b) * b }
416 let ns: Vec<u64> = args.iter().filter_map(|v| v.as_number().map(|n| n as u64)).collect();
417 Ok(CellValue::Number(ns.iter().copied().reduce(lcm).unwrap_or(0) as f64))
418}
419fn fn_even(args: &[CellValue]) -> Result<CellValue, String> {
420 let n = require_num!(&args[0]);
421 let r = if n >= 0.0 { (n / 2.0).ceil() * 2.0 } else { (n / 2.0).floor() * 2.0 };
422 Ok(CellValue::Number(r))
423}
424fn fn_odd(args: &[CellValue]) -> Result<CellValue, String> {
425 let n = require_num!(&args[0]);
426 let r = if n >= 0.0 { (n / 2.0).ceil() * 2.0 + 1.0 } else { (n / 2.0).floor() * 2.0 - 1.0 };
427 Ok(CellValue::Number(r))
428}
429fn fn_mround(args: &[CellValue]) -> Result<CellValue, String> {
430 let n = require_num!(&args[0]);
431 let m = require_num!(&args[1]);
432 if m == 0.0 { return Ok(CellValue::Number(0.0)); }
433 Ok(CellValue::Number((n / m).round() * m))
434}
435
436fn fn_average(args: &[CellValue]) -> Result<CellValue, String> {
439 let ns = nums_from_args(args);
440 if ns.is_empty() { return Ok(CellValue::Error(CellError::Div0)); }
441 Ok(CellValue::Number(ns.iter().sum::<f64>() / ns.len() as f64))
442}
443
444fn fn_averageif(args: &[CellValue]) -> Result<CellValue, String> {
445 fn_average(args) }
447
448fn fn_min(args: &[CellValue]) -> Result<CellValue, String> {
449 let ns = nums_from_args(args);
450 Ok(CellValue::Number(ns.iter().copied().fold(f64::INFINITY, f64::min)))
451}
452
453fn fn_max(args: &[CellValue]) -> Result<CellValue, String> {
454 let ns = nums_from_args(args);
455 Ok(CellValue::Number(ns.iter().copied().fold(f64::NEG_INFINITY, f64::max)))
456}
457
458fn fn_median(args: &[CellValue]) -> Result<CellValue, String> {
459 let mut ns = nums_from_args(args);
460 if ns.is_empty() { return Ok(CellValue::Error(CellError::NA)); }
461 ns.sort_by(f64::total_cmp);
462 let mid = ns.len() / 2;
463 let m = if ns.len() % 2 == 0 { (ns[mid - 1] + ns[mid]) / 2.0 } else { ns[mid] };
464 Ok(CellValue::Number(m))
465}
466
467fn fn_mode(args: &[CellValue]) -> Result<CellValue, String> {
468 let ns = nums_from_args(args);
469 let mut freq: HashMap<u64, (f64, usize)> = HashMap::new();
470 for n in &ns {
471 let key = n.to_bits();
472 let entry = freq.entry(key).or_insert((*n, 0));
473 entry.1 += 1;
474 }
475 freq.into_values().max_by_key(|(_, c)| *c).map(|(v, _)| CellValue::Number(v))
476 .ok_or_else(|| "No data".into())
477}
478
479fn fn_count(args: &[CellValue]) -> Result<CellValue, String> {
480 Ok(CellValue::Number(args.iter().filter(|v| v.is_number()).count() as f64))
481}
482
483fn fn_counta(args: &[CellValue]) -> Result<CellValue, String> {
484 Ok(CellValue::Number(args.iter().filter(|v| !v.is_empty()).count() as f64))
485}
486
487fn fn_countblank(args: &[CellValue]) -> Result<CellValue, String> {
488 Ok(CellValue::Number(args.iter().filter(|v| v.is_empty()).count() as f64))
489}
490
491fn fn_countif(args: &[CellValue]) -> Result<CellValue, String> {
492 if args.len() < 2 { return Err("COUNTIF requires 2 args".into()); }
493 let criteria = &args[1];
494 let count = args[..args.len()-1].iter().filter(|v| *v == criteria).count();
495 Ok(CellValue::Number(count as f64))
496}
497
498fn fn_countifs(args: &[CellValue]) -> Result<CellValue, String> {
499 fn_countif(args)
500}
501
502fn fn_stdev(args: &[CellValue]) -> Result<CellValue, String> {
503 let ns = nums_from_args(args);
504 if ns.len() < 2 { return Ok(CellValue::Error(CellError::Div0)); }
505 let mean = ns.iter().sum::<f64>() / ns.len() as f64;
506 let var = ns.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (ns.len() - 1) as f64;
507 Ok(CellValue::Number(var.sqrt()))
508}
509
510fn fn_stdevp(args: &[CellValue]) -> Result<CellValue, String> {
511 let ns = nums_from_args(args);
512 if ns.is_empty() { return Ok(CellValue::Error(CellError::Div0)); }
513 let mean = ns.iter().sum::<f64>() / ns.len() as f64;
514 let var = ns.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / ns.len() as f64;
515 Ok(CellValue::Number(var.sqrt()))
516}
517
518fn fn_var(args: &[CellValue]) -> Result<CellValue, String> {
519 let ns = nums_from_args(args);
520 if ns.len() < 2 { return Ok(CellValue::Error(CellError::Div0)); }
521 let mean = ns.iter().sum::<f64>() / ns.len() as f64;
522 Ok(CellValue::Number(ns.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (ns.len() - 1) as f64))
523}
524
525fn fn_varp(args: &[CellValue]) -> Result<CellValue, String> {
526 let ns = nums_from_args(args);
527 if ns.is_empty() { return Ok(CellValue::Error(CellError::Div0)); }
528 let mean = ns.iter().sum::<f64>() / ns.len() as f64;
529 Ok(CellValue::Number(ns.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / ns.len() as f64))
530}
531
532fn fn_large(args: &[CellValue]) -> Result<CellValue, String> {
533 let mut ns = nums_from_args(&args[..args.len()-1]);
534 let k = require_num!(args.last().unwrap()) as usize;
535 ns.sort_by(|a, b| b.total_cmp(a));
536 ns.get(k - 1).map(|n| CellValue::Number(*n)).ok_or_else(|| "Index out of range".into())
537}
538
539fn fn_small(args: &[CellValue]) -> Result<CellValue, String> {
540 let mut ns = nums_from_args(&args[..args.len()-1]);
541 let k = require_num!(args.last().unwrap()) as usize;
542 ns.sort_by(f64::total_cmp);
543 ns.get(k - 1).map(|n| CellValue::Number(*n)).ok_or_else(|| "Index out of range".into())
544}
545
546fn fn_rank(args: &[CellValue]) -> Result<CellValue, String> {
547 let n = require_num!(&args[0]);
548 let ns = nums_from_args(&args[1..]);
549 let rank = ns.iter().filter(|&&x| x > n).count() + 1;
550 Ok(CellValue::Number(rank as f64))
551}
552
553fn fn_percentile(args: &[CellValue]) -> Result<CellValue, String> {
554 let mut ns = nums_from_args(&args[..args.len()-1]);
555 let k = require_num!(args.last().unwrap());
556 ns.sort_by(f64::total_cmp);
557 let idx = k * (ns.len() - 1) as f64;
558 let lo = idx.floor() as usize;
559 let hi = idx.ceil() as usize;
560 let frac = idx - lo as f64;
561 let val = ns[lo] + frac * (ns.get(hi).copied().unwrap_or(ns[lo]) - ns[lo]);
562 Ok(CellValue::Number(val))
563}
564
565fn fn_quartile(args: &[CellValue]) -> Result<CellValue, String> {
566 let q = require_num!(args.last().unwrap());
567 fn_percentile(&[args[..args.len()-1].to_vec(), vec![CellValue::Number(q / 4.0)]].concat())
568}
569
570fn fn_correl(args: &[CellValue]) -> Result<CellValue, String> {
571 let n = args.len() / 2;
572 let xs = nums_from_args(&args[..n]);
573 let ys = nums_from_args(&args[n..]);
574 let mx = xs.iter().sum::<f64>() / n as f64;
575 let my = ys.iter().sum::<f64>() / n as f64;
576 let cov: f64 = xs.iter().zip(ys.iter()).map(|(x, y)| (x - mx) * (y - my)).sum();
577 let sx: f64 = xs.iter().map(|x| (x - mx).powi(2)).sum::<f64>().sqrt();
578 let sy: f64 = ys.iter().map(|y| (y - my).powi(2)).sum::<f64>().sqrt();
579 Ok(CellValue::Number(cov / (sx * sy)))
580}
581
582fn fn_covar(args: &[CellValue]) -> Result<CellValue, String> {
583 let n = args.len() / 2;
584 let xs = nums_from_args(&args[..n]);
585 let ys = nums_from_args(&args[n..]);
586 let mx = xs.iter().sum::<f64>() / n as f64;
587 let my = ys.iter().sum::<f64>() / n as f64;
588 let cov: f64 = xs.iter().zip(ys.iter()).map(|(x, y)| (x - mx) * (y - my)).sum::<f64>() / n as f64;
589 Ok(CellValue::Number(cov))
590}
591
592fn fn_slope(args: &[CellValue]) -> Result<CellValue, String> {
593 let n = args.len() / 2;
594 let ys = nums_from_args(&args[..n]);
595 let xs = nums_from_args(&args[n..]);
596 let mx = xs.iter().sum::<f64>() / n as f64;
597 let my = ys.iter().sum::<f64>() / n as f64;
598 let num: f64 = xs.iter().zip(ys.iter()).map(|(x, y)| (x - mx) * (y - my)).sum();
599 let den: f64 = xs.iter().map(|x| (x - mx).powi(2)).sum();
600 Ok(CellValue::Number(num / den))
601}
602
603fn fn_intercept(args: &[CellValue]) -> Result<CellValue, String> {
604 let n = args.len() / 2;
605 let ys = nums_from_args(&args[..n]);
606 let xs = nums_from_args(&args[n..]);
607 let mx = xs.iter().sum::<f64>() / n as f64;
608 let my = ys.iter().sum::<f64>() / n as f64;
609 let slope = match fn_slope(args)? { CellValue::Number(n) => n, _ => return Ok(CellValue::Error(CellError::Value)) };
610 Ok(CellValue::Number(my - slope * mx))
611}
612
613fn fn_len(args: &[CellValue]) -> Result<CellValue, String> {
616 Ok(CellValue::Number(require_text!(&args[0]).chars().count() as f64))
617}
618
619fn fn_left(args: &[CellValue]) -> Result<CellValue, String> {
620 let s = require_text!(&args[0]);
621 let n = if args.len() > 1 { require_num!(&args[1]) as usize } else { 1 };
622 Ok(CellValue::Text(s.chars().take(n).collect()))
623}
624
625fn fn_right(args: &[CellValue]) -> Result<CellValue, String> {
626 let s = require_text!(&args[0]);
627 let n = if args.len() > 1 { require_num!(&args[1]) as usize } else { 1 };
628 let chars: Vec<char> = s.chars().collect();
629 let start = chars.len().saturating_sub(n);
630 Ok(CellValue::Text(chars[start..].iter().collect()))
631}
632
633fn fn_mid(args: &[CellValue]) -> Result<CellValue, String> {
634 let s = require_text!(&args[0]);
635 let start = (require_num!(&args[1]) as usize).saturating_sub(1);
636 let len = require_num!(&args[2]) as usize;
637 Ok(CellValue::Text(s.chars().skip(start).take(len).collect()))
638}
639
640fn fn_upper(args: &[CellValue]) -> Result<CellValue, String> {
641 Ok(CellValue::Text(require_text!(&args[0]).to_uppercase()))
642}
643
644fn fn_lower(args: &[CellValue]) -> Result<CellValue, String> {
645 Ok(CellValue::Text(require_text!(&args[0]).to_lowercase()))
646}
647
648fn fn_proper(args: &[CellValue]) -> Result<CellValue, String> {
649 let s = require_text!(&args[0]);
650 let result = s.chars().enumerate().map(|(i, c)| {
651 if i == 0 || !s.chars().nth(i-1).map(|p| p.is_alphanumeric()).unwrap_or(false) {
652 c.to_uppercase().next().unwrap_or(c)
653 } else {
654 c.to_lowercase().next().unwrap_or(c)
655 }
656 }).collect();
657 Ok(CellValue::Text(result))
658}
659
660fn fn_trim(args: &[CellValue]) -> Result<CellValue, String> {
661 let s = require_text!(&args[0]);
662 let trimmed = s.split_whitespace().collect::<Vec<&str>>().join(" ");
664 Ok(CellValue::Text(trimmed))
665}
666
667fn fn_ltrim(args: &[CellValue]) -> Result<CellValue, String> {
668 Ok(CellValue::Text(require_text!(&args[0]).trim_start().to_string()))
669}
670
671fn fn_rtrim(args: &[CellValue]) -> Result<CellValue, String> {
672 Ok(CellValue::Text(require_text!(&args[0]).trim_end().to_string()))
673}
674
675fn fn_concatenate(args: &[CellValue]) -> Result<CellValue, String> {
676 Ok(CellValue::Text(args.iter().map(|v| v.as_text()).collect()))
677}
678
679fn fn_concat(args: &[CellValue]) -> Result<CellValue, String> {
680 fn_concatenate(args)
681}
682
683fn fn_textjoin(args: &[CellValue]) -> Result<CellValue, String> {
684 if args.len() < 3 { return Err("TEXTJOIN needs 3+ args".into()); }
685 let delim = require_text!(&args[0]);
686 let ignore_empty = to_bool(&args[1]);
687 let parts: Vec<String> = args[2..].iter()
688 .map(|v| v.as_text())
689 .filter(|s| !ignore_empty || !s.is_empty())
690 .collect();
691 Ok(CellValue::Text(parts.join(&delim)))
692}
693
694fn fn_replace(args: &[CellValue]) -> Result<CellValue, String> {
695 let s = require_text!(&args[0]);
696 let start = (require_num!(&args[1]) as usize).saturating_sub(1);
697 let num_chars = require_num!(&args[2]) as usize;
698 let new_text = require_text!(&args[3]);
699 let chars: Vec<char> = s.chars().collect();
700 let result: String = chars[..start.min(chars.len())].iter()
701 .chain(new_text.chars().collect::<Vec<_>>().iter())
702 .chain(chars[(start + num_chars).min(chars.len())..].iter())
703 .collect();
704 Ok(CellValue::Text(result))
705}
706
707fn fn_substitute(args: &[CellValue]) -> Result<CellValue, String> {
708 let text = require_text!(&args[0]);
709 let old = require_text!(&args[1]);
710 let new = require_text!(&args[2]);
711 let instance = if args.len() > 3 { Some(require_num!(&args[3]) as usize) } else { None };
712 match instance {
713 None => Ok(CellValue::Text(text.replace(old.as_str(), new.as_str()))),
714 Some(n) => {
715 let mut count = 0;
716 let result = text.split(old.as_str()).enumerate().map(|(i, part)| {
717 if i == 0 { part.to_string() }
718 else { count += 1; if count == n { format!("{}{}", new, part) } else { format!("{}{}", old, part) } }
719 }).collect();
720 Ok(CellValue::Text(result))
721 }
722 }
723}
724
725fn fn_find(args: &[CellValue]) -> Result<CellValue, String> {
726 let find = require_text!(&args[0]);
727 let within = require_text!(&args[1]);
728 let start = if args.len() > 2 { (require_num!(&args[2]) as usize).saturating_sub(1) } else { 0 };
729 within[start..].find(find.as_str())
730 .map(|pos| CellValue::Number((start + pos + 1) as f64))
731 .ok_or_else(|| "Not found".into())
732}
733
734fn fn_search(args: &[CellValue]) -> Result<CellValue, String> {
735 let find = require_text!(&args[0]).to_lowercase();
736 let within = require_text!(&args[1]).to_lowercase();
737 let start = if args.len() > 2 { (require_num!(&args[2]) as usize).saturating_sub(1) } else { 0 };
738 within[start..].find(find.as_str())
739 .map(|pos| CellValue::Number((start + pos + 1) as f64))
740 .ok_or_else(|| "Not found".into())
741}
742
743fn fn_text(args: &[CellValue]) -> Result<CellValue, String> {
744 let n = require_num!(&args[0]);
745 let fmt = require_text!(&args[1]);
746 let formatted = if fmt.contains('%') {
748 format!("{:.0}%", n * 100.0)
749 } else if fmt.contains('.') {
750 let places = fmt.chars().rev().take_while(|c| *c == '0').count();
751 format!("{:.prec$}", n, prec = places)
752 } else {
753 format!("{:.0}", n)
754 };
755 Ok(CellValue::Text(formatted))
756}
757
758fn fn_value(args: &[CellValue]) -> Result<CellValue, String> {
759 let s = require_text!(&args[0]);
760 s.trim().replace(',', "").parse::<f64>()
761 .map(CellValue::Number)
762 .map_err(|_| format!("Cannot convert '{}' to number", s))
763}
764
765fn fn_fixed(args: &[CellValue]) -> Result<CellValue, String> {
766 let n = require_num!(&args[0]);
767 let places = if args.len() > 1 { require_num!(&args[1]) as usize } else { 2 };
768 Ok(CellValue::Text(format!("{:.prec$}", n, prec = places)))
769}
770
771fn fn_rept(args: &[CellValue]) -> Result<CellValue, String> {
772 let s = require_text!(&args[0]);
773 let n = require_num!(&args[1]) as usize;
774 Ok(CellValue::Text(s.repeat(n)))
775}
776
777fn fn_code(args: &[CellValue]) -> Result<CellValue, String> {
778 let s = require_text!(&args[0]);
779 s.chars().next().map(|c| CellValue::Number(c as u32 as f64))
780 .ok_or_else(|| "Empty string".into())
781}
782
783fn fn_char(args: &[CellValue]) -> Result<CellValue, String> {
784 let n = require_num!(&args[0]) as u32;
785 char::from_u32(n).map(|c| CellValue::Text(c.to_string()))
786 .ok_or_else(|| "Invalid char code".into())
787}
788
789fn fn_exact(args: &[CellValue]) -> Result<CellValue, String> {
790 Ok(CellValue::Bool(require_text!(&args[0]) == require_text!(&args[1])))
791}
792
793fn fn_t(args: &[CellValue]) -> Result<CellValue, String> {
794 match &args[0] {
795 CellValue::Text(s) => Ok(CellValue::Text(s.clone())),
796 _ => Ok(CellValue::Text(String::new())),
797 }
798}
799
800fn fn_if(args: &[CellValue]) -> Result<CellValue, String> {
803 if args.len() < 2 { return Err("IF needs 2+ args".into()); }
804 if to_bool(&args[0]) {
805 Ok(args[1].clone())
806 } else {
807 Ok(args.get(2).cloned().unwrap_or(CellValue::Bool(false)))
808 }
809}
810
811fn fn_ifs(args: &[CellValue]) -> Result<CellValue, String> {
812 for chunk in args.chunks(2) {
813 if to_bool(&chunk[0]) {
814 return Ok(chunk.get(1).cloned().unwrap_or(CellValue::Empty));
815 }
816 }
817 Ok(CellValue::Error(CellError::NA))
818}
819
820fn fn_and(args: &[CellValue]) -> Result<CellValue, String> {
821 Ok(CellValue::Bool(args.iter().all(to_bool)))
822}
823
824fn fn_or(args: &[CellValue]) -> Result<CellValue, String> {
825 Ok(CellValue::Bool(args.iter().any(to_bool)))
826}
827
828fn fn_not(args: &[CellValue]) -> Result<CellValue, String> {
829 Ok(CellValue::Bool(!to_bool(&args[0])))
830}
831
832fn fn_xor(args: &[CellValue]) -> Result<CellValue, String> {
833 Ok(CellValue::Bool(args.iter().filter(|v| to_bool(v)).count() % 2 == 1))
834}
835
836fn fn_iferror(args: &[CellValue]) -> Result<CellValue, String> {
837 if args.len() < 2 { return Err("IFERROR needs 2 args".into()); }
838 if args[0].is_error() { Ok(args[1].clone()) } else { Ok(args[0].clone()) }
839}
840
841fn fn_ifna(args: &[CellValue]) -> Result<CellValue, String> {
842 if args.len() < 2 { return Err("IFNA needs 2 args".into()); }
843 if matches!(args[0], CellValue::Error(CellError::NA)) { Ok(args[1].clone()) } else { Ok(args[0].clone()) }
844}
845
846fn fn_switch(args: &[CellValue]) -> Result<CellValue, String> {
847 if args.len() < 3 { return Err("SWITCH needs 3+ args".into()); }
848 let expr = &args[0];
849 let pairs = &args[1..];
850 for chunk in pairs.chunks(2) {
851 if chunk.len() == 1 { return Ok(chunk[0].clone()); } if &chunk[0] == expr { return Ok(chunk[1].clone()); }
853 }
854 Ok(CellValue::Error(CellError::NA))
855}
856
857fn fn_true(_: &[CellValue]) -> Result<CellValue, String> { Ok(CellValue::Bool(true)) }
858fn fn_false(_: &[CellValue]) -> Result<CellValue, String> { Ok(CellValue::Bool(false)) }
859
860fn fn_vlookup(args: &[CellValue]) -> Result<CellValue, String> {
863 if args.len() < 3 { return Err("VLOOKUP needs 3+ args".into()); }
864 let lookup = &args[0];
865 let col_idx = require_num!(&args[2]) as usize;
866 let data = &args[1..args.len()-1];
868 for chunk in data.chunks(col_idx) {
869 if chunk.first() == Some(lookup) {
870 return Ok(chunk.get(col_idx - 1).cloned().unwrap_or(CellValue::Error(CellError::Ref)));
871 }
872 }
873 Ok(CellValue::Error(CellError::NA))
874}
875
876fn fn_hlookup(args: &[CellValue]) -> Result<CellValue, String> {
877 fn_vlookup(args) }
879
880fn fn_index(args: &[CellValue]) -> Result<CellValue, String> {
881 if args.len() < 3 { return Err("INDEX needs 3 args".into()); }
882 let row = require_num!(&args[1]) as usize;
883 let col = require_num!(&args[2]) as usize;
884 args.get(row.max(1) - 1).cloned().ok_or_else(|| "INDEX out of bounds".into())
886}
887
888fn fn_match(args: &[CellValue]) -> Result<CellValue, String> {
889 if args.len() < 2 { return Err("MATCH needs 2+ args".into()); }
890 let lookup = &args[0];
891 let data = &args[1..];
892 data.iter().position(|v| v == lookup)
893 .map(|i| CellValue::Number((i + 1) as f64))
894 .ok_or_else(|| "Not found".into())
895}
896
897fn fn_choose(args: &[CellValue]) -> Result<CellValue, String> {
898 let idx = require_num!(&args[0]) as usize;
899 args.get(idx).cloned().ok_or_else(|| "CHOOSE index out of range".into())
900}
901
902fn fn_offset(args: &[CellValue]) -> Result<CellValue, String> {
903 Ok(args.first().cloned().unwrap_or(CellValue::Empty))
905}
906
907fn fn_row(args: &[CellValue]) -> Result<CellValue, String> {
908 Ok(CellValue::Number(1.0)) }
910
911fn fn_column(args: &[CellValue]) -> Result<CellValue, String> {
912 Ok(CellValue::Number(1.0)) }
914
915fn fn_rows(args: &[CellValue]) -> Result<CellValue, String> {
916 Ok(CellValue::Number(args.len() as f64))
917}
918
919fn fn_columns(args: &[CellValue]) -> Result<CellValue, String> {
920 Ok(CellValue::Number(1.0)) }
922
923fn fn_transpose(args: &[CellValue]) -> Result<CellValue, String> {
924 Ok(args.first().cloned().unwrap_or(CellValue::Empty))
925}
926
927fn fn_now(_: &[CellValue]) -> Result<CellValue, String> {
930 Ok(CellValue::Text(chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string()))
931}
932
933fn fn_today(_: &[CellValue]) -> Result<CellValue, String> {
934 Ok(CellValue::Text(chrono::Utc::now().format("%Y-%m-%d").to_string()))
935}
936
937fn fn_date(args: &[CellValue]) -> Result<CellValue, String> {
938 let y = require_num!(&args[0]) as i32;
939 let m = require_num!(&args[1]) as u32;
940 let d = require_num!(&args[2]) as u32;
941 use chrono::NaiveDate;
942 NaiveDate::from_ymd_opt(y, m, d)
943 .map(|dt| CellValue::Date(dt))
944 .ok_or_else(|| "Invalid date".into())
945}
946
947fn fn_time(args: &[CellValue]) -> Result<CellValue, String> {
948 let h = require_num!(&args[0]);
949 let m = require_num!(&args[1]);
950 let s = require_num!(&args[2]);
951 Ok(CellValue::Number((h * 3600.0 + m * 60.0 + s) / 86400.0))
952}
953
954fn extract_date(v: &CellValue) -> Option<chrono::NaiveDate> {
955 match v {
956 CellValue::Date(d) => Some(*d),
957 CellValue::Text(s) => s.parse().ok(),
958 _ => None,
959 }
960}
961
962fn fn_year(args: &[CellValue]) -> Result<CellValue, String> {
963 use chrono::Datelike;
964 extract_date(&args[0]).map(|d| CellValue::Number(d.year() as f64))
965 .ok_or_else(|| "Invalid date".into())
966}
967fn fn_month(args: &[CellValue]) -> Result<CellValue, String> {
968 use chrono::Datelike;
969 extract_date(&args[0]).map(|d| CellValue::Number(d.month() as f64))
970 .ok_or_else(|| "Invalid date".into())
971}
972fn fn_day(args: &[CellValue]) -> Result<CellValue, String> {
973 use chrono::Datelike;
974 extract_date(&args[0]).map(|d| CellValue::Number(d.day() as f64))
975 .ok_or_else(|| "Invalid date".into())
976}
977fn fn_hour(args: &[CellValue]) -> Result<CellValue, String> {
978 Ok(CellValue::Number(0.0)) }
980fn fn_minute(args: &[CellValue]) -> Result<CellValue, String> {
981 Ok(CellValue::Number(0.0))
982}
983fn fn_second(args: &[CellValue]) -> Result<CellValue, String> {
984 Ok(CellValue::Number(0.0))
985}
986fn fn_weekday(args: &[CellValue]) -> Result<CellValue, String> {
987 use chrono::Datelike;
988 extract_date(&args[0]).map(|d| CellValue::Number(d.weekday().num_days_from_sunday() as f64 + 1.0))
989 .ok_or_else(|| "Invalid date".into())
990}
991fn fn_weeknum(args: &[CellValue]) -> Result<CellValue, String> {
992 use chrono::Datelike;
993 extract_date(&args[0]).map(|d| CellValue::Number(d.iso_week().week() as f64))
994 .ok_or_else(|| "Invalid date".into())
995}
996fn fn_edate(args: &[CellValue]) -> Result<CellValue, String> {
997 use chrono::Datelike;
998 let d = extract_date(&args[0]).ok_or_else(|| "Invalid date".to_string())?;
999 let months = require_num!(&args[1]) as i32;
1000 let new_month = d.month() as i32 + months;
1001 let year_add = (new_month - 1) / 12;
1002 let month = ((new_month - 1) % 12 + 12) % 12 + 1;
1003 let new_date = chrono::NaiveDate::from_ymd_opt(d.year() + year_add, month as u32, d.day())
1004 .ok_or_else(|| "Invalid date result".to_string())?;
1005 Ok(CellValue::Date(new_date))
1006}
1007fn fn_eomonth(args: &[CellValue]) -> Result<CellValue, String> {
1008 use chrono::Datelike;
1009 let d = extract_date(&args[0]).ok_or_else(|| "Invalid date".to_string())?;
1010 let months = require_num!(&args[1]) as i32;
1011 let new_month = d.month() as i32 + months + 1;
1012 let year_add = (new_month - 1) / 12;
1013 let month = ((new_month - 1) % 12 + 12) % 12 + 1;
1014 let first_next = chrono::NaiveDate::from_ymd_opt(d.year() + year_add, month as u32, 1).unwrap();
1015 let last = first_next - chrono::Duration::days(1);
1016 Ok(CellValue::Date(last))
1017}
1018fn fn_networkdays(args: &[CellValue]) -> Result<CellValue, String> {
1019 Ok(CellValue::Number(0.0)) }
1021fn fn_workday(args: &[CellValue]) -> Result<CellValue, String> {
1022 Ok(args[0].clone()) }
1024fn fn_datedif(args: &[CellValue]) -> Result<CellValue, String> {
1025 let start = extract_date(&args[0]).ok_or_else(|| "Invalid start date".to_string())?;
1026 let end = extract_date(&args[1]).ok_or_else(|| "Invalid end date".to_string())?;
1027 let unit = require_text!(&args[2]).to_uppercase();
1028 let diff = (end - start).num_days();
1029 match unit.as_str() {
1030 "D" => Ok(CellValue::Number(diff as f64)),
1031 "M" => {
1032 use chrono::Datelike;
1033 let months = (end.year() - start.year()) * 12 + (end.month() as i32 - start.month() as i32);
1034 Ok(CellValue::Number(months as f64))
1035 }
1036 "Y" => {
1037 use chrono::Datelike;
1038 Ok(CellValue::Number((end.year() - start.year()) as f64))
1039 }
1040 _ => Ok(CellValue::Number(diff as f64)),
1041 }
1042}
1043fn fn_datevalue(args: &[CellValue]) -> Result<CellValue, String> {
1044 let s = require_text!(&args[0]);
1045 s.parse::<chrono::NaiveDate>()
1046 .map(|d| CellValue::Date(d))
1047 .map_err(|_| format!("Cannot parse date: {}", s))
1048}
1049fn fn_timevalue(args: &[CellValue]) -> Result<CellValue, String> {
1050 Ok(CellValue::Number(0.0)) }
1052
1053fn fn_isnumber(args: &[CellValue]) -> Result<CellValue, String> {
1056 Ok(CellValue::Bool(args[0].is_number()))
1057}
1058fn fn_istext(args: &[CellValue]) -> Result<CellValue, String> {
1059 Ok(CellValue::Bool(args[0].is_text()))
1060}
1061fn fn_isblank(args: &[CellValue]) -> Result<CellValue, String> {
1062 Ok(CellValue::Bool(args[0].is_empty()))
1063}
1064fn fn_iserror(args: &[CellValue]) -> Result<CellValue, String> {
1065 Ok(CellValue::Bool(args[0].is_error()))
1066}
1067fn fn_iserr(args: &[CellValue]) -> Result<CellValue, String> {
1068 Ok(CellValue::Bool(matches!(&args[0], CellValue::Error(e) if !matches!(e, CellError::NA))))
1069}
1070fn fn_isna(args: &[CellValue]) -> Result<CellValue, String> {
1071 Ok(CellValue::Bool(matches!(&args[0], CellValue::Error(CellError::NA))))
1072}
1073fn fn_islogical(args: &[CellValue]) -> Result<CellValue, String> {
1074 Ok(CellValue::Bool(matches!(args[0], CellValue::Bool(_))))
1075}
1076fn fn_isodd(args: &[CellValue]) -> Result<CellValue, String> {
1077 let n = require_num!(&args[0]) as i64;
1078 Ok(CellValue::Bool(n % 2 != 0))
1079}
1080fn fn_iseven(args: &[CellValue]) -> Result<CellValue, String> {
1081 let n = require_num!(&args[0]) as i64;
1082 Ok(CellValue::Bool(n % 2 == 0))
1083}
1084fn fn_na(_: &[CellValue]) -> Result<CellValue, String> {
1085 Ok(CellValue::Error(CellError::NA))
1086}
1087fn fn_error_type(args: &[CellValue]) -> Result<CellValue, String> {
1088 match &args[0] {
1089 CellValue::Error(e) => Ok(CellValue::Number(match e {
1090 CellError::Null => 1.0, CellError::Div0 => 2.0, CellError::Value => 3.0,
1091 CellError::Ref => 4.0, CellError::Name => 5.0, CellError::Num => 6.0,
1092 CellError::NA => 7.0, _ => 8.0,
1093 })),
1094 _ => Ok(CellValue::Error(CellError::NA)),
1095 }
1096}
1097fn fn_cell(_: &[CellValue]) -> Result<CellValue, String> { Ok(CellValue::Text(String::new())) }
1098fn fn_type(args: &[CellValue]) -> Result<CellValue, String> {
1099 Ok(CellValue::Number(match &args[0] {
1100 CellValue::Number(_) => 1.0,
1101 CellValue::Text(_) => 2.0,
1102 CellValue::Bool(_) => 4.0,
1103 CellValue::Error(_) => 16.0,
1104 CellValue::Empty => 1.0,
1105 _ => 1.0,
1106 }))
1107}
1108fn fn_n(args: &[CellValue]) -> Result<CellValue, String> {
1109 Ok(CellValue::Number(args[0].as_number().unwrap_or(0.0)))
1110}
1111
1112fn fn_pmt(args: &[CellValue]) -> Result<CellValue, String> {
1115 let rate = require_num!(&args[0]);
1116 let nper = require_num!(&args[1]);
1117 let pv = require_num!(&args[2]);
1118 let fv = if args.len() > 3 { require_num!(&args[3]) } else { 0.0 };
1119 let type_ = if args.len() > 4 { require_num!(&args[4]) } else { 0.0 };
1120 let pmt = if rate == 0.0 {
1121 -(pv + fv) / nper
1122 } else {
1123 let factor = (1.0 + rate).powf(nper);
1124 -(pv * factor * rate + fv * rate) / ((factor - 1.0) * (1.0 + rate * type_))
1125 };
1126 Ok(CellValue::Number(pmt))
1127}
1128
1129fn fn_pv(args: &[CellValue]) -> Result<CellValue, String> {
1130 let rate = require_num!(&args[0]);
1131 let nper = require_num!(&args[1]);
1132 let pmt = require_num!(&args[2]);
1133 let fv = if args.len() > 3 { require_num!(&args[3]) } else { 0.0 };
1134 let pv = if rate == 0.0 {
1135 -(pmt * nper + fv)
1136 } else {
1137 let factor = (1.0 + rate).powf(nper);
1138 -(pmt * (factor - 1.0) / rate + fv) / factor
1139 };
1140 Ok(CellValue::Number(pv))
1141}
1142
1143fn fn_fv(args: &[CellValue]) -> Result<CellValue, String> {
1144 let rate = require_num!(&args[0]);
1145 let nper = require_num!(&args[1]);
1146 let pmt = require_num!(&args[2]);
1147 let pv = if args.len() > 3 { require_num!(&args[3]) } else { 0.0 };
1148 let fv = if rate == 0.0 {
1149 -(pmt * nper + pv)
1150 } else {
1151 let factor = (1.0 + rate).powf(nper);
1152 -(pmt * (factor - 1.0) / rate + pv * factor)
1153 };
1154 Ok(CellValue::Number(fv))
1155}
1156
1157fn fn_rate(args: &[CellValue]) -> Result<CellValue, String> {
1158 let nper = require_num!(&args[0]);
1160 let pmt = require_num!(&args[1]);
1161 let pv = require_num!(&args[2]);
1162 let mut rate = 0.1;
1163 for _ in 0..1000 {
1164 let f = pv * (1.0_f64 + rate).powf(nper) + pmt * ((1.0_f64 + rate).powf(nper) - 1.0) / rate;
1165 let df = pv * nper * (1.0_f64 + rate).powf(nper - 1.0) +
1166 pmt * (nper * (1.0_f64 + rate).powf(nper - 1.0) * rate - ((1.0_f64 + rate).powf(nper) - 1.0)) / (rate * rate);
1167 let new_rate = rate - f / df;
1168 if (new_rate - rate).abs() < 1e-10 { return Ok(CellValue::Number(new_rate)); }
1169 rate = new_rate;
1170 }
1171 Ok(CellValue::Number(rate))
1172}
1173
1174fn fn_nper(args: &[CellValue]) -> Result<CellValue, String> {
1175 let rate = require_num!(&args[0]);
1176 let pmt = require_num!(&args[1]);
1177 let pv = require_num!(&args[2]);
1178 if rate == 0.0 { return Ok(CellValue::Number(-pv / pmt)); }
1179 let nper = ((pmt / rate) / (pmt / rate + pv)).log(1.0 + rate);
1180 Ok(CellValue::Number(nper))
1181}
1182
1183fn fn_npv(args: &[CellValue]) -> Result<CellValue, String> {
1184 let rate = require_num!(&args[0]);
1185 let npv: f64 = args[1..].iter()
1186 .enumerate()
1187 .filter_map(|(i, v)| v.as_number().map(|n| n / (1.0 + rate).powi(i as i32 + 1)))
1188 .sum();
1189 Ok(CellValue::Number(npv))
1190}
1191
1192fn fn_irr(args: &[CellValue]) -> Result<CellValue, String> {
1193 if args.is_empty() { return Err("IRR needs cash flows".into()); }
1194 let flows: Vec<f64> = args.iter().filter_map(|v| v.as_number()).collect();
1195 let mut rate = 0.1;
1196 for _ in 0..1000 {
1197 let npv: f64 = flows.iter().enumerate()
1198 .map(|(i, cf)| cf / (1.0_f64 + rate).powi(i as i32))
1199 .sum();
1200 let d_npv: f64 = flows.iter().enumerate()
1201 .map(|(i, cf)| -(i as f64) * cf / (1.0_f64 + rate).powi(i as i32 + 1))
1202 .sum();
1203 if d_npv.abs() < 1e-15 { break; }
1204 let new_rate = rate - npv / d_npv;
1205 if (new_rate - rate).abs() < 1e-10 { return Ok(CellValue::Number(new_rate)); }
1206 rate = new_rate;
1207 }
1208 Ok(CellValue::Number(rate))
1209}
1210
1211fn fn_ipmt(args: &[CellValue]) -> Result<CellValue, String> {
1212 let rate = require_num!(&args[0]);
1213 let per = require_num!(&args[1]);
1214 let nper = require_num!(&args[2]);
1215 let pv = require_num!(&args[3]);
1216 let pmt_val = match fn_pmt(&[CellValue::Number(rate), CellValue::Number(nper), CellValue::Number(pv)])? {
1217 CellValue::Number(n) => n,
1218 _ => return Ok(CellValue::Error(CellError::Value)),
1219 };
1220 let ipmt = -(pv * (1.0_f64 + rate).powf(per - 1.0) * rate + pmt_val * ((1.0_f64 + rate).powf(per - 1.0) - 1.0));
1221 Ok(CellValue::Number(ipmt))
1222}
1223
1224fn fn_ppmt(args: &[CellValue]) -> Result<CellValue, String> {
1225 let pmt_val = match fn_pmt(&args[..4])? { CellValue::Number(n) => n, _ => return Ok(CellValue::Error(CellError::Value)) };
1226 let ipmt_val = match fn_ipmt(args)? { CellValue::Number(n) => n, _ => return Ok(CellValue::Error(CellError::Value)) };
1227 Ok(CellValue::Number(pmt_val - ipmt_val))
1228}