rubble_templates/std_fun/
math.rs1use std::collections::HashMap;
6use rubble_templates_core::evaluator::{Function, Context, SyntaxError, EvaluationError};
7use rubble_templates_core::functions::{SimpleFunction, FunctionWithContext};
8use std::num::ParseFloatError;
9use crate::std_fun::strings::EMPTY_STRING;
10
11pub fn math_functions() -> HashMap<String, Box<dyn Function>> {
20 let mut functions: HashMap<String, Box<dyn Function>> = HashMap::new();
21 functions.insert("+".to_string(), SimpleFunction::new(plus_function));
22 functions.insert("-".to_string(), FunctionWithContext::new(minus_function));
23 functions.insert("*".to_string(), FunctionWithContext::new(multiply_function));
24 functions.insert("/".to_string(), FunctionWithContext::new(divide_function));
25 functions.insert("mod".to_string(), FunctionWithContext::new(modulo_function));
26 functions
27}
28
29pub fn plus_function(parameters: &[String]) -> String {
43 let mut result: String = EMPTY_STRING.to_string();
44 let mut floating_result: Option<f64> = None;
45
46 parameters.iter().for_each(|param| {
47 if result.is_empty() {
48 if let Result::Ok(value) = param.parse::<f64>() {
49 floating_result = Some(floating_result.unwrap_or(0 as f64) + value);
50 } else {
51 if let Some(number) = floating_result
52 .map(|number| number.to_string()) {
53 result += &number
54 }
55
56 result.push_str(param);
57 }
58 } else {
59 result.push_str(param);
60 };
61 });
62
63 if result.is_empty() && floating_result.is_some() {
64 floating_result.map(|number| number.to_string()).unwrap()
65 } else {
66 result
67 }
68}
69
70pub fn minus_function(parameters: &[String], _context: &mut Context) -> Result<String, SyntaxError> {
82 reduce_numbers(parameters, |a, b| a - b)
83}
84
85pub fn multiply_function(parameters: &[String], _context: &mut Context) -> Result<String, SyntaxError> {
97 reduce_numbers(parameters, |a, b| a * b)
98}
99
100pub fn divide_function(parameters: &[String], _context: &mut Context) -> Result<String, SyntaxError> {
112 reduce_numbers(parameters, |a, b| a / b)
113}
114
115pub fn modulo_function(parameters: &[String], _context: &mut Context) -> Result<String, SyntaxError> {
127 reduce_numbers(parameters, |a, b| a % b)
128}
129
130pub fn reduce_numbers<F>(parameters: &[String], f: F) -> Result<String, SyntaxError>
131 where F: Fn(f64, f64) -> f64 {
132 let (index, numbers) = as_numbers(parameters);
133
134 if let Result::Err(error) = numbers {
135 Err(SyntaxError::new(EvaluationError::InvalidValues {
136 description: Some(error.to_string()),
137 values: vec![parameters[index - 1].clone()],
138 })
139 )
140 } else {
141 Ok(numbers.unwrap()
142 .into_iter()
143 .reduce(f)
144 .unwrap_or(0 as f64)
145 .to_string()
146 )
147 }
148}
149
150pub fn as_numbers(parameters: &[String]) -> (usize, Result<Vec<f64>, ParseFloatError>) {
151 let mut index: usize = 0;
152 let numbers: Result<Vec<f64>, ParseFloatError> = parameters.iter()
153 .map(|number| {
154 index += 1;
155 number.parse::<f64>()
156 })
157 .collect();
158
159 (index, numbers)
160}