Skip to main content

ff_script/
macros.rs

1//! The `ff_function!` declarative macro for typed FCALL wrappers.
2//!
3//! Generates an async function that:
4//! 1. Builds KEYS and ARGV vectors from the provided expressions
5//! 2. Calls `conn.fcall::<Value>(fn_name, &keys, &argv)`
6//! 3. Parses the result via `FromFcallResult`
7//!
8//! # Example
9//!
10//! ```ignore
11//! ff_function! {
12//!     /// Complete an active execution.
13//!     pub ff_complete_execution(args: CompleteExecutionArgs) -> CompleteExecutionResult {
14//!         keys(ctx: &ExecKeyContext) {
15//!             ctx.core(),
16//!             ctx.attempt_hash(args.attempt_index),
17//!             ctx.lease_current(),
18//!         }
19//!         argv {
20//!             args.execution_id.to_string(),
21//!             args.lease_id.to_string(),
22//!         }
23//!     }
24//! }
25//! ```
26
27/// Generate typed async FCALL wrappers from a declarative specification.
28///
29/// Each invocation defines one or more functions. The macro generates:
30/// - An `async fn` that takes `conn`, a key context, and typed args
31/// - Builds KEYS and ARGV vectors from the provided expressions
32/// - Calls `FCALL <function_name>` via the ferriskey client
33/// - Parses the result via the `FromFcallResult` trait
34#[macro_export]
35macro_rules! ff_function {
36    // Support multiple function definitions in one block
37    (
38        $(
39            $(#[$attr:meta])*
40            $vis:vis $fn_name:ident (
41                $args_name:ident : $args_type:ty
42            ) -> $result_type:ty {
43                keys( $ctx_name:ident : & $ctx_type:ty ) {
44                    $( $key_expr:expr ),* $(,)?
45                }
46                argv {
47                    $( $argv_expr:expr ),* $(,)?
48                }
49            }
50        )*
51    ) => {
52        $(
53            $(#[$attr])*
54            $vis async fn $fn_name(
55                conn: &ferriskey::Client,
56                $ctx_name: &$ctx_type,
57                $args_name: &$args_type,
58            ) -> ::core::result::Result<$result_type, $crate::error::ScriptError> {
59                let keys: ::std::vec::Vec<String> = vec![ $( $key_expr ),* ];
60                let argv: ::std::vec::Vec<String> = vec![ $( $argv_expr ),* ];
61                let key_refs: ::std::vec::Vec<&str> = keys.iter().map(|s| s.as_str()).collect();
62                let argv_refs: ::std::vec::Vec<&str> = argv.iter().map(|s| s.as_str()).collect();
63                let raw = conn
64                    .fcall::<ferriskey::Value>(stringify!($fn_name), &key_refs, &argv_refs)
65                    .await
66                    .map_err($crate::error::ScriptError::Valkey)?;
67                <$result_type as $crate::result::FromFcallResult>::from_fcall_result(&raw)
68            }
69        )*
70    };
71}