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_list_do_int_or_do_float(
32 arr,
33 |arr| {
34 let mut x = crate::array_to_vec_int(arr);
35 x.sort();
36 x.dedup();
37 Ok(x.iter().map(|el| Dynamic::from_int(*el)).collect())
38 },
39 |arr| {
40 let mut x = crate::array_to_vec_float(arr);
41 x.sort_by(|a, b| a.partial_cmp(b).unwrap());
42 x.dedup();
43 Ok(x.iter().map(|el| Dynamic::from_float(*el)).collect())
44 },
45 )
46 }
47
48 #[rhai_fn(name = "interp1", return_raw)]
61 pub fn interp1(x: &mut Array, y: Array, xq: Dynamic) -> Result<FLOAT, Box<EvalAltResult>> {
62 let new_xq = if xq.is_int() {
63 xq.as_int().unwrap() as FLOAT
64 } else if xq.is_float() {
65 xq.as_float().unwrap()
66 } else {
67 return Err(EvalAltResult::ErrorArithmetic(
68 "xq must be either INT or FLOAT".to_string(),
69 Position::NONE,
70 )
71 .into());
72 };
73
74 if x.len() < 2 {
75 return Err(EvalAltResult::ErrorArithmetic(
76 "The arrays must have at least 2 elements".to_string(),
77 Position::NONE,
78 )
79 .into());
80 }
81 if x.len() != y.len() {
82 return Err(EvalAltResult::ErrorArithmetic(
83 "The arrays must have the same length".to_string(),
84 Position::NONE,
85 )
86 .into());
87 }
88
89 let mut y = y;
90
91 if_list_convert_to_vec_float_and_do(&mut y, |new_y| {
92 if_list_convert_to_vec_float_and_do(x, |new_x| {
93 if new_xq >= *new_x.last().unwrap() {
94 return Ok(*new_y.last().unwrap());
95 } else if new_xq <= *new_x.first().unwrap() {
96 return Ok(*new_y.first().unwrap());
97 }
98
99 let b = new_x
101 .iter()
102 .enumerate()
103 .find_map(|(i, &el)| (el >= new_xq).then(|| i))
104 .unwrap();
105
106 let a = b - 1;
107 Ok(new_y[a] + (new_xq - new_x[a]) * (new_y[b] - new_y[a]) / (new_x[b] - new_x[a]))
108 })
109 })
110 }
111}