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