1use rhai::plugin::*;
2
3#[export_module]
4pub mod misc_functions {
5 use crate::{if_list_convert_to_vec_float_and_do, if_list_do_int_or_do_float};
6 use rhai::{Array, Dynamic, EvalAltResult, Position, FLOAT};
7
8 #[allow(non_upper_case_globals)]
10 pub const inf: FLOAT = FLOAT::INFINITY;
11
12 #[cfg(feature = "rand")]
18 #[rhai_fn(name = "rand")]
19 pub fn rand_float() -> FLOAT {
20 randlib::random()
21 }
22
23 #[rhai_fn(name = "unique", return_raw, pure)]
30 pub fn unique(arr: &mut Array) -> Result<Array, Box<EvalAltResult>> {
31 if arr.is_empty() {
32 return Ok(Array::new());
33 }
34 if_list_do_int_or_do_float(
35 arr,
36 |arr| {
37 let mut x = crate::array_to_vec_int(arr);
38 x.sort();
39 x.dedup();
40 Ok(x.iter().map(|el| Dynamic::from_int(*el)).collect())
41 },
42 |arr| {
43 let mut x = crate::array_to_vec_float(arr);
44 x.sort_by(|a, b| a.partial_cmp(b).unwrap());
45 x.dedup();
46 Ok(x.iter().map(|el| Dynamic::from_float(*el)).collect())
47 },
48 )
49 }
50
51 #[rhai_fn(name = "interp1", return_raw)]
64 pub fn interp1(x: &mut Array, y: Array, xq: Dynamic) -> Result<FLOAT, Box<EvalAltResult>> {
65 let new_xq = if xq.is_int() {
66 xq.as_int().unwrap() as FLOAT
67 } else if xq.is_float() {
68 xq.as_float().unwrap()
69 } else {
70 return Err(EvalAltResult::ErrorArithmetic(
71 "xq must be either INT or FLOAT".to_string(),
72 Position::NONE,
73 )
74 .into());
75 };
76
77 let mut y = y;
78
79 if_list_convert_to_vec_float_and_do(&mut y, |new_y| {
80 if_list_convert_to_vec_float_and_do(x, |new_x| {
81 if new_x.len() < 2 {
82 return Err(EvalAltResult::ErrorArithmetic(
83 "The arrays must have at least 2 elements".to_string(),
84 Position::NONE,
85 )
86 .into());
87 }
88 if new_x.len() != new_y.len() {
89 return Err(EvalAltResult::ErrorArithmetic(
90 "The arrays must have the same length".to_string(),
91 Position::NONE,
92 )
93 .into());
94 }
95
96 if new_xq >= *new_x.last().unwrap() {
97 return Ok(*new_y.last().unwrap());
98 } else if new_xq <= *new_x.first().unwrap() {
99 return Ok(*new_y.first().unwrap());
100 }
101
102 let b = new_x
104 .iter()
105 .enumerate()
106 .find_map(|(i, &el)| (el >= new_xq).then(|| i))
107 .unwrap();
108
109 let a = b - 1;
110 Ok(new_y[a] + (new_xq - new_x[a]) * (new_y[b] - new_y[a]) / (new_x[b] - new_x[a]))
111 })
112 })
113 }
114}