1use std::rc::Rc;
20
21use crate::common::{
22 ArgumentType, Context, ErrorReason, Function, JmespathError, Rcvar, Runtime, Variable,
23};
24use crate::define_function;
25
26pub fn register(runtime: &mut Runtime) {
28 runtime.register_function("round", Box::new(RoundFn::new()));
29 runtime.register_function("floor_fn", Box::new(FloorFn::new()));
30 runtime.register_function("ceil_fn", Box::new(CeilFn::new()));
31 runtime.register_function("abs_fn", Box::new(AbsFn::new()));
32 runtime.register_function("mod_fn", Box::new(ModFn::new()));
33 runtime.register_function("pow", Box::new(PowFn::new()));
34 runtime.register_function("sqrt", Box::new(SqrtFn::new()));
35 runtime.register_function("log", Box::new(LogFn::new()));
36 runtime.register_function("clamp", Box::new(ClampFn::new()));
37 runtime.register_function("median", Box::new(MedianFn::new()));
38 runtime.register_function("percentile", Box::new(PercentileFn::new()));
39 runtime.register_function("variance", Box::new(VarianceFn::new()));
40 runtime.register_function("stddev", Box::new(StddevFn::new()));
41 runtime.register_function("sin", Box::new(SinFn::new()));
42 runtime.register_function("cos", Box::new(CosFn::new()));
43 runtime.register_function("tan", Box::new(TanFn::new()));
44 runtime.register_function("asin", Box::new(AsinFn::new()));
45 runtime.register_function("acos", Box::new(AcosFn::new()));
46 runtime.register_function("atan", Box::new(AtanFn::new()));
47 runtime.register_function("atan2", Box::new(Atan2Fn::new()));
48 runtime.register_function("deg_to_rad", Box::new(DegToRadFn::new()));
49 runtime.register_function("rad_to_deg", Box::new(RadToDegFn::new()));
50 runtime.register_function("sign", Box::new(SignFn::new()));
51 runtime.register_function("add", Box::new(AddFn::new()));
52 runtime.register_function("subtract", Box::new(SubtractFn::new()));
53 runtime.register_function("multiply", Box::new(MultiplyFn::new()));
54 runtime.register_function("divide", Box::new(DivideFn::new()));
55 runtime.register_function("mode", Box::new(ModeFn::new()));
56 runtime.register_function("to_fixed", Box::new(ToFixedFn::new()));
57 runtime.register_function("format_number", Box::new(FormatNumberFn::new()));
58 runtime.register_function("histogram", Box::new(HistogramFn::new()));
59 runtime.register_function("normalize", Box::new(NormalizeFn::new()));
60 runtime.register_function("z_score", Box::new(ZScoreFn::new()));
61 runtime.register_function("correlation", Box::new(CorrelationFn::new()));
62 runtime.register_function("quantile", Box::new(QuantileFn::new()));
63 runtime.register_function("moving_avg", Box::new(MovingAvgFn::new()));
64 runtime.register_function("ewma", Box::new(EwmaFn::new()));
65 runtime.register_function("covariance", Box::new(CovarianceFn::new()));
66 runtime.register_function("standardize", Box::new(StandardizeFn::new()));
67}
68
69define_function!(
74 RoundFn,
75 vec![ArgumentType::Number],
76 Some(ArgumentType::Number)
77);
78
79impl Function for RoundFn {
80 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
81 self.signature.validate(args, ctx)?;
82
83 let n = args[0].as_number().ok_or_else(|| {
84 JmespathError::new(
85 ctx.expression,
86 0,
87 ErrorReason::Parse("Expected number argument".to_owned()),
88 )
89 })?;
90
91 let precision = if args.len() > 1 {
92 args[1].as_number().map(|p| p as i32).unwrap_or(0)
93 } else {
94 0
95 };
96
97 let result = if precision == 0 {
98 n.round()
99 } else {
100 let multiplier = 10_f64.powi(precision);
101 (n * multiplier).round() / multiplier
102 };
103
104 Ok(Rc::new(Variable::Number(
105 serde_json::Number::from_f64(result).unwrap_or_else(|| serde_json::Number::from(0)),
106 )))
107 }
108}
109
110define_function!(FloorFn, vec![ArgumentType::Number], None);
115
116impl Function for FloorFn {
117 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
118 self.signature.validate(args, ctx)?;
119
120 let n = args[0].as_number().ok_or_else(|| {
121 JmespathError::new(
122 ctx.expression,
123 0,
124 ErrorReason::Parse("Expected number argument".to_owned()),
125 )
126 })?;
127
128 Ok(Rc::new(Variable::Number(serde_json::Number::from(
129 n.floor() as i64,
130 ))))
131 }
132}
133
134define_function!(CeilFn, vec![ArgumentType::Number], None);
139
140impl Function for CeilFn {
141 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
142 self.signature.validate(args, ctx)?;
143
144 let n = args[0].as_number().ok_or_else(|| {
145 JmespathError::new(
146 ctx.expression,
147 0,
148 ErrorReason::Parse("Expected number argument".to_owned()),
149 )
150 })?;
151
152 Ok(Rc::new(Variable::Number(serde_json::Number::from(
153 n.ceil() as i64,
154 ))))
155 }
156}
157
158define_function!(AbsFn, vec![ArgumentType::Number], None);
163
164impl Function for AbsFn {
165 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
166 self.signature.validate(args, ctx)?;
167
168 let n = args[0].as_number().ok_or_else(|| {
169 JmespathError::new(
170 ctx.expression,
171 0,
172 ErrorReason::Parse("Expected number argument".to_owned()),
173 )
174 })?;
175
176 Ok(Rc::new(Variable::Number(
177 serde_json::Number::from_f64(n.abs()).unwrap_or_else(|| serde_json::Number::from(0)),
178 )))
179 }
180}
181
182define_function!(
187 ModFn,
188 vec![ArgumentType::Number, ArgumentType::Number],
189 None
190);
191
192impl Function for ModFn {
193 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
194 self.signature.validate(args, ctx)?;
195
196 let n = args[0].as_number().ok_or_else(|| {
197 JmespathError::new(
198 ctx.expression,
199 0,
200 ErrorReason::Parse("Expected number argument".to_owned()),
201 )
202 })?;
203
204 let divisor = args[1].as_number().ok_or_else(|| {
205 JmespathError::new(
206 ctx.expression,
207 0,
208 ErrorReason::Parse("Expected divisor argument".to_owned()),
209 )
210 })?;
211
212 if divisor == 0.0 {
213 return Err(JmespathError::new(
214 ctx.expression,
215 0,
216 ErrorReason::Parse("Division by zero".to_owned()),
217 ));
218 }
219
220 Ok(Rc::new(Variable::Number(
221 serde_json::Number::from_f64(n % divisor)
222 .unwrap_or_else(|| serde_json::Number::from(0)),
223 )))
224 }
225}
226
227define_function!(
232 PowFn,
233 vec![ArgumentType::Number, ArgumentType::Number],
234 None
235);
236
237impl Function for PowFn {
238 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
239 self.signature.validate(args, ctx)?;
240
241 let base = args[0].as_number().ok_or_else(|| {
242 JmespathError::new(
243 ctx.expression,
244 0,
245 ErrorReason::Parse("Expected base number".to_owned()),
246 )
247 })?;
248
249 let exp = args[1].as_number().ok_or_else(|| {
250 JmespathError::new(
251 ctx.expression,
252 0,
253 ErrorReason::Parse("Expected exponent number".to_owned()),
254 )
255 })?;
256
257 Ok(Rc::new(Variable::Number(
258 serde_json::Number::from_f64(base.powf(exp))
259 .unwrap_or_else(|| serde_json::Number::from(0)),
260 )))
261 }
262}
263
264define_function!(SqrtFn, vec![ArgumentType::Number], None);
269
270impl Function for SqrtFn {
271 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
272 self.signature.validate(args, ctx)?;
273
274 let n = args[0].as_number().ok_or_else(|| {
275 JmespathError::new(
276 ctx.expression,
277 0,
278 ErrorReason::Parse("Expected number argument".to_owned()),
279 )
280 })?;
281
282 if n < 0.0 {
283 return Err(JmespathError::new(
284 ctx.expression,
285 0,
286 ErrorReason::Parse("Cannot take square root of negative number".to_owned()),
287 ));
288 }
289
290 Ok(Rc::new(Variable::Number(
291 serde_json::Number::from_f64(n.sqrt()).unwrap_or_else(|| serde_json::Number::from(0)),
292 )))
293 }
294}
295
296define_function!(
301 LogFn,
302 vec![ArgumentType::Number],
303 Some(ArgumentType::Number)
304);
305
306impl Function for LogFn {
307 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
308 self.signature.validate(args, ctx)?;
309
310 let n = args[0].as_number().ok_or_else(|| {
311 JmespathError::new(
312 ctx.expression,
313 0,
314 ErrorReason::Parse("Expected number argument".to_owned()),
315 )
316 })?;
317
318 if n <= 0.0 {
319 return Err(JmespathError::new(
320 ctx.expression,
321 0,
322 ErrorReason::Parse("Logarithm requires positive number".to_owned()),
323 ));
324 }
325
326 let result = if args.len() > 1 {
327 let base = args[1].as_number().ok_or_else(|| {
328 JmespathError::new(
329 ctx.expression,
330 0,
331 ErrorReason::Parse("Expected base number".to_owned()),
332 )
333 })?;
334 n.log(base)
335 } else {
336 n.ln()
337 };
338
339 Ok(Rc::new(Variable::Number(
340 serde_json::Number::from_f64(result).unwrap_or_else(|| serde_json::Number::from(0)),
341 )))
342 }
343}
344
345define_function!(
350 ClampFn,
351 vec![
352 ArgumentType::Number,
353 ArgumentType::Number,
354 ArgumentType::Number
355 ],
356 None
357);
358
359impl Function for ClampFn {
360 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
361 self.signature.validate(args, ctx)?;
362
363 let n = args[0].as_number().ok_or_else(|| {
364 JmespathError::new(
365 ctx.expression,
366 0,
367 ErrorReason::Parse("Expected number argument".to_owned()),
368 )
369 })?;
370
371 let min = args[1].as_number().ok_or_else(|| {
372 JmespathError::new(
373 ctx.expression,
374 0,
375 ErrorReason::Parse("Expected min number".to_owned()),
376 )
377 })?;
378
379 let max = args[2].as_number().ok_or_else(|| {
380 JmespathError::new(
381 ctx.expression,
382 0,
383 ErrorReason::Parse("Expected max number".to_owned()),
384 )
385 })?;
386
387 let result = n.max(min).min(max);
388
389 Ok(Rc::new(Variable::Number(
390 serde_json::Number::from_f64(result).unwrap_or_else(|| serde_json::Number::from(0)),
391 )))
392 }
393}
394
395define_function!(MedianFn, vec![ArgumentType::Array], None);
400
401impl Function for MedianFn {
402 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
403 self.signature.validate(args, ctx)?;
404
405 let arr = args[0].as_array().ok_or_else(|| {
406 JmespathError::new(
407 ctx.expression,
408 0,
409 ErrorReason::Parse("Expected array argument".to_owned()),
410 )
411 })?;
412
413 let mut numbers: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
414
415 if numbers.is_empty() {
416 return Ok(Rc::new(Variable::Null));
417 }
418
419 numbers.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
420
421 let len = numbers.len();
422 let median = if len % 2 == 0 {
423 (numbers[len / 2 - 1] + numbers[len / 2]) / 2.0
424 } else {
425 numbers[len / 2]
426 };
427
428 Ok(Rc::new(Variable::Number(
429 serde_json::Number::from_f64(median).unwrap_or_else(|| serde_json::Number::from(0)),
430 )))
431 }
432}
433
434define_function!(
439 PercentileFn,
440 vec![ArgumentType::Array, ArgumentType::Number],
441 None
442);
443
444impl Function for PercentileFn {
445 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
446 self.signature.validate(args, ctx)?;
447
448 let arr = args[0].as_array().ok_or_else(|| {
449 JmespathError::new(
450 ctx.expression,
451 0,
452 ErrorReason::Parse("Expected array argument".to_owned()),
453 )
454 })?;
455
456 let p = args[1].as_number().ok_or_else(|| {
457 JmespathError::new(
458 ctx.expression,
459 0,
460 ErrorReason::Parse("Expected percentile value".to_owned()),
461 )
462 })?;
463
464 if !(0.0..=100.0).contains(&p) {
465 return Err(JmespathError::new(
466 ctx.expression,
467 0,
468 ErrorReason::Parse("Percentile must be between 0 and 100".to_owned()),
469 ));
470 }
471
472 let mut numbers: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
473
474 if numbers.is_empty() {
475 return Ok(Rc::new(Variable::Null));
476 }
477
478 numbers.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
479
480 let len = numbers.len();
481 if len == 1 {
482 return Ok(Rc::new(Variable::Number(
483 serde_json::Number::from_f64(numbers[0])
484 .unwrap_or_else(|| serde_json::Number::from(0)),
485 )));
486 }
487
488 let rank = (p / 100.0) * (len - 1) as f64;
489 let lower_idx = rank.floor() as usize;
490 let upper_idx = rank.ceil() as usize;
491 let fraction = rank - lower_idx as f64;
492
493 let result = if lower_idx == upper_idx {
494 numbers[lower_idx]
495 } else {
496 numbers[lower_idx] * (1.0 - fraction) + numbers[upper_idx] * fraction
497 };
498
499 Ok(Rc::new(Variable::Number(
500 serde_json::Number::from_f64(result).unwrap_or_else(|| serde_json::Number::from(0)),
501 )))
502 }
503}
504
505define_function!(VarianceFn, vec![ArgumentType::Array], None);
510
511impl Function for VarianceFn {
512 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
513 self.signature.validate(args, ctx)?;
514
515 let arr = args[0].as_array().ok_or_else(|| {
516 JmespathError::new(
517 ctx.expression,
518 0,
519 ErrorReason::Parse("Expected array argument".to_owned()),
520 )
521 })?;
522
523 let numbers: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
524
525 if numbers.is_empty() {
526 return Ok(Rc::new(Variable::Null));
527 }
528
529 let mean = numbers.iter().sum::<f64>() / numbers.len() as f64;
530 let variance =
531 numbers.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / numbers.len() as f64;
532
533 Ok(Rc::new(Variable::Number(
534 serde_json::Number::from_f64(variance).unwrap_or_else(|| serde_json::Number::from(0)),
535 )))
536 }
537}
538
539define_function!(StddevFn, vec![ArgumentType::Array], None);
544
545impl Function for StddevFn {
546 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
547 self.signature.validate(args, ctx)?;
548
549 let arr = args[0].as_array().ok_or_else(|| {
550 JmespathError::new(
551 ctx.expression,
552 0,
553 ErrorReason::Parse("Expected array argument".to_owned()),
554 )
555 })?;
556
557 let numbers: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
558
559 if numbers.is_empty() {
560 return Ok(Rc::new(Variable::Null));
561 }
562
563 let mean = numbers.iter().sum::<f64>() / numbers.len() as f64;
564 let variance =
565 numbers.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / numbers.len() as f64;
566 let stddev = variance.sqrt();
567
568 Ok(Rc::new(Variable::Number(
569 serde_json::Number::from_f64(stddev).unwrap_or_else(|| serde_json::Number::from(0)),
570 )))
571 }
572}
573
574define_function!(SinFn, vec![ArgumentType::Number], None);
579
580impl Function for SinFn {
581 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
582 self.signature.validate(args, ctx)?;
583 let n = args[0].as_number().ok_or_else(|| {
584 JmespathError::new(
585 ctx.expression,
586 0,
587 ErrorReason::Parse("Expected number".to_owned()),
588 )
589 })?;
590 Ok(Rc::new(Variable::Number(
591 serde_json::Number::from_f64(n.sin()).unwrap_or_else(|| serde_json::Number::from(0)),
592 )))
593 }
594}
595
596define_function!(CosFn, vec![ArgumentType::Number], None);
597
598impl Function for CosFn {
599 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
600 self.signature.validate(args, ctx)?;
601 let n = args[0].as_number().ok_or_else(|| {
602 JmespathError::new(
603 ctx.expression,
604 0,
605 ErrorReason::Parse("Expected number".to_owned()),
606 )
607 })?;
608 Ok(Rc::new(Variable::Number(
609 serde_json::Number::from_f64(n.cos()).unwrap_or_else(|| serde_json::Number::from(0)),
610 )))
611 }
612}
613
614define_function!(TanFn, vec![ArgumentType::Number], None);
615
616impl Function for TanFn {
617 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
618 self.signature.validate(args, ctx)?;
619 let n = args[0].as_number().ok_or_else(|| {
620 JmespathError::new(
621 ctx.expression,
622 0,
623 ErrorReason::Parse("Expected number".to_owned()),
624 )
625 })?;
626 Ok(Rc::new(Variable::Number(
627 serde_json::Number::from_f64(n.tan()).unwrap_or_else(|| serde_json::Number::from(0)),
628 )))
629 }
630}
631
632define_function!(AsinFn, vec![ArgumentType::Number], None);
633
634impl Function for AsinFn {
635 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
636 self.signature.validate(args, ctx)?;
637 let n = args[0].as_number().ok_or_else(|| {
638 JmespathError::new(
639 ctx.expression,
640 0,
641 ErrorReason::Parse("Expected number".to_owned()),
642 )
643 })?;
644 let result = n.asin();
645 if result.is_nan() {
647 Ok(Rc::new(Variable::Null))
648 } else {
649 Ok(Rc::new(Variable::Number(
650 serde_json::Number::from_f64(result).unwrap_or_else(|| serde_json::Number::from(0)),
651 )))
652 }
653 }
654}
655
656define_function!(AcosFn, vec![ArgumentType::Number], None);
657
658impl Function for AcosFn {
659 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
660 self.signature.validate(args, ctx)?;
661 let n = args[0].as_number().ok_or_else(|| {
662 JmespathError::new(
663 ctx.expression,
664 0,
665 ErrorReason::Parse("Expected number".to_owned()),
666 )
667 })?;
668 let result = n.acos();
669 if result.is_nan() {
671 Ok(Rc::new(Variable::Null))
672 } else {
673 Ok(Rc::new(Variable::Number(
674 serde_json::Number::from_f64(result).unwrap_or_else(|| serde_json::Number::from(0)),
675 )))
676 }
677 }
678}
679
680define_function!(AtanFn, vec![ArgumentType::Number], None);
681
682impl Function for AtanFn {
683 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
684 self.signature.validate(args, ctx)?;
685 let n = args[0].as_number().ok_or_else(|| {
686 JmespathError::new(
687 ctx.expression,
688 0,
689 ErrorReason::Parse("Expected number".to_owned()),
690 )
691 })?;
692 Ok(Rc::new(Variable::Number(
693 serde_json::Number::from_f64(n.atan()).unwrap_or_else(|| serde_json::Number::from(0)),
694 )))
695 }
696}
697
698define_function!(
699 Atan2Fn,
700 vec![ArgumentType::Number, ArgumentType::Number],
701 None
702);
703
704impl Function for Atan2Fn {
705 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
706 self.signature.validate(args, ctx)?;
707 let y = args[0].as_number().ok_or_else(|| {
708 JmespathError::new(
709 ctx.expression,
710 0,
711 ErrorReason::Parse("Expected number".to_owned()),
712 )
713 })?;
714 let x = args[1].as_number().ok_or_else(|| {
715 JmespathError::new(
716 ctx.expression,
717 0,
718 ErrorReason::Parse("Expected number".to_owned()),
719 )
720 })?;
721 Ok(Rc::new(Variable::Number(
722 serde_json::Number::from_f64(y.atan2(x)).unwrap_or_else(|| serde_json::Number::from(0)),
723 )))
724 }
725}
726
727define_function!(DegToRadFn, vec![ArgumentType::Number], None);
728
729impl Function for DegToRadFn {
730 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
731 self.signature.validate(args, ctx)?;
732 let n = args[0].as_number().ok_or_else(|| {
733 JmespathError::new(
734 ctx.expression,
735 0,
736 ErrorReason::Parse("Expected number".to_owned()),
737 )
738 })?;
739 Ok(Rc::new(Variable::Number(
740 serde_json::Number::from_f64(n.to_radians())
741 .unwrap_or_else(|| serde_json::Number::from(0)),
742 )))
743 }
744}
745
746define_function!(RadToDegFn, vec![ArgumentType::Number], None);
747
748impl Function for RadToDegFn {
749 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
750 self.signature.validate(args, ctx)?;
751 let n = args[0].as_number().ok_or_else(|| {
752 JmespathError::new(
753 ctx.expression,
754 0,
755 ErrorReason::Parse("Expected number".to_owned()),
756 )
757 })?;
758 Ok(Rc::new(Variable::Number(
759 serde_json::Number::from_f64(n.to_degrees())
760 .unwrap_or_else(|| serde_json::Number::from(0)),
761 )))
762 }
763}
764
765define_function!(SignFn, vec![ArgumentType::Number], None);
766
767impl Function for SignFn {
768 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
769 self.signature.validate(args, ctx)?;
770 let n = args[0].as_number().ok_or_else(|| {
771 JmespathError::new(
772 ctx.expression,
773 0,
774 ErrorReason::Parse("Expected number".to_owned()),
775 )
776 })?;
777 let sign = if n > 0.0 {
778 1
779 } else if n < 0.0 {
780 -1
781 } else {
782 0
783 };
784 Ok(Rc::new(Variable::Number(serde_json::Number::from(sign))))
785 }
786}
787
788define_function!(
793 AddFn,
794 vec![ArgumentType::Number, ArgumentType::Number],
795 None
796);
797
798impl Function for AddFn {
799 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
800 self.signature.validate(args, ctx)?;
801 let a = args[0].as_number().ok_or_else(|| {
802 JmespathError::new(
803 ctx.expression,
804 0,
805 ErrorReason::Parse("Expected number".to_owned()),
806 )
807 })?;
808 let b = args[1].as_number().ok_or_else(|| {
809 JmespathError::new(
810 ctx.expression,
811 0,
812 ErrorReason::Parse("Expected number".to_owned()),
813 )
814 })?;
815 Ok(Rc::new(Variable::Number(
816 serde_json::Number::from_f64(a + b).unwrap_or_else(|| serde_json::Number::from(0)),
817 )))
818 }
819}
820
821define_function!(
826 SubtractFn,
827 vec![ArgumentType::Number, ArgumentType::Number],
828 None
829);
830
831impl Function for SubtractFn {
832 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
833 self.signature.validate(args, ctx)?;
834 let a = args[0].as_number().ok_or_else(|| {
835 JmespathError::new(
836 ctx.expression,
837 0,
838 ErrorReason::Parse("Expected number".to_owned()),
839 )
840 })?;
841 let b = args[1].as_number().ok_or_else(|| {
842 JmespathError::new(
843 ctx.expression,
844 0,
845 ErrorReason::Parse("Expected number".to_owned()),
846 )
847 })?;
848 Ok(Rc::new(Variable::Number(
849 serde_json::Number::from_f64(a - b).unwrap_or_else(|| serde_json::Number::from(0)),
850 )))
851 }
852}
853
854define_function!(
859 MultiplyFn,
860 vec![ArgumentType::Number, ArgumentType::Number],
861 None
862);
863
864impl Function for MultiplyFn {
865 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
866 self.signature.validate(args, ctx)?;
867 let a = args[0].as_number().ok_or_else(|| {
868 JmespathError::new(
869 ctx.expression,
870 0,
871 ErrorReason::Parse("Expected number".to_owned()),
872 )
873 })?;
874 let b = args[1].as_number().ok_or_else(|| {
875 JmespathError::new(
876 ctx.expression,
877 0,
878 ErrorReason::Parse("Expected number".to_owned()),
879 )
880 })?;
881 Ok(Rc::new(Variable::Number(
882 serde_json::Number::from_f64(a * b).unwrap_or_else(|| serde_json::Number::from(0)),
883 )))
884 }
885}
886
887define_function!(
892 DivideFn,
893 vec![ArgumentType::Number, ArgumentType::Number],
894 None
895);
896
897impl Function for DivideFn {
898 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
899 self.signature.validate(args, ctx)?;
900 let a = args[0].as_number().ok_or_else(|| {
901 JmespathError::new(
902 ctx.expression,
903 0,
904 ErrorReason::Parse("Expected number".to_owned()),
905 )
906 })?;
907 let b = args[1].as_number().ok_or_else(|| {
908 JmespathError::new(
909 ctx.expression,
910 0,
911 ErrorReason::Parse("Expected number".to_owned()),
912 )
913 })?;
914 if b == 0.0 {
915 return Err(JmespathError::new(
916 ctx.expression,
917 0,
918 ErrorReason::Parse("Division by zero".to_owned()),
919 ));
920 }
921 Ok(Rc::new(Variable::Number(
922 serde_json::Number::from_f64(a / b).unwrap_or_else(|| serde_json::Number::from(0)),
923 )))
924 }
925}
926
927define_function!(ModeFn, vec![ArgumentType::Array], None);
932
933impl Function for ModeFn {
934 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
935 self.signature.validate(args, ctx)?;
936
937 let arr = args[0].as_array().ok_or_else(|| {
938 JmespathError::new(
939 ctx.expression,
940 0,
941 ErrorReason::Parse("Expected array argument".to_owned()),
942 )
943 })?;
944
945 if arr.is_empty() {
946 return Ok(Rc::new(Variable::Null));
947 }
948
949 let mut counts: std::collections::HashMap<String, (usize, Rcvar)> =
951 std::collections::HashMap::new();
952
953 for item in arr.iter() {
954 let key = serde_json::to_string(&**item).unwrap_or_default();
955 counts
956 .entry(key)
957 .and_modify(|(count, _)| *count += 1)
958 .or_insert((1, item.clone()));
959 }
960
961 let (_, (_, mode_value)) = counts
963 .into_iter()
964 .max_by_key(|(_, (count, _))| *count)
965 .unwrap();
966
967 Ok(mode_value)
968 }
969}
970
971define_function!(
977 ToFixedFn,
978 vec![ArgumentType::Number, ArgumentType::Number],
979 None
980);
981
982impl Function for ToFixedFn {
983 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
984 self.signature.validate(args, ctx)?;
985
986 let num = args[0].as_number().ok_or_else(|| {
987 JmespathError::new(
988 ctx.expression,
989 0,
990 ErrorReason::Parse("Expected number argument".to_owned()),
991 )
992 })?;
993
994 let precision = args[1].as_number().ok_or_else(|| {
995 JmespathError::new(
996 ctx.expression,
997 0,
998 ErrorReason::Parse("Expected precision argument".to_owned()),
999 )
1000 })? as usize;
1001
1002 let result = format!("{:.prec$}", num, prec = precision);
1003 Ok(Rc::new(Variable::String(result)))
1004 }
1005}
1006
1007define_function!(
1013 FormatNumberFn,
1014 vec![ArgumentType::Number],
1015 Some(ArgumentType::Any)
1016);
1017
1018impl Function for FormatNumberFn {
1019 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1020 self.signature.validate(args, ctx)?;
1021
1022 let num = args[0].as_number().ok_or_else(|| {
1023 JmespathError::new(
1024 ctx.expression,
1025 0,
1026 ErrorReason::Parse("Expected number argument".to_owned()),
1027 )
1028 })?;
1029
1030 let precision = args
1031 .get(1)
1032 .and_then(|v| v.as_number())
1033 .map(|n| n as usize)
1034 .unwrap_or(0);
1035
1036 let suffix = args
1037 .get(2)
1038 .and_then(|v| v.as_string())
1039 .map(|s| s.to_string());
1040
1041 let (scaled_num, auto_suffix) = if let Some(ref s) = suffix {
1043 match s.as_str() {
1044 "k" | "K" => (num / 1_000.0, "k"),
1045 "M" => (num / 1_000_000.0, "M"),
1046 "B" => (num / 1_000_000_000.0, "B"),
1047 "T" => (num / 1_000_000_000_000.0, "T"),
1048 "auto" => {
1049 let abs_num = num.abs();
1051 if abs_num >= 1_000_000_000_000.0 {
1052 (num / 1_000_000_000_000.0, "T")
1053 } else if abs_num >= 1_000_000_000.0 {
1054 (num / 1_000_000_000.0, "B")
1055 } else if abs_num >= 1_000_000.0 {
1056 (num / 1_000_000.0, "M")
1057 } else if abs_num >= 1_000.0 {
1058 (num / 1_000.0, "k")
1059 } else {
1060 (num, "")
1061 }
1062 }
1063 _ => (num, s.as_str()),
1064 }
1065 } else {
1066 (num, "")
1067 };
1068
1069 let formatted = format!("{:.prec$}", scaled_num, prec = precision);
1071
1072 let result = if suffix.is_none() || suffix.as_deref() == Some("") {
1074 add_thousand_separators(&formatted)
1075 } else {
1076 format!("{}{}", formatted, auto_suffix)
1077 };
1078
1079 Ok(Rc::new(Variable::String(result)))
1080 }
1081}
1082
1083fn add_thousand_separators(s: &str) -> String {
1085 let parts: Vec<&str> = s.split('.').collect();
1086 let int_part = parts[0];
1087 let dec_part = parts.get(1);
1088
1089 let (sign, digits) = if let Some(stripped) = int_part.strip_prefix('-') {
1091 ("-", stripped)
1092 } else {
1093 ("", int_part)
1094 };
1095
1096 let digit_chars: Vec<char> = digits.chars().collect();
1098 let len = digit_chars.len();
1099 let with_commas: String = digit_chars
1100 .iter()
1101 .enumerate()
1102 .map(|(i, c)| {
1103 let pos_from_right = len - 1 - i;
1104 if pos_from_right > 0 && pos_from_right % 3 == 0 {
1105 format!("{},", c)
1106 } else {
1107 c.to_string()
1108 }
1109 })
1110 .collect();
1111
1112 match dec_part {
1113 Some(dec) => format!("{}{}.{}", sign, with_commas, dec),
1114 None => format!("{}{}", sign, with_commas),
1115 }
1116}
1117
1118define_function!(
1124 HistogramFn,
1125 vec![ArgumentType::Array, ArgumentType::Number],
1126 None
1127);
1128
1129impl Function for HistogramFn {
1130 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1131 self.signature.validate(args, ctx)?;
1132
1133 let arr = args[0].as_array().ok_or_else(|| {
1134 JmespathError::new(
1135 ctx.expression,
1136 0,
1137 ErrorReason::Parse("Expected array argument".to_owned()),
1138 )
1139 })?;
1140
1141 let num_bins = args[1].as_number().ok_or_else(|| {
1142 JmespathError::new(
1143 ctx.expression,
1144 0,
1145 ErrorReason::Parse("Expected number of bins".to_owned()),
1146 )
1147 })? as usize;
1148
1149 if num_bins == 0 {
1150 return Err(JmespathError::new(
1151 ctx.expression,
1152 0,
1153 ErrorReason::Parse("Number of bins must be greater than 0".to_owned()),
1154 ));
1155 }
1156
1157 let values: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
1159
1160 if values.is_empty() {
1161 return Ok(Rc::new(Variable::Array(vec![])));
1162 }
1163
1164 let min_val = values.iter().cloned().fold(f64::INFINITY, f64::min);
1165 let max_val = values.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
1166
1167 let bin_width = if (max_val - min_val).abs() < f64::EPSILON {
1169 1.0
1170 } else {
1171 (max_val - min_val) / num_bins as f64
1172 };
1173
1174 let mut bins: Vec<(f64, f64, usize)> = (0..num_bins)
1176 .map(|i| {
1177 let bin_min = min_val + (i as f64 * bin_width);
1178 let bin_max = if i == num_bins - 1 {
1179 max_val
1180 } else {
1181 min_val + ((i + 1) as f64 * bin_width)
1182 };
1183 (bin_min, bin_max, 0)
1184 })
1185 .collect();
1186
1187 for val in &values {
1189 let bin_idx = if (max_val - min_val).abs() < f64::EPSILON {
1190 0
1191 } else {
1192 let idx = ((val - min_val) / bin_width) as usize;
1193 idx.min(num_bins - 1)
1194 };
1195 bins[bin_idx].2 += 1;
1196 }
1197
1198 let result: Vec<Rcvar> = bins
1200 .into_iter()
1201 .map(|(bin_min, bin_max, count)| {
1202 let mut map = std::collections::BTreeMap::new();
1203 map.insert(
1204 "min".to_string(),
1205 Rc::new(Variable::Number(
1206 serde_json::Number::from_f64(bin_min)
1207 .unwrap_or_else(|| serde_json::Number::from(0)),
1208 )) as Rcvar,
1209 );
1210 map.insert(
1211 "max".to_string(),
1212 Rc::new(Variable::Number(
1213 serde_json::Number::from_f64(bin_max)
1214 .unwrap_or_else(|| serde_json::Number::from(0)),
1215 )) as Rcvar,
1216 );
1217 map.insert(
1218 "count".to_string(),
1219 Rc::new(Variable::Number(serde_json::Number::from(count))) as Rcvar,
1220 );
1221 Rc::new(Variable::Object(map)) as Rcvar
1222 })
1223 .collect();
1224
1225 Ok(Rc::new(Variable::Array(result)))
1226 }
1227}
1228
1229define_function!(NormalizeFn, vec![ArgumentType::Array], None);
1235
1236impl Function for NormalizeFn {
1237 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1238 self.signature.validate(args, ctx)?;
1239
1240 let arr = args[0].as_array().ok_or_else(|| {
1241 JmespathError::new(
1242 ctx.expression,
1243 0,
1244 ErrorReason::Parse("Expected array argument".to_owned()),
1245 )
1246 })?;
1247
1248 let values: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
1250
1251 if values.is_empty() {
1252 return Ok(Rc::new(Variable::Array(vec![])));
1253 }
1254
1255 let min_val = values.iter().cloned().fold(f64::INFINITY, f64::min);
1256 let max_val = values.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
1257 let range = max_val - min_val;
1258
1259 let result: Vec<Rcvar> = values
1260 .iter()
1261 .map(|v| {
1262 let normalized = if range.abs() < f64::EPSILON {
1263 0.0 } else {
1265 (v - min_val) / range
1266 };
1267 Rc::new(Variable::Number(
1268 serde_json::Number::from_f64(normalized)
1269 .unwrap_or_else(|| serde_json::Number::from(0)),
1270 )) as Rcvar
1271 })
1272 .collect();
1273
1274 Ok(Rc::new(Variable::Array(result)))
1275 }
1276}
1277
1278define_function!(ZScoreFn, vec![ArgumentType::Array], None);
1284
1285impl Function for ZScoreFn {
1286 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1287 self.signature.validate(args, ctx)?;
1288
1289 let arr = args[0].as_array().ok_or_else(|| {
1290 JmespathError::new(
1291 ctx.expression,
1292 0,
1293 ErrorReason::Parse("Expected array argument".to_owned()),
1294 )
1295 })?;
1296
1297 let values: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
1299
1300 if values.is_empty() {
1301 return Ok(Rc::new(Variable::Array(vec![])));
1302 }
1303
1304 let n = values.len() as f64;
1305 let mean = values.iter().sum::<f64>() / n;
1306 let variance = values.iter().map(|v| (v - mean).powi(2)).sum::<f64>() / n;
1307 let stddev = variance.sqrt();
1308
1309 let result: Vec<Rcvar> = values
1310 .iter()
1311 .map(|v| {
1312 let z = if stddev.abs() < f64::EPSILON {
1313 0.0 } else {
1315 (v - mean) / stddev
1316 };
1317 Rc::new(Variable::Number(
1318 serde_json::Number::from_f64(z).unwrap_or_else(|| serde_json::Number::from(0)),
1319 )) as Rcvar
1320 })
1321 .collect();
1322
1323 Ok(Rc::new(Variable::Array(result)))
1324 }
1325}
1326
1327define_function!(
1333 CorrelationFn,
1334 vec![ArgumentType::Array, ArgumentType::Array],
1335 None
1336);
1337
1338impl Function for CorrelationFn {
1339 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1340 self.signature.validate(args, ctx)?;
1341
1342 let arr1 = args[0].as_array().ok_or_else(|| {
1343 JmespathError::new(
1344 ctx.expression,
1345 0,
1346 ErrorReason::Parse("Expected array argument".to_owned()),
1347 )
1348 })?;
1349
1350 let arr2 = args[1].as_array().ok_or_else(|| {
1351 JmespathError::new(
1352 ctx.expression,
1353 0,
1354 ErrorReason::Parse("Expected array argument".to_owned()),
1355 )
1356 })?;
1357
1358 let values1: Vec<f64> = arr1.iter().filter_map(|v| v.as_number()).collect();
1360 let values2: Vec<f64> = arr2.iter().filter_map(|v| v.as_number()).collect();
1361
1362 if values1.is_empty() || values2.is_empty() {
1363 return Ok(Rc::new(Variable::Null));
1364 }
1365
1366 let n = values1.len().min(values2.len());
1368 if n == 0 {
1369 return Ok(Rc::new(Variable::Null));
1370 }
1371
1372 let values1 = &values1[..n];
1373 let values2 = &values2[..n];
1374
1375 let mean1 = values1.iter().sum::<f64>() / n as f64;
1376 let mean2 = values2.iter().sum::<f64>() / n as f64;
1377
1378 let mut cov = 0.0;
1379 let mut var1 = 0.0;
1380 let mut var2 = 0.0;
1381
1382 for i in 0..n {
1383 let d1 = values1[i] - mean1;
1384 let d2 = values2[i] - mean2;
1385 cov += d1 * d2;
1386 var1 += d1 * d1;
1387 var2 += d2 * d2;
1388 }
1389
1390 let denom = (var1 * var2).sqrt();
1391 let correlation = if denom.abs() < f64::EPSILON {
1392 0.0 } else {
1394 cov / denom
1395 };
1396
1397 Ok(Rc::new(Variable::Number(
1398 serde_json::Number::from_f64(correlation)
1399 .unwrap_or_else(|| serde_json::Number::from(0)),
1400 )))
1401 }
1402}
1403
1404define_function!(
1410 QuantileFn,
1411 vec![ArgumentType::Array, ArgumentType::Number],
1412 None
1413);
1414
1415impl Function for QuantileFn {
1416 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1417 self.signature.validate(args, ctx)?;
1418
1419 let arr = args[0].as_array().ok_or_else(|| {
1420 JmespathError::new(
1421 ctx.expression,
1422 0,
1423 ErrorReason::Parse("Expected array argument".to_owned()),
1424 )
1425 })?;
1426
1427 let q = args[1].as_number().ok_or_else(|| {
1428 JmespathError::new(
1429 ctx.expression,
1430 0,
1431 ErrorReason::Parse("Expected number for quantile".to_owned()),
1432 )
1433 })?;
1434
1435 if !(0.0..=1.0).contains(&q) {
1436 return Ok(Rc::new(Variable::Null));
1437 }
1438
1439 let mut values: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
1440
1441 if values.is_empty() {
1442 return Ok(Rc::new(Variable::Null));
1443 }
1444
1445 values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
1446
1447 let n = values.len();
1448 let pos = q * (n - 1) as f64;
1449 let lower = pos.floor() as usize;
1450 let upper = pos.ceil() as usize;
1451 let frac = pos - lower as f64;
1452
1453 let result = if lower == upper {
1454 values[lower]
1455 } else {
1456 values[lower] * (1.0 - frac) + values[upper] * frac
1457 };
1458
1459 Ok(Rc::new(Variable::Number(
1460 serde_json::Number::from_f64(result).unwrap_or_else(|| serde_json::Number::from(0)),
1461 )))
1462 }
1463}
1464
1465define_function!(
1471 MovingAvgFn,
1472 vec![ArgumentType::Array, ArgumentType::Number],
1473 None
1474);
1475
1476impl Function for MovingAvgFn {
1477 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1478 self.signature.validate(args, ctx)?;
1479
1480 let arr = args[0].as_array().ok_or_else(|| {
1481 JmespathError::new(
1482 ctx.expression,
1483 0,
1484 ErrorReason::Parse("Expected array argument".to_owned()),
1485 )
1486 })?;
1487
1488 let window = args[1].as_number().ok_or_else(|| {
1489 JmespathError::new(
1490 ctx.expression,
1491 0,
1492 ErrorReason::Parse("Expected number for window size".to_owned()),
1493 )
1494 })? as usize;
1495
1496 if window == 0 {
1497 return Ok(Rc::new(Variable::Null));
1498 }
1499
1500 let values: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
1501
1502 if values.is_empty() || window > values.len() {
1503 return Ok(Rc::new(Variable::Array(vec![])));
1504 }
1505
1506 let mut result: Vec<Rcvar> = Vec::new();
1507
1508 for i in 0..values.len() {
1510 if i + 1 < window {
1511 result.push(Rc::new(Variable::Null));
1513 } else {
1514 let start = i + 1 - window;
1515 let sum: f64 = values[start..=i].iter().sum();
1516 let avg = sum / window as f64;
1517 result.push(Rc::new(Variable::Number(
1518 serde_json::Number::from_f64(avg)
1519 .unwrap_or_else(|| serde_json::Number::from(0)),
1520 )));
1521 }
1522 }
1523
1524 Ok(Rc::new(Variable::Array(result)))
1525 }
1526}
1527
1528define_function!(
1534 EwmaFn,
1535 vec![ArgumentType::Array, ArgumentType::Number],
1536 None
1537);
1538
1539impl Function for EwmaFn {
1540 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1541 self.signature.validate(args, ctx)?;
1542
1543 let arr = args[0].as_array().ok_or_else(|| {
1544 JmespathError::new(
1545 ctx.expression,
1546 0,
1547 ErrorReason::Parse("Expected array argument".to_owned()),
1548 )
1549 })?;
1550
1551 let alpha = args[1].as_number().ok_or_else(|| {
1552 JmespathError::new(
1553 ctx.expression,
1554 0,
1555 ErrorReason::Parse("Expected number for alpha".to_owned()),
1556 )
1557 })?;
1558
1559 if !(0.0..=1.0).contains(&alpha) {
1560 return Ok(Rc::new(Variable::Null));
1561 }
1562
1563 let values: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
1564
1565 if values.is_empty() {
1566 return Ok(Rc::new(Variable::Array(vec![])));
1567 }
1568
1569 let mut result: Vec<Rcvar> = Vec::new();
1570 let mut ewma = values[0];
1571
1572 for value in &values {
1573 ewma = alpha * value + (1.0 - alpha) * ewma;
1574 result.push(Rc::new(Variable::Number(
1575 serde_json::Number::from_f64(ewma).unwrap_or_else(|| serde_json::Number::from(0)),
1576 )));
1577 }
1578
1579 Ok(Rc::new(Variable::Array(result)))
1580 }
1581}
1582
1583define_function!(
1589 CovarianceFn,
1590 vec![ArgumentType::Array, ArgumentType::Array],
1591 None
1592);
1593
1594impl Function for CovarianceFn {
1595 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1596 self.signature.validate(args, ctx)?;
1597
1598 let arr1 = args[0].as_array().ok_or_else(|| {
1599 JmespathError::new(
1600 ctx.expression,
1601 0,
1602 ErrorReason::Parse("Expected array argument".to_owned()),
1603 )
1604 })?;
1605
1606 let arr2 = args[1].as_array().ok_or_else(|| {
1607 JmespathError::new(
1608 ctx.expression,
1609 0,
1610 ErrorReason::Parse("Expected array argument".to_owned()),
1611 )
1612 })?;
1613
1614 let values1: Vec<f64> = arr1.iter().filter_map(|v| v.as_number()).collect();
1615 let values2: Vec<f64> = arr2.iter().filter_map(|v| v.as_number()).collect();
1616
1617 if values1.is_empty() || values1.len() != values2.len() {
1618 return Ok(Rc::new(Variable::Null));
1619 }
1620
1621 let n = values1.len() as f64;
1622 let mean1: f64 = values1.iter().sum::<f64>() / n;
1623 let mean2: f64 = values2.iter().sum::<f64>() / n;
1624
1625 let cov: f64 = values1
1626 .iter()
1627 .zip(values2.iter())
1628 .map(|(x, y)| (x - mean1) * (y - mean2))
1629 .sum::<f64>()
1630 / n;
1631
1632 Ok(Rc::new(Variable::Number(
1633 serde_json::Number::from_f64(cov).unwrap_or_else(|| serde_json::Number::from(0)),
1634 )))
1635 }
1636}
1637
1638define_function!(StandardizeFn, vec![ArgumentType::Array], None);
1644
1645impl Function for StandardizeFn {
1646 fn evaluate(&self, args: &[Rcvar], ctx: &mut Context<'_>) -> Result<Rcvar, JmespathError> {
1647 self.signature.validate(args, ctx)?;
1648
1649 let arr = args[0].as_array().ok_or_else(|| {
1650 JmespathError::new(
1651 ctx.expression,
1652 0,
1653 ErrorReason::Parse("Expected array argument".to_owned()),
1654 )
1655 })?;
1656
1657 let values: Vec<f64> = arr.iter().filter_map(|v| v.as_number()).collect();
1658
1659 if values.is_empty() {
1660 return Ok(Rc::new(Variable::Array(vec![])));
1661 }
1662
1663 let n = values.len() as f64;
1664 let mean: f64 = values.iter().sum::<f64>() / n;
1665 let variance: f64 = values.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / n;
1666 let std_dev = variance.sqrt();
1667
1668 let result: Vec<Rcvar> = values
1669 .iter()
1670 .map(|x| {
1671 let standardized = if std_dev.abs() < f64::EPSILON {
1672 0.0
1673 } else {
1674 (x - mean) / std_dev
1675 };
1676 Rc::new(Variable::Number(
1677 serde_json::Number::from_f64(standardized)
1678 .unwrap_or_else(|| serde_json::Number::from(0)),
1679 ))
1680 })
1681 .collect();
1682
1683 Ok(Rc::new(Variable::Array(result)))
1684 }
1685}
1686
1687#[cfg(test)]
1688mod tests {
1689 use super::*;
1690 use jmespath::Runtime;
1691
1692 fn setup_runtime() -> Runtime {
1693 let mut runtime = Runtime::new();
1694 runtime.register_builtin_functions();
1695 register(&mut runtime);
1696 runtime
1697 }
1698
1699 #[test]
1700 #[allow(clippy::approx_constant)]
1701 fn test_round() {
1702 let runtime = setup_runtime();
1703 let expr = runtime.compile("round(`3.14159`, `2`)").unwrap();
1704 let result = expr.search(&Variable::Null).unwrap();
1705 assert!((result.as_number().unwrap() - 3.14_f64).abs() < 0.001);
1706 }
1707
1708 #[test]
1709 fn test_sqrt() {
1710 let runtime = setup_runtime();
1711 let expr = runtime.compile("sqrt(`16`)").unwrap();
1712 let result = expr.search(&Variable::Null).unwrap();
1713 assert_eq!(result.as_number().unwrap() as i64, 4);
1714 }
1715
1716 #[test]
1717 fn test_clamp() {
1718 let runtime = setup_runtime();
1719 let expr = runtime.compile("clamp(`5`, `0`, `3`)").unwrap();
1720 let result = expr.search(&Variable::Null).unwrap();
1721 assert_eq!(result.as_number().unwrap() as i64, 3);
1722 }
1723
1724 #[test]
1725 fn test_add() {
1726 let runtime = setup_runtime();
1727 let expr = runtime.compile("add(`1`, `2`)").unwrap();
1728 let result = expr.search(&Variable::Null).unwrap();
1729 assert_eq!(result.as_number().unwrap() as i64, 3);
1730 }
1731
1732 #[test]
1733 fn test_subtract() {
1734 let runtime = setup_runtime();
1735 let expr = runtime.compile("subtract(`10`, `3`)").unwrap();
1736 let result = expr.search(&Variable::Null).unwrap();
1737 assert_eq!(result.as_number().unwrap() as i64, 7);
1738 }
1739
1740 #[test]
1741 fn test_multiply() {
1742 let runtime = setup_runtime();
1743 let expr = runtime.compile("multiply(`4`, `5`)").unwrap();
1744 let result = expr.search(&Variable::Null).unwrap();
1745 assert_eq!(result.as_number().unwrap() as i64, 20);
1746 }
1747
1748 #[test]
1749 fn test_divide() {
1750 let runtime = setup_runtime();
1751 let expr = runtime.compile("divide(`10`, `4`)").unwrap();
1752 let result = expr.search(&Variable::Null).unwrap();
1753 assert_eq!(result.as_number().unwrap(), 2.5);
1754 }
1755
1756 #[test]
1757 fn test_mode_numbers() {
1758 let runtime = setup_runtime();
1759 let expr = runtime.compile("mode(`[1, 2, 2, 3]`)").unwrap();
1760 let result = expr.search(&Variable::Null).unwrap();
1761 assert_eq!(result.as_number().unwrap() as i64, 2);
1762 }
1763
1764 #[test]
1765 fn test_mode_strings() {
1766 let runtime = setup_runtime();
1767 let expr = runtime
1768 .compile("mode(`[\"a\", \"b\", \"a\", \"c\"]`)")
1769 .unwrap();
1770 let result = expr.search(&Variable::Null).unwrap();
1771 assert_eq!(result.as_string().unwrap(), "a");
1772 }
1773
1774 #[test]
1775 fn test_mode_empty() {
1776 let runtime = setup_runtime();
1777 let expr = runtime.compile("mode(`[]`)").unwrap();
1778 let result = expr.search(&Variable::Null).unwrap();
1779 assert!(result.is_null());
1780 }
1781
1782 #[test]
1783 fn test_to_fixed() {
1784 let runtime = setup_runtime();
1785 let expr = runtime.compile("to_fixed(`3.14159`, `2`)").unwrap();
1786 let result = expr.search(&Variable::Null).unwrap();
1787 assert_eq!(result.as_string().unwrap(), "3.14");
1788 }
1789
1790 #[test]
1791 fn test_to_fixed_padding() {
1792 let runtime = setup_runtime();
1793 let expr = runtime.compile("to_fixed(`3.1`, `3`)").unwrap();
1794 let result = expr.search(&Variable::Null).unwrap();
1795 assert_eq!(result.as_string().unwrap(), "3.100");
1796 }
1797
1798 #[test]
1799 fn test_format_number_with_separators() {
1800 let runtime = setup_runtime();
1801 let expr = runtime.compile("format_number(`1234567.89`, `2`)").unwrap();
1802 let result = expr.search(&Variable::Null).unwrap();
1803 assert_eq!(result.as_string().unwrap(), "1,234,567.89");
1804 }
1805
1806 #[test]
1807 fn test_format_number_with_k_suffix() {
1808 let runtime = setup_runtime();
1809 let expr = runtime.compile("format_number(`1500`, `1`, 'k')").unwrap();
1810 let result = expr.search(&Variable::Null).unwrap();
1811 assert_eq!(result.as_string().unwrap(), "1.5k");
1812 }
1813
1814 #[test]
1815 fn test_format_number_with_m_suffix() {
1816 let runtime = setup_runtime();
1817 let expr = runtime
1818 .compile("format_number(`1500000`, `1`, 'M')")
1819 .unwrap();
1820 let result = expr.search(&Variable::Null).unwrap();
1821 assert_eq!(result.as_string().unwrap(), "1.5M");
1822 }
1823
1824 #[test]
1825 fn test_format_number_auto_suffix() {
1826 let runtime = setup_runtime();
1827 let expr = runtime
1828 .compile("format_number(`1500000000`, `2`, 'auto')")
1829 .unwrap();
1830 let result = expr.search(&Variable::Null).unwrap();
1831 assert_eq!(result.as_string().unwrap(), "1.50B");
1832 }
1833
1834 #[test]
1835 fn test_histogram() {
1836 let runtime = setup_runtime();
1837 let expr = runtime.compile("histogram(@, `3`)").unwrap();
1838 let data: Variable = serde_json::from_str("[1, 2, 3, 4, 5, 6, 7, 8, 9]").unwrap();
1839 let result = expr.search(&data).unwrap();
1840 let arr = result.as_array().unwrap();
1841 assert_eq!(arr.len(), 3);
1842 for bin in arr {
1844 let obj = bin.as_object().unwrap();
1845 assert!(obj.contains_key("min"));
1846 assert!(obj.contains_key("max"));
1847 assert!(obj.contains_key("count"));
1848 }
1849 }
1850
1851 #[test]
1852 fn test_normalize() {
1853 let runtime = setup_runtime();
1854 let expr = runtime.compile("normalize(@)").unwrap();
1855 let data: Variable = serde_json::from_str("[0, 50, 100]").unwrap();
1856 let result = expr.search(&data).unwrap();
1857 let arr = result.as_array().unwrap();
1858 assert_eq!(arr.len(), 3);
1859 assert!((arr[0].as_number().unwrap() - 0.0).abs() < 0.001);
1860 assert!((arr[1].as_number().unwrap() - 0.5).abs() < 0.001);
1861 assert!((arr[2].as_number().unwrap() - 1.0).abs() < 0.001);
1862 }
1863
1864 #[test]
1865 fn test_z_score() {
1866 let runtime = setup_runtime();
1867 let expr = runtime.compile("z_score(@)").unwrap();
1868 let data: Variable = serde_json::from_str("[1, 2, 3, 4, 5]").unwrap();
1869 let result = expr.search(&data).unwrap();
1870 let arr = result.as_array().unwrap();
1871 assert_eq!(arr.len(), 5);
1872 assert!((arr[2].as_number().unwrap() - 0.0).abs() < 0.001);
1874 }
1875
1876 #[test]
1877 fn test_correlation_positive() {
1878 let runtime = setup_runtime();
1879 let expr = runtime
1880 .compile("correlation(`[1, 2, 3]`, `[1, 2, 3]`)")
1881 .unwrap();
1882 let result = expr.search(&Variable::Null).unwrap();
1883 assert!((result.as_number().unwrap() - 1.0).abs() < 0.001);
1884 }
1885
1886 #[test]
1887 fn test_correlation_negative() {
1888 let runtime = setup_runtime();
1889 let expr = runtime
1890 .compile("correlation(`[1, 2, 3]`, `[3, 2, 1]`)")
1891 .unwrap();
1892 let result = expr.search(&Variable::Null).unwrap();
1893 assert!((result.as_number().unwrap() - (-1.0)).abs() < 0.001);
1894 }
1895
1896 #[test]
1897 fn test_quantile_median() {
1898 let runtime = setup_runtime();
1899 let expr = runtime
1900 .compile("quantile(`[1, 2, 3, 4, 5]`, `0.5`)")
1901 .unwrap();
1902 let result = expr.search(&Variable::Null).unwrap();
1903 assert_eq!(result.as_number().unwrap(), 3.0);
1904 }
1905
1906 #[test]
1907 fn test_quantile_quartiles() {
1908 let runtime = setup_runtime();
1909 let expr = runtime
1911 .compile("quantile(`[1, 2, 3, 4, 5]`, `0.25`)")
1912 .unwrap();
1913 let result = expr.search(&Variable::Null).unwrap();
1914 assert_eq!(result.as_number().unwrap(), 2.0);
1915
1916 let expr = runtime
1918 .compile("quantile(`[1, 2, 3, 4, 5]`, `0.75`)")
1919 .unwrap();
1920 let result = expr.search(&Variable::Null).unwrap();
1921 assert_eq!(result.as_number().unwrap(), 4.0);
1922 }
1923
1924 #[test]
1925 fn test_moving_avg() {
1926 let runtime = setup_runtime();
1927 let expr = runtime
1928 .compile("moving_avg(`[1, 2, 3, 4, 5, 6]`, `3`)")
1929 .unwrap();
1930 let result = expr.search(&Variable::Null).unwrap();
1931 let arr = result.as_array().unwrap();
1932 assert_eq!(arr.len(), 6);
1933 assert!(arr[0].is_null());
1934 assert!(arr[1].is_null());
1935 assert_eq!(arr[2].as_number().unwrap(), 2.0); assert_eq!(arr[3].as_number().unwrap(), 3.0); assert_eq!(arr[4].as_number().unwrap(), 4.0); assert_eq!(arr[5].as_number().unwrap(), 5.0); }
1940
1941 #[test]
1942 fn test_ewma() {
1943 let runtime = setup_runtime();
1944 let expr = runtime.compile("ewma(`[1, 2, 3, 4, 5]`, `0.5`)").unwrap();
1945 let result = expr.search(&Variable::Null).unwrap();
1946 let arr = result.as_array().unwrap();
1947 assert_eq!(arr.len(), 5);
1948 assert_eq!(arr[0].as_number().unwrap(), 1.0);
1950 assert_eq!(arr[1].as_number().unwrap(), 1.5); assert_eq!(arr[2].as_number().unwrap(), 2.25); }
1954
1955 #[test]
1956 fn test_covariance() {
1957 let runtime = setup_runtime();
1958 let expr = runtime
1959 .compile("covariance(`[1, 2, 3]`, `[1, 2, 3]`)")
1960 .unwrap();
1961 let result = expr.search(&Variable::Null).unwrap();
1962 assert!((result.as_number().unwrap() - 0.666666).abs() < 0.01);
1964 }
1965
1966 #[test]
1967 fn test_covariance_negative() {
1968 let runtime = setup_runtime();
1969 let expr = runtime
1970 .compile("covariance(`[1, 2, 3]`, `[3, 2, 1]`)")
1971 .unwrap();
1972 let result = expr.search(&Variable::Null).unwrap();
1973 assert!((result.as_number().unwrap() - (-0.666666)).abs() < 0.01);
1974 }
1975
1976 #[test]
1977 fn test_standardize() {
1978 let runtime = setup_runtime();
1979 let expr = runtime
1980 .compile("standardize(`[10, 20, 30, 40, 50]`)")
1981 .unwrap();
1982 let result = expr.search(&Variable::Null).unwrap();
1983 let arr = result.as_array().unwrap();
1984 assert_eq!(arr.len(), 5);
1985 assert!((arr[0].as_number().unwrap() - (-1.414)).abs() < 0.01);
1988 assert!(arr[2].as_number().unwrap().abs() < 0.001);
1990 assert!((arr[4].as_number().unwrap() - 1.414).abs() < 0.01);
1992 }
1993}