1use crate::{
2 for_all_tuples,
3 value::ValueType,
4 value::{Load, Store},
5 ExprContext, Type, TypeSet, TypedValue,
6};
7
8pub enum FunctionCallError {
10 FunctionNotFound,
12
13 IncorrectArgumentCount {
15 expected: usize,
17 },
18
19 IncorrectArgumentType {
21 idx: usize,
23 expected: Type,
25 },
26
27 Other(&'static str),
29}
30
31#[doc(hidden)]
32pub trait DynFunction<A, T>
33where
34 T: TypeSet,
35 T::Integer: ValueType,
36 T::Float: ValueType,
37{
38 fn call(
39 &self,
40 ctx: &mut dyn ExprContext<T>,
41 args: &[TypedValue<T>],
42 ) -> Result<TypedValue<T>, FunctionCallError>;
43}
44
45macro_rules! ignore {
46 ($arg:tt) => {};
47}
48
49for_all_tuples! {
50 ($($arg:ident),*) => {
51 impl<$($arg,)* R, F, T> DynFunction<($($arg,)*), T> for F
52 where
53 $($arg: ValueType + Load<T>,)*
54 F: Fn($($arg,)*) -> R,
58 F: for<'t> Fn($($arg::Output<'t>,)*) -> R,
59 R: ValueType + Store<T>,
60 T: TypeSet,
61 T::Integer: ValueType,
62 T::Float: ValueType,
63 {
64 #[allow(non_snake_case, unused)]
65 fn call(&self, ctx: &mut dyn ExprContext<T>, args: &[TypedValue<T>]) -> Result<TypedValue<T>, FunctionCallError> {
66 let arg_count = 0;
67 $(
68 ignore!($arg);
69 let arg_count = arg_count + 1;
70 )*
71
72 let idx = 0;
73 let mut args = args.iter().cloned();
74 $(
75 let Some(arg) = args.next() else {
76 return Err(FunctionCallError::IncorrectArgumentCount { expected: arg_count });
77 };
78 let $arg = match <$arg>::load(ctx, arg) {
79 Some(arg) => arg,
80 None => return Err(FunctionCallError::IncorrectArgumentType { idx, expected: $arg::TYPE }),
81 };
82 let idx = idx + 1;
83 )*
84
85 if args.next().is_some() {
86 return Err(FunctionCallError::IncorrectArgumentCount { expected: arg_count });
87 }
88
89 Ok(self($($arg),*).store(ctx))
90 }
91 }
92 };
93}
94
95pub(crate) struct ExprFn<'ctx, T>
96where
97 T: TypeSet,
98 T::Integer: ValueType,
99 T::Float: ValueType,
100{
101 #[allow(clippy::type_complexity)]
102 func: Box<
103 dyn Fn(
104 &mut dyn ExprContext<T>,
105 &[TypedValue<T>],
106 ) -> Result<TypedValue<T>, FunctionCallError>
107 + 'ctx,
108 >,
109}
110
111impl<'ctx, T> ExprFn<'ctx, T>
112where
113 T: TypeSet,
114 T::Integer: ValueType,
115 T::Float: ValueType,
116{
117 pub fn new<A, F>(func: F) -> Self
118 where
119 F: DynFunction<A, T> + 'ctx,
120 {
121 Self {
122 func: Box::new(move |ctx, args| func.call(ctx, args)),
123 }
124 }
125
126 pub fn call(
127 &self,
128 ctx: &mut dyn ExprContext<T>,
129 args: &[TypedValue<T>],
130 ) -> Result<TypedValue<T>, FunctionCallError> {
131 (self.func)(ctx, args)
132 }
133}