aimx/functions/
macros.rs

1//! Macros for registering AIMX functions with the function registry.
2//!
3//! These macros generate [`FunctionHandler`](crate::functions::FunctionHandler)
4//! implementations that convert [`Value`](crate::values::Value) arguments, enforce arity,
5//! and register handlers in [`FunctionRegistry`](crate::functions::FunctionRegistry).
6//! Intended for defining built-in functions, not for general API users.
7
8/// Define a function that returns `Result<T, E>`.
9
10/// Expands to a `FunctionHandler` that:
11/// - Validates argument count (0–4).
12/// - Converts [`Value`](crate::values::Value) arguments to the specified Rust types.
13/// - Executes `$body` and maps `Ok(T)` into `Value` via `Into<Value>`.
14#[macro_export]
15macro_rules! define_function {
16    // No arguments
17    ($name:ident, args: [], $body:expr) => {
18        |registry: &mut $crate::functions::FunctionRegistry| {
19            struct Handler;
20            impl $crate::functions::FunctionHandler for Handler {
21                fn call(
22                    &self,
23                    _context: &mut dyn $crate::aim::ContextLike,
24                    _args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
25                ) -> Result<$crate::values::Value, anyhow::Error> {
26                    let result: anyhow::Result<_> = $body;
27                    result.map(|v| $crate::values::Value::from(v))
28                }
29            }
30            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
31        }
32    };
33
34    // One argument
35    ($name:ident, args: [$arg_type:ty], $body:expr) => {
36        |registry: &mut $crate::functions::FunctionRegistry| {
37            struct Handler;
38            impl $crate::functions::FunctionHandler for Handler {
39                fn call(
40                    &self,
41                    _context: &mut dyn $crate::aim::ContextLike,
42                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
43                ) -> Result<$crate::values::Value, anyhow::Error> {
44                    if args.len() < 1 {
45                        return Err(anyhow::anyhow!("Expected 1 argument, got {}", args.len()));
46                    }
47                    let arg0 = $crate::functions::convert_value_to_type::<
48                        $arg_type,
49                    >(args[0].clone())?;
50                    let result = $body(arg0);
51                    result.map(|v| $crate::values::Value::from(v))
52                }
53            }
54            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
55        }
56    };
57
58    // Two arguments
59    ($name:ident, args: [$arg_type1:ty, $arg_type2:ty], $body:expr) => {
60        |registry: &mut $crate::functions::FunctionRegistry| {
61            struct Handler;
62            impl $crate::functions::FunctionHandler for Handler {
63                fn call(
64                    &self,
65                    _context: &mut dyn $crate::aim::ContextLike,
66                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
67                ) -> Result<$crate::values::Value, anyhow::Error> {
68                    if args.len() < 2 {
69                        return Err(anyhow::anyhow!("Expected 2 arguments, got {}", args.len()));
70                    }
71                    let arg0 = $crate::functions::convert_value_to_type::<
72                        $arg_type1,
73                    >(args[0].clone())?;
74                    let arg1 = $crate::functions::convert_value_to_type::<
75                        $arg_type2,
76                    >(args[1].clone())?;
77                    let result = $body(arg0, arg1);
78                    result.map(|v| $crate::values::Value::from(v))
79                }
80            }
81            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
82        }
83    };
84
85    // Three arguments
86    ($name:ident, args: [$arg_type1:ty, $arg_type2:ty, $arg_type3:ty], $body:expr) => {
87        |registry: &mut $crate::functions::FunctionRegistry| {
88            struct Handler;
89            impl $crate::functions::FunctionHandler for Handler {
90                fn call(
91                    &self,
92                    _context: &mut dyn $crate::aim::ContextLike,
93                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
94                ) -> Result<$crate::values::Value, anyhow::Error> {
95                    if args.len() < 3 {
96                        return Err(anyhow::anyhow!("Expected 3 arguments, got {}", args.len()));
97                    }
98                    let arg0 = $crate::functions::convert_value_to_type::<
99                        $arg_type1,
100                    >(args[0].clone())?;
101                    let arg1 = $crate::functions::convert_value_to_type::<
102                        $arg_type2,
103                    >(args[1].clone())?;
104                    let arg2 = $crate::functions::convert_value_to_type::<
105                        $arg_type3,
106                    >(args[2].clone())?;
107                    let result = $body(arg0, arg1, arg2);
108                    result.map(|v| $crate::values::Value::from(v))
109                }
110            }
111            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
112        }
113    };
114
115    // Four arguments
116    ($name:ident, args: [$arg_type1:ty, $arg_type2:ty, $arg_type3:ty, $arg_type4:ty], $body:expr) => {
117        |registry: &mut $crate::functions::FunctionRegistry| {
118            struct Handler;
119            impl $crate::functions::FunctionHandler for Handler {
120                fn call(
121                    &self,
122                    _context: &mut dyn $crate::aim::ContextLike,
123                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
124                ) -> Result<$crate::values::Value, anyhow::Error> {
125                    if args.len() < 4 {
126                        return Err(anyhow::anyhow!("Expected 4 arguments, got {}", args.len()));
127                    }
128                    let arg0 = $crate::functions::convert_value_to_type::<
129                        $arg_type1,
130                    >(args[0].clone())?;
131                    let arg1 = $crate::functions::convert_value_to_type::<
132                        $arg_type2,
133                    >(args[1].clone())?;
134                    let arg2 = $crate::functions::convert_value_to_type::<
135                        $arg_type3,
136                    >(args[2].clone())?;
137                    let arg3 = $crate::functions::convert_value_to_type::<
138                        $arg_type4,
139                    >(args[3].clone())?;
140                    let result = $body(arg0, arg1, arg2, arg3);
141                    result.map(|v| $crate::values::Value::from(v))
142                }
143            }
144            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
145        }
146    };
147}
148
149/// Define a function that returns a direct value.
150///
151/// Expands to a `FunctionHandler` that:
152/// - Validates argument count (0–4).
153/// - Converts [`Value`](crate::values::Value) arguments to the specified Rust types.
154/// - Converts the returned value into [`Value`](crate::values::Value) via
155///   `convert_result_to_value`.
156#[macro_export]
157macro_rules! define_direct_function {
158    // No arguments
159    ($name:ident, args: [], $body:expr) => {
160        |registry: &mut $crate::functions::FunctionRegistry| {
161            struct Handler;
162            impl $crate::functions::FunctionHandler for Handler {
163                fn call(
164                    &self,
165                    _context: &mut dyn $crate::aim::ContextLike,
166                    _args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
167                ) -> Result<$crate::values::Value, anyhow::Error> {
168                    let result = $body;
169                    Ok($crate::values::Value::from(result))
170                }
171            }
172            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
173        }
174    };
175
176    // One argument
177    ($name:ident, args: [$arg_type:ty], $body:expr) => {
178        |registry: &mut $crate::functions::FunctionRegistry| {
179            struct Handler;
180            impl $crate::functions::FunctionHandler for Handler {
181                fn call(
182                    &self,
183                    _context: &mut dyn $crate::aim::ContextLike,
184                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
185                ) -> Result<$crate::values::Value, anyhow::Error> {
186                    if args.len() < 1 {
187                        return Err(anyhow::anyhow!("Expected 1 argument, got {}", args.len()));
188                    }
189                    let arg0 = $crate::functions::convert_value_to_type::<
190                        $arg_type,
191                    >(args[0].clone())?;
192                    let result = $body(arg0);
193                    Ok($crate::values::Value::from(result))
194                }
195            }
196            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
197        }
198    };
199
200    // Two arguments
201    ($name:ident, args: [$arg_type1:ty, $arg_type2:ty], $body:expr) => {
202        |registry: &mut $crate::functions::FunctionRegistry| {
203            struct Handler;
204            impl $crate::functions::FunctionHandler for Handler {
205                fn call(
206                    &self,
207                    _context: &mut dyn $crate::aim::ContextLike,
208                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
209                ) -> Result<$crate::values::Value, anyhow::Error> {
210                    if args.len() < 2 {
211                        return Err(anyhow::anyhow!("Expected 2 arguments, got {}", args.len()));
212                    }
213                    let arg0 = $crate::functions::convert_value_to_type::<
214                        $arg_type1,
215                    >(args[0].clone())?;
216                    let arg1 = $crate::functions::convert_value_to_type::<
217                        $arg_type2,
218                    >(args[1].clone())?;
219                    let result = $body(arg0, arg1);
220                    Ok($crate::values::Value::from(result))
221                }
222            }
223            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
224        }
225    };
226
227    // Three arguments
228    ($name:ident, args: [$arg_type1:ty, $arg_type2:ty, $arg_type3:ty], $body:expr) => {
229        |registry: &mut $crate::functions::FunctionRegistry| {
230            struct Handler;
231            impl $crate::functions::FunctionHandler for Handler {
232                fn call(
233                    &self,
234                    _context: &mut dyn $crate::aim::ContextLike,
235                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
236                ) -> Result<$crate::values::Value, anyhow::Error> {
237                    if args.len() < 3 {
238                        return Err(anyhow::anyhow!("Expected 3 arguments, got {}", args.len()));
239                    }
240                    let arg0 = $crate::functions::convert_value_to_type::<
241                        $arg_type1,
242                    >(args[0].clone())?;
243                    let arg1 = $crate::functions::convert_value_to_type::<
244                        $arg_type2,
245                    >(args[1].clone())?;
246                    let arg2 = $crate::functions::convert_value_to_type::<
247                        $arg_type3,
248                    >(args[2].clone())?;
249                    let result = $body(arg0, arg1, arg2);
250                    Ok($crate::values::Value::from(result))
251                }
252            }
253            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
254        }
255    };
256
257    // Four arguments
258    ($name:ident, args: [$arg_type1:ty, $arg_type2:ty, $arg_type3:ty, $arg_type4:ty], $body:expr) => {
259        |registry: &mut $crate::functions::FunctionRegistry| {
260            struct Handler;
261            impl $crate::functions::FunctionHandler for Handler {
262                fn call(
263                    &self,
264                    _context: &mut dyn $crate::aim::ContextLike,
265                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
266                ) -> Result<$crate::values::Value, anyhow::Error> {
267                    if args.len() < 4 {
268                        return Err(anyhow::anyhow!("Expected 4 arguments, got {}", args.len()));
269                    }
270                    let arg0 = $crate::functions::convert_value_to_type::<
271                        $arg_type1,
272                    >(args[0].clone())?;
273                    let arg1 = $crate::functions::convert_value_to_type::<
274                        $arg_type2,
275                    >(args[1].clone())?;
276                    let arg2 = $crate::functions::convert_value_to_type::<
277                        $arg_type3,
278                    >(args[2].clone())?;
279                    let arg3 = $crate::functions::convert_value_to_type::<
280                        $arg_type4,
281                    >(args[3].clone())?;
282                    let result = $body(arg0, arg1, arg2, arg3);
283                    Ok($crate::values::Value::from(result))
284                }
285            }
286            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
287        }
288    };
289}
290
291/// Define an implicit (method-style) function for specific [`Value`](crate::values::Value) types.
292///
293/// Expands to a `FunctionHandler` that:
294/// - Validates argument count (1–4).
295/// - For each argument, reuses the actual type if it matches `$arg_typeN`,
296///   otherwise converts via `to_type`.
297/// - Invokes `$body` with references to typed arguments and, for multi-arg
298///   variants, the evaluation context.
299#[macro_export]
300macro_rules! define_implicit_function {
301    // One argument - e.g. value.method()
302    ($name:ident, args: [$arg_type0:path], $body:expr) => {
303        |registry: &mut $crate::functions::FunctionRegistry| {
304            struct Handler;
305            impl $crate::functions::FunctionHandler for Handler {
306                fn call(
307                    &self,
308                    _context: &mut dyn $crate::aim::ContextLike,
309                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
310                ) -> Result<$crate::values::Value, anyhow::Error> {
311                    if args.len() < 1 {
312                        return Err(anyhow::anyhow!("Expected 1 argument, got {}", args.len()));
313                    }
314                    let arg0 = if args[0].is_actual_type(&$arg_type0) {
315                        args[0].clone()
316                    } else {
317                        args[0].clone().to_type(&$arg_type0)?
318                    };
319                    let result = $body(arg0);
320                    result.map(|v| $crate::values::Value::from(v))
321                }
322            }
323            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
324        }
325    };
326
327    // Two arguments
328    ($name:ident, args: [$arg_type0:path, $arg_type1:path], $body:expr) => {
329        |registry: &mut $crate::functions::FunctionRegistry| {
330            struct Handler;
331            impl $crate::functions::FunctionHandler for Handler {
332                fn call(
333                    &self,
334                    context: &mut dyn $crate::aim::ContextLike,
335                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
336                ) -> Result<$crate::values::Value, anyhow::Error> {
337                    if args.len() < 2 {
338                        return Err(anyhow::anyhow!("Expected 2 arguments, got {}", args.len()));
339                    }
340                    let arg0 = if args[0].is_actual_type(&$arg_type0) {
341                        args[0].clone()
342                    } else {
343                        args[0].clone().to_type(&$arg_type0)?
344                    };
345                    let arg1 = if args[1].is_actual_type(&$arg_type1) {
346                        args[1].clone()
347                    } else {
348                        args[1].clone().to_type(&$arg_type1)?
349                    };
350                    let result = $body(context, arg0, arg1);
351                    result.map(|v| $crate::values::Value::from(v))
352                }
353            }
354            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
355        }
356    };
357
358    // Three arguments
359    ($name:ident, args: [$arg_type0:path, $arg_type1:path, $arg_type2:path], $body:expr) => {
360        |registry: &mut $crate::functions::FunctionRegistry| {
361            struct Handler;
362            impl $crate::functions::FunctionHandler for Handler {
363                fn call(
364                    &self,
365                    context: &mut dyn $crate::aim::ContextLike,
366                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
367                ) -> Result<$crate::values::Value, anyhow::Error> {
368                    if args.len() < 3 {
369                        return Err(anyhow::anyhow!("Expected 3 arguments, got {}", args.len()));
370                    }
371                    let arg0 = if args[0].is_actual_type(&$arg_type0) {
372                        args[0].clone()
373                    } else {
374                        args[0].clone().to_type(&$arg_type0)?
375                    };
376                    let arg1 = if args[1].is_actual_type(&$arg_type1) {
377                        args[1].clone()
378                    } else {
379                        args[1].clone().to_type(&$arg_type1)?
380                    };
381                    let arg2 = if args[2].is_actual_type(&$arg_type2) {
382                        args[2].clone()
383                    } else {
384                        args[2].clone().to_type(&$arg_type2)?
385                    };
386                    let result = $body(context, arg0, arg1, arg2);
387                    result.map(|v| $crate::values::Value::from(v))
388                }
389            }
390            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
391        }
392    };
393
394    // Four arguments
395    ($name:ident, args: [$arg_type0:path, $arg_type1:path, $arg_type2:path, $arg_type3:path], $body:expr) => {
396        |registry: &mut $crate::functions::FunctionRegistry| {
397            struct Handler;
398            impl $crate::functions::FunctionHandler for Handler {
399                fn call(
400                    &self,
401                    context: &mut dyn $crate::aim::ContextLike,
402                    args: std::vec::Vec<std::sync::Arc<$crate::values::Value>>,
403                ) -> Result<$crate::values::Value, anyhow::Error> {
404                    if args.len() < 4 {
405                        return Err(anyhow::anyhow!("Expected 4 arguments, got {}", args.len()));
406                    }
407                    let arg0 = if args[0].is_actual_type(&$arg_type0) {
408                        args[0].clone()
409                    } else {
410                        args[0].clone().to_type(&$arg_type0)?
411                    };
412                    let arg1 = if args[1].is_actual_type(&$arg_type1) {
413                        args[1].clone()
414                    } else {
415                        args[1].clone().to_type(&$arg_type1)?
416                    };
417                    let arg2 = if args[2].is_actual_type(&$arg_type2) {
418                        args[2].clone()
419                    } else {
420                        args[2].clone().to_type(&$arg_type2)?
421                    };
422                    let arg3 = if args[3].is_actual_type(&$arg_type3) {
423                        args[3].clone()
424                    } else {
425                        args[3].clone().to_type(&$arg_type3)?
426                    };
427                    let result = $body(context, arg0, arg1, arg2, arg3);
428                    result.map(|v| $crate::values::Value::from(v))
429                }
430            }
431            registry.register(std::sync::Arc::from(stringify!($name)), Handler);
432        }
433    };
434}