1use rhai::{Array, Dynamic, EvalAltResult, Position, FLOAT, INT};
2
3#[allow(dead_code)]
5pub enum FOIL {
6 First,
8 Outside,
10 Inside,
12 Last,
14}
15
16pub fn int_and_float_totals(arr: &mut Array) -> (INT, INT, INT) {
17 crate::matrix_functions::flatten(arr)
18 .iter()
19 .fold((0, 0, 0), |(i, f, t), x| {
20 if x.is_int() {
21 (i + 1, f, t + 1)
22 } else if x.is_float() {
23 (i, f + 1, t + 1)
24 } else {
25 (i, f, t + 1)
26 }
27 })
28}
29
30pub fn if_list_do_int_or_do_float<FA, FB, T>(
31 arr: &mut Array,
32 mut f_int: FA,
33 mut f_float: FB,
34) -> Result<T, Box<EvalAltResult>>
35where
36 FA: FnMut(&mut Array) -> Result<T, Box<EvalAltResult>>,
37 FB: FnMut(&mut Array) -> Result<T, Box<EvalAltResult>>,
38{
39 let (int, float, total) = int_and_float_totals(arr);
40 if int == total {
41 f_int(arr)
42 } else if float == total {
43 f_float(arr)
44 } else if float + int == total {
45 let mut arr_of_float = arr
46 .iter()
47 .map(|el| {
48 Dynamic::from_float(if el.is_int() {
49 el.as_int().unwrap() as FLOAT
50 } else if el.is_float() {
51 el.as_float().unwrap()
52 } else {
53 unreachable!("This should never happen!");
54 })
55 })
56 .collect::<Array>();
57 f_float(&mut arr_of_float)
58 } else {
59 Err(EvalAltResult::ErrorArithmetic(
60 "The elements of the input array must either be INT or FLOAT".to_string(),
61 Position::NONE,
62 )
63 .into())
64 }
65}
66
67pub fn if_list_do<F, T>(arr: &mut Array, mut f: F) -> Result<T, Box<EvalAltResult>>
69where
70 F: FnMut(&mut Array) -> Result<T, Box<EvalAltResult>>,
71{
72 crate::validation_functions::is_numeric_list(arr)
73 .then(|| f(arr))
74 .unwrap_or(Err(EvalAltResult::ErrorArithmetic(
75 format!("The elements of the input array must either be INT or FLOAT."),
76 Position::NONE,
77 )
78 .into()))
79}
80
81pub fn if_list_convert_to_vec_float_and_do<F, T>(
82 arr: &mut Array,
83 f: F,
84) -> Result<T, Box<EvalAltResult>>
85where
86 F: FnMut(Vec<FLOAT>) -> Result<T, Box<EvalAltResult>>,
87{
88 if_list_do_int_or_do_float(
89 arr,
90 |arr: &mut Array| Ok(arr.iter().map(|el| el.as_int().unwrap() as FLOAT).collect()),
91 |arr: &mut Array| Ok(arr.iter().map(|el| el.as_float().unwrap()).collect()),
92 )
93 .and_then(f)
94}
95
96pub fn if_int_convert_to_float_and_do<F, T>(x: Dynamic, mut f: F) -> Result<T, Box<EvalAltResult>>
99where
100 F: FnMut(FLOAT) -> Result<T, Box<EvalAltResult>>,
101{
102 let new_x: FLOAT = if x.is_float() {
103 x.as_float().unwrap()
104 } else if x.is_int() {
105 x.as_int().unwrap() as FLOAT
106 } else {
107 return Err(EvalAltResult::ErrorArithmetic(
108 "The input must either be INT or FLOAT".to_string(),
109 Position::NONE,
110 )
111 .into());
112 };
113 f(new_x)
114}
115
116#[cfg(feature = "nalgebra")]
117pub fn if_matrix_do<T, F>(matrix: &mut Array, mut f: F) -> Result<T, Box<EvalAltResult>>
118where
119 F: FnMut(&mut Array) -> Result<T, Box<EvalAltResult>>,
120{
121 crate::validation_functions::is_matrix(matrix)
122 .then(|| f(matrix))
123 .unwrap_or(Err(EvalAltResult::ErrorArithmetic(
124 format!("The input must be a matrix."),
125 Position::NONE,
126 )
127 .into()))
128}
129
130#[cfg(feature = "nalgebra")]
131pub fn if_matrices_and_compatible_convert_to_vec_array_and_do<T, F>(
132 compatibility_condition: FOIL,
133 matrix1: &mut Array,
134 matrix2: &mut Array,
135 mut f: F,
136) -> Result<T, Box<EvalAltResult>>
137where
138 F: FnMut(Vec<Array>, Vec<Array>) -> Result<T, Box<EvalAltResult>>,
139{
140 if crate::validation_functions::is_matrix(matrix1) {
141 if crate::validation_functions::is_matrix(matrix2) {
142 let s1 = crate::matrix_functions::matrix_size_by_reference(matrix1);
143 let s2 = crate::matrix_functions::matrix_size_by_reference(matrix2);
144 if match compatibility_condition {
145 FOIL::First => s1[0].as_int().unwrap() == s2[0].as_int().unwrap(),
146 FOIL::Outside => s1[0].as_int().unwrap() == s2[1].as_int().unwrap(),
147 FOIL::Inside => s1[1].as_int().unwrap() == s2[0].as_int().unwrap(),
148 FOIL::Last => s1[1].as_int().unwrap() == s2[1].as_int().unwrap(),
149 } {
150 let matrix_as_vec1 = matrix1
152 .into_iter()
153 .map(|x| x.clone().into_array().unwrap())
154 .collect::<Vec<Array>>();
155 let matrix_as_vec2 = matrix2
157 .into_iter()
158 .map(|x| x.clone().into_array().unwrap())
159 .collect::<Vec<Array>>();
160 f(matrix_as_vec1, matrix_as_vec2)
161 } else {
162 Err(EvalAltResult::ErrorArithmetic(
163 "The input matrices are not compatible for this operation".to_string(),
164 Position::NONE,
165 )
166 .into())
167 }
168 } else {
169 Err(EvalAltResult::ErrorArithmetic(
170 "The second input must be a matrix".to_string(),
171 Position::NONE,
172 )
173 .into())
174 }
175 } else {
176 Err(EvalAltResult::ErrorArithmetic(
177 "The first input must be a matrix".to_string(),
178 Position::NONE,
179 )
180 .into())
181 }
182}
183
184pub fn if_matrix_convert_to_vec_array_and_do<F, T>(
186 matrix: &mut Array,
187 mut f: F,
188) -> Result<T, Box<EvalAltResult>>
189where
190 F: FnMut(Vec<Array>) -> Result<T, Box<EvalAltResult>>,
191{
192 let matrix_as_vec = matrix
193 .into_iter()
194 .map(|x| x.clone().into_array().unwrap())
195 .collect::<Vec<Array>>();
196 if crate::validation_functions::is_matrix(matrix) {
197 f(matrix_as_vec)
198 } else {
199 Err(EvalAltResult::ErrorArithmetic(
200 "The input must be a matrix".to_string(),
201 Position::NONE,
202 )
203 .into())
204 }
205}
206
207pub fn if_int_do_else_if_array_do<FA, FB, T>(
208 d: Dynamic,
209 mut f_int: FA,
210 mut f_array: FB,
211) -> Result<T, Box<EvalAltResult>>
212where
213 FA: FnMut(INT) -> Result<T, Box<EvalAltResult>>,
214 FB: FnMut(&mut Array) -> Result<T, Box<EvalAltResult>>,
215{
216 if d.is_int() {
217 f_int(d.as_int().unwrap())
218 } else if d.is_array() {
219 if_list_do(&mut d.into_array().unwrap(), |arr| f_array(arr))
220 } else {
221 Err(EvalAltResult::ErrorArithmetic(
222 "The input must be either an INT or an numeric array".to_string(),
223 Position::NONE,
224 )
225 .into())
226 }
227}
228
229pub fn array_to_vec_int(arr: &mut Array) -> Vec<INT> {
230 arr.iter()
231 .map(|el| el.as_int().unwrap())
232 .collect::<Vec<INT>>()
233}
234
235pub fn array_to_vec_float(arr: &mut Array) -> Vec<FLOAT> {
236 arr.into_iter()
237 .map(|el| el.as_float().unwrap())
238 .collect::<Vec<FLOAT>>()
239}
240
241#[cfg(feature = "nalgebra")]
242pub fn omatrix_to_vec_dynamic(
243 mat: nalgebralib::OMatrix<FLOAT, nalgebralib::Dyn, nalgebralib::Dyn>,
244) -> Vec<Dynamic> {
245 let mut out = vec![];
246 for idx in 0..mat.shape().0 {
247 let mut new_row = vec![];
248 for jdx in 0..mat.shape().1 {
249 new_row.push(Dynamic::from_float(mat[(idx, jdx)]));
250 }
251 out.push(Dynamic::from_array(new_row));
252 }
253 out
254}
255
256#[cfg(feature = "nalgebra")]
257pub fn ovector_to_vec_dynamic(mat: nalgebralib::OVector<FLOAT, nalgebralib::Dyn>) -> Vec<Dynamic> {
258 let mut out = vec![];
259 for idx in 0..mat.shape().0 {
260 out.push(Dynamic::from_float(mat[idx]));
261 }
262 out
263}