json_eval_rs/rlogic/evaluator/
math_ops.rs1use super::Evaluator;
2use serde_json::Value;
3use super::super::compiled::CompiledLogic;
4use super::helpers;
5
6impl Evaluator {
7 pub(super) fn eval_min_max(&self, items: &[CompiledLogic], is_max: bool, user_data: &Value, internal_context: &Value, depth: usize) -> Result<Value, String> {
9 if items.is_empty() {
10 return Ok(Value::Null);
11 }
12 let first_val = self.evaluate_with_context(&items[0], user_data, internal_context, depth + 1)?;
13 let mut result = helpers::to_f64(&first_val);
14 for item in &items[1..] {
15 let val = self.evaluate_with_context(item, user_data, internal_context, depth + 1)?;
16 let num = helpers::to_f64(&val);
17 if is_max {
18 if num > result { result = num; }
19 } else {
20 if num < result { result = num; }
21 }
22 }
23 Ok(self.f64_to_json(result))
24 }
25
26 #[inline]
29 pub(super) fn apply_round(&self, expr: &CompiledLogic, decimals_expr: &Option<Box<CompiledLogic>>, round_type: u8, user_data: &Value, internal_context: &Value, depth: usize) -> Result<Value, String> {
30 let val = self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
31 let num = helpers::to_f64(&val);
32
33 let decimals = if let Some(dec_expr) = decimals_expr {
34 let dec_val = self.evaluate_with_context(dec_expr, user_data, internal_context, depth + 1)?;
35 helpers::to_number(&dec_val) as i32
36 } else {
37 0
38 };
39
40 let result = if decimals == 0 {
41 match round_type {
43 0 => num.round(),
44 1 => num.ceil(),
45 2 => num.floor(),
46 _ => num
47 }
48 } else if decimals > 0 {
49 let multiplier = 10f64.powi(decimals);
51 match round_type {
52 0 => (num * multiplier).round() / multiplier,
53 1 => (num * multiplier).ceil() / multiplier,
54 2 => (num * multiplier).floor() / multiplier,
55 _ => num
56 }
57 } else {
58 let divider = 10f64.powi(-decimals);
60 match round_type {
61 0 => (num / divider).round() * divider,
62 1 => (num / divider).ceil() * divider,
63 2 => (num / divider).floor() * divider,
64 _ => num
65 }
66 };
67
68 Ok(self.f64_to_json(result))
69 }
70
71 pub(super) fn eval_ceiling(&self, expr: &CompiledLogic, significance_expr: &Option<Box<CompiledLogic>>, user_data: &Value, internal_context: &Value, depth: usize) -> Result<Value, String> {
73 let val = self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
74 let num = helpers::to_f64(&val);
75
76 let significance = if let Some(sig_expr) = significance_expr {
77 let sig_val = self.evaluate_with_context(sig_expr, user_data, internal_context, depth + 1)?;
78 helpers::to_f64(&sig_val)
79 } else {
80 1.0
81 };
82
83 if significance == 0.0 {
84 return Ok(Value::Number(serde_json::Number::from(0)));
85 }
86
87 let result = (num / significance).ceil() * significance;
88 Ok(self.f64_to_json(result))
89 }
90
91 pub(super) fn eval_floor(&self, expr: &CompiledLogic, significance_expr: &Option<Box<CompiledLogic>>, user_data: &Value, internal_context: &Value, depth: usize) -> Result<Value, String> {
93 let val = self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
94 let num = helpers::to_f64(&val);
95
96 let significance = if let Some(sig_expr) = significance_expr {
97 let sig_val = self.evaluate_with_context(sig_expr, user_data, internal_context, depth + 1)?;
98 helpers::to_f64(&sig_val)
99 } else {
100 1.0
101 };
102
103 if significance == 0.0 {
104 return Ok(Value::Number(serde_json::Number::from(0)));
105 }
106
107 let result = (num / significance).floor() * significance;
108 Ok(self.f64_to_json(result))
109 }
110
111 pub(super) fn eval_trunc(&self, expr: &CompiledLogic, decimals_expr: &Option<Box<CompiledLogic>>, user_data: &Value, internal_context: &Value, depth: usize) -> Result<Value, String> {
113 let val = self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
114 let num = helpers::to_f64(&val);
115
116 let decimals = if let Some(dec_expr) = decimals_expr {
117 let dec_val = self.evaluate_with_context(dec_expr, user_data, internal_context, depth + 1)?;
118 helpers::to_number(&dec_val) as i32
119 } else {
120 0
121 };
122
123 let result = if decimals == 0 {
124 num.trunc()
125 } else if decimals > 0 {
126 let multiplier = 10f64.powi(decimals);
127 (num * multiplier).trunc() / multiplier
128 } else {
129 let divider = 10f64.powi(-decimals);
130 (num / divider).trunc() * divider
131 };
132
133 Ok(self.f64_to_json(result))
134 }
135
136 pub(super) fn eval_mround(&self, value_expr: &CompiledLogic, multiple_expr: &CompiledLogic, user_data: &Value, internal_context: &Value, depth: usize) -> Result<Value, String> {
138 let val = self.evaluate_with_context(value_expr, user_data, internal_context, depth + 1)?;
139 let num = helpers::to_f64(&val);
140
141 let multiple_val = self.evaluate_with_context(multiple_expr, user_data, internal_context, depth + 1)?;
142 let multiple = helpers::to_f64(&multiple_val);
143
144 if multiple == 0.0 {
145 return Ok(Value::Number(serde_json::Number::from(0)));
146 }
147
148 let result = (num / multiple).round() * multiple;
149 Ok(self.f64_to_json(result))
150 }
151
152 #[inline]
154 pub(super) fn eval_unary_math<F>(&self, expr: &CompiledLogic, f: F, user_data: &Value, internal_context: &Value, depth: usize) -> Result<Value, String>
155 where F: FnOnce(f64) -> f64
156 {
157 let val = self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
158 let num = helpers::to_f64(&val);
159 Ok(self.f64_to_json(f(num)))
160 }
161
162 pub(super) fn eval_pow(&self, base_expr: &CompiledLogic, exp_expr: &CompiledLogic, user_data: &Value, internal_context: &Value, depth: usize) -> Result<Value, String> {
164 self.eval_binary_arith(base_expr, exp_expr, |a, b| Some(a.powf(b)), user_data, internal_context, depth)
165 }
166}