1use std::collections::HashMap;
4use std::sync::Arc;
5
6use super::expression_evaluation_context::IExpressionForeignFunctionInterface;
7use super::expression_variant::{ExpressionVariant, ExpressionVariantValue, VariantType};
8
9type FfiDelegate = Arc<dyn Fn(&[ExpressionVariant]) -> ExpressionVariant + Send + Sync>;
11
12struct FfiRecord {
13 types: Vec<VariantType>,
14 delegate: FfiDelegate,
15}
16
17#[derive(Default)]
26pub struct DelegateExpressionFfi {
27 registry: HashMap<String, HashMap<usize, Vec<FfiRecord>>>,
28}
29
30fn type_of<T: ExpressionVariantValue>() -> VariantType {
35 match T::FFI_VARIANT_TYPE {
36 Some(t) => t,
37 None => panic!(
38 "{} cannot be a parameter of an expression foreign function",
39 std::any::type_name::<T>()
40 ),
41 }
42}
43
44macro_rules! add_overload {
47 ($(#[$meta:meta])* $name:ident; $($t:ident => $index:expr),+) => {
48 $(#[$meta])*
49 pub fn $name<$($t,)+ R, F>(&mut self, name: &str, cb: F)
50 where
51 $($t: ExpressionVariantValue,)+
52 R: Into<ExpressionVariant>,
53 F: Fn($($t),+) -> R + Send + Sync + 'static,
54 {
55 self.add(
56 name,
57 Arc::new(move |args: &[ExpressionVariant]| {
58 cb($(args[$index].cast_or_default::<$t>()),+).into()
59 }),
60 vec![$(type_of::<$t>()),+],
61 );
62 }
63 };
64}
65
66impl DelegateExpressionFfi {
67 pub fn new() -> Self {
69 Self::default()
70 }
71
72 fn call_with_cast(
73 count_group: &[FfiRecord],
74 arguments: &[ExpressionVariant],
75 any_cast: bool,
76 ) -> Option<ExpressionVariant> {
77 for record in count_group {
78 let mut matches = true;
79 for (c, argument) in arguments.iter().enumerate() {
80 let parameter = record.types[c];
81 let arg = argument.variant_type();
82 if parameter != arg {
83 let can_cast = (parameter == VariantType::Vector3D && arg == VariantType::Vector3)
84 || (parameter == VariantType::Vector && arg == VariantType::Vector2)
85 || (any_cast
86 && ((arg == VariantType::Vector3D && parameter == VariantType::Vector3)
87 || (arg == VariantType::Vector && parameter == VariantType::Vector2)));
88 if !can_cast {
89 matches = false;
90 break;
91 }
92 }
93 }
94
95 if matches {
96 return Some((record.delegate)(arguments));
97 }
98 }
99
100 if !any_cast {
101 return Self::call_with_cast(count_group, arguments, true);
102 }
103 None
104 }
105
106 fn add(&mut self, name: &str, cb: FfiDelegate, types: Vec<VariantType>) {
107 self.registry
108 .entry(name.to_owned())
109 .or_default()
110 .entry(types.len())
111 .or_default()
112 .push(FfiRecord { types, delegate: cb });
113 }
114
115 pub fn add0<R, F>(&mut self, name: &str, cb: F)
117 where
118 R: Into<ExpressionVariant>,
119 F: Fn() -> R + Send + Sync + 'static,
120 {
121 self.add(name, Arc::new(move |_: &[ExpressionVariant]| cb().into()), Vec::new());
122 }
123
124 add_overload!(
125 add1; T1 => 0
127 );
128 add_overload!(
129 add2; T1 => 0, T2 => 1
131 );
132 add_overload!(
133 add3; T1 => 0, T2 => 1, T3 => 2
135 );
136 add_overload!(
137 add4; T1 => 0, T2 => 1, T3 => 2, T4 => 3
139 );
140 add_overload!(
141 add5; T1 => 0, T2 => 1, T3 => 2, T4 => 3, T5 => 4
143 );
144 add_overload!(
145 add6; T1 => 0, T2 => 1, T3 => 2, T4 => 3, T5 => 4, T6 => 4
150 );
151 add_overload!(
152 add16;
157 T1 => 0, T2 => 1, T3 => 2, T4 => 3,
158 T5 => 4, T6 => 4, T7 => 4, T8 => 4,
159 T9 => 4, T10 => 4, T11 => 4, T12 => 4,
160 T13 => 4, T14 => 4, T15 => 4, T16 => 4
161 );
162}
163
164impl IExpressionForeignFunctionInterface for DelegateExpressionFfi {
165 fn call(&self, name: &str, arguments: &[ExpressionVariant]) -> Option<ExpressionVariant> {
166 let name_group = self.registry.get(name)?;
167 let count_group = name_group.get(&arguments.len())?;
168 for record in count_group {
169 let mut matches = true;
170 for (c, argument) in arguments.iter().enumerate() {
171 if record.types[c] != argument.variant_type() {
172 matches = false;
173 break;
174 }
175 }
176
177 if matches {
178 return Some((record.delegate)(arguments));
179 }
180 }
181
182 Self::call_with_cast(count_group, arguments, false)
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189 use crate::numerics::{Vector2, Vector3};
190 use crate::{Matrix, Vector, Vector3D};
191
192 fn call(ffi: &DelegateExpressionFfi, name: &str, args: &[ExpressionVariant]) -> Option<ExpressionVariant> {
193 ffi.call(name, args)
194 }
195
196 #[test]
197 fn selects_the_overload_by_name_count_and_types() {
198 let mut ffi = DelegateExpressionFfi::new();
199 ffi.add0("F", || 0.0f32);
200 ffi.add1("F", |a: f32| a + 1.0);
201 ffi.add1("F", |a: Vector2| a.x + a.y);
202 ffi.add2("F", |a: f32, b: bool| if b { a } else { -a });
203
204 assert_eq!(call(&ffi, "F", &[]), Some(0.0.into()));
205 assert_eq!(call(&ffi, "F", &[2.0.into()]), Some(3.0.into()));
206 assert_eq!(call(&ffi, "F", &[Vector2::new(1.0, 2.0).into()]), Some(3.0.into()));
207 assert_eq!(call(&ffi, "F", &[2.0.into(), false.into()]), Some((-2.0).into()));
208 assert_eq!(call(&ffi, "F", &[true.into()]), None);
209 assert_eq!(call(&ffi, "F", &[2.0.into(), 2.0.into()]), None);
210 assert_eq!(call(&ffi, "F", &[2.0.into(), false.into(), 1.0.into()]), None);
211 assert_eq!(call(&ffi, "G", &[]), None);
212 assert_eq!(call(&ffi, "f", &[]), None);
213 }
214
215 #[test]
216 fn the_first_registered_of_equal_signatures_wins() {
217 let mut ffi = DelegateExpressionFfi::new();
218 ffi.add1("F", |a: f32| a);
219 ffi.add1("F", |a: f64| a * 2.0);
220 assert_eq!(call(&ffi, "F", &[0.1.into()]), Some((0.1f32 as f64).into()));
223 }
224
225 #[test]
226 fn widens_single_precision_vectors_before_narrowing() {
227 let mut ffi = DelegateExpressionFfi::new();
228 ffi.add1("Wide", |a: Vector| a.x);
229 ffi.add1("Wide3", |a: Vector3D| a.z);
230 ffi.add1("Narrow", |a: Vector2| a.x);
231 ffi.add1("Narrow3", |a: Vector3| a.z);
232 ffi.add2("Both", |a: Vector2, _b: Vector2| a.x);
233 ffi.add2("Both", |a: Vector, _b: Vector| a.x + 100.0);
234
235 assert_eq!(call(&ffi, "Wide", &[Vector2::new(1.5, 0.0).into()]), Some(1.5.into()));
236 assert_eq!(
237 call(&ffi, "Wide3", &[Vector3::new(0.0, 0.0, 2.5).into()]),
238 Some(2.5.into())
239 );
240 assert_eq!(call(&ffi, "Narrow", &[Vector::new(1.5, 0.0).into()]), Some(1.5.into()));
241 assert_eq!(
242 call(&ffi, "Narrow3", &[Vector3D::new(0.0, 0.0, 2.5).into()]),
243 Some(2.5.into())
244 );
245 assert_eq!(
247 call(
248 &ffi,
249 "Both",
250 &[Vector2::new(1.0, 0.0).into(), Vector::new(0.0, 0.0).into()]
251 ),
252 Some(101.0.into())
253 );
254 assert_eq!(call(&ffi, "Wide", &[Vector3::new(1.0, 2.0, 3.0).into()]), None);
255 }
256
257 #[test]
258 fn parameters_past_the_fifth_read_the_fifth_argument() {
259 let mut ffi = DelegateExpressionFfi::new();
260 ffi.add5("F", |a: f32, b: f32, c: f32, d: f32, e: f32| {
261 a + 10.0 * b + 100.0 * c + 1000.0 * d + 10000.0 * e
262 });
263 ffi.add6("F", |_a: f32, _b: f32, _c: f32, _d: f32, e: f32, f: f32| e * 10.0 + f);
264 let args: Vec<ExpressionVariant> = (1..=6).map(|v| (v as f64).into()).collect();
265 assert_eq!(call(&ffi, "F", &args[..5]), Some(54321.0.into()));
266 assert_eq!(call(&ffi, "F", &args), Some(55.0.into()));
267 }
268
269 #[test]
270 #[should_panic(expected = "cannot be a parameter")]
271 fn the_3x3_matrix_cannot_be_a_parameter() {
272 let mut ffi = DelegateExpressionFfi::new();
273 ffi.add1("F", |m: Matrix| m);
274 }
275
276 #[test]
277 fn is_shareable_between_threads() {
278 fn assert_send_sync<T: Send + Sync>() {}
279 assert_send_sync::<DelegateExpressionFfi>();
280 }
281}