pub struct Macro(/* private fields */);Expand description
A CEL macro that expands expressions at compile time.
A Macro represents a compile-time transformation rule that can be registered
with a CEL environment. When the parser encounters a matching function or method
call, the macro’s expander is invoked to transform the expression tree.
§Macro Expansion
During compilation, macros are expanded before type checking:
- Parser identifies function/method calls matching registered macros
- Macro expander receives the call expression and its arguments
- Expander returns a new expression tree or
Noneto keep original - Type checker validates the expanded expression
§Thread Safety
The expander functions captured in macros must be Send + Sync + 'static,
ensuring thread-safe usage across the CEL environment.
§Error Handling
Macro creation methods return Result<Self, Error> and can fail if:
- The macro name is invalid
- Internal FFI allocation fails
- The expander closure cannot be registered
§Examples
§Fixed argument count
// A macro that requires exactly 1 argument
let add_one_macro = Macro::new_global("add_one", 1, |factory, mut args| {
let arg = args.pop()?;
Some(factory.new_call("_+_", &[arg, factory.new_const(1)]))
})?;§Variable argument count
// A macro that accepts any number of arguments
let debug_macro = Macro::new_global_var_arg("debug", |factory, args| {
// Wrap all arguments in a list for debugging
let elements: Vec<_> = args.iter()
.map(|arg| factory.new_list_element(arg, false))
.collect();
Some(factory.new_list(&elements))
})?;Implementations§
Source§impl Macro
impl Macro
Sourcepub fn new_global(
name: impl AsRef<str>,
argument_count: usize,
expander: impl GlobalMacroExpander + 'static,
) -> Result<Self, Error>
pub fn new_global( name: impl AsRef<str>, argument_count: usize, expander: impl GlobalMacroExpander + 'static, ) -> Result<Self, Error>
Creates a new global macro with a fixed number of arguments.
Global macros are invoked like regular functions, e.g., macro_name(arg1, arg2).
The macro will only be expanded when called with exactly argument_count arguments.
§Parameters
name: The function name that triggers this macro (as a string reference)argument_count: The exact number of arguments requiredexpander: The expansion function that transforms the expression
§Returns
Ok(Macro): Successfully created macroErr(Error): Failed to create macro (e.g., invalid name or FFI error)
§Expander Function
The expander receives:
factory: A mutable reference toMacroExprFactoryfor creating new expressionsargs: A vector of argument expressions
The expander should return:
Some(Expr): The expanded expression to replace the original callNone: Keep the original expression unchanged
§Examples
// Macro: not_zero(x) expands to x != 0
let macro_def = Macro::new_global("not_zero", 1, |factory, mut args| {
let arg = args.pop()?;
Some(factory.new_call("_!=_", &[arg, factory.new_const(0)]))
})?;Sourcepub fn new_global_var_arg(
name: impl AsRef<str>,
expander: impl GlobalMacroExpander + 'static,
) -> Result<Self, Error>
pub fn new_global_var_arg( name: impl AsRef<str>, expander: impl GlobalMacroExpander + 'static, ) -> Result<Self, Error>
Creates a new global macro that accepts a variable number of arguments.
Variable-argument macros can handle any number of arguments, from zero to many. The expander function receives all arguments and decides how to handle them.
§Parameters
name: The function name that triggers this macro (as a string reference)expander: The expansion function that transforms the expression
§Returns
Ok(Macro): Successfully created macroErr(Error): Failed to create macro (e.g., invalid name or FFI error)
§Expander Function
The expander receives:
factory: A mutable reference toMacroExprFactoryfor creating new expressionsargs: A vector of argument expressions (can be empty)
The expander should return:
Some(Expr): The expanded expression to replace the original callNone: Keep the original expression unchanged
§Examples
// Macro: max(args...) finds maximum of all arguments
let max_macro = Macro::new_global_var_arg("max", |factory, args| {
if args.is_empty() {
return None;
}
// Implementation would build comparison chain
Some(args.into_iter().reduce(|acc, arg| {
factory.new_call("_>_?_:_", &[acc, arg.clone(), acc.clone(), arg])
})?)
})?;Sourcepub fn new_receiver(
name: impl AsRef<str>,
argument_count: usize,
expander: impl ReceiverMacroExpander + 'static,
) -> Result<Self, Error>
pub fn new_receiver( name: impl AsRef<str>, argument_count: usize, expander: impl ReceiverMacroExpander + 'static, ) -> Result<Self, Error>
Creates a new receiver macro with a fixed number of arguments.
Receiver macros are invoked as method calls on a target expression,
e.g., target.macro_name(arg1, arg2). The macro will only be expanded
when called with exactly argument_count arguments.
§Parameters
name: The method name that triggers this macro (as a string reference)argument_count: The exact number of arguments required (not including receiver)expander: The expansion function that receives the target and arguments
§Returns
Ok(Macro): Successfully created macroErr(Error): Failed to create macro (e.g., invalid name or FFI error)
§Expander Function
The expander receives:
factory: A mutable reference toMacroExprFactoryfor creating new expressionstarget: The receiver expression (the object before the dot)args: A vector of argument expressions
The expander should return:
Some(Expr): The expanded expression to replace the original callNone: Keep the original expression unchanged
§Examples
// Macro: list.is_empty() expands to size(list) == 0
let is_empty_macro = Macro::new_receiver("is_empty", 0, |factory, target, _args| {
let size_call = factory.new_call("size", &[target]);
Some(factory.new_call("_==_", &[size_call, factory.new_const(0)]))
})?;Sourcepub fn new_receiver_var_arg(
name: impl AsRef<str>,
expander: impl ReceiverMacroExpander + 'static,
) -> Result<Self, Error>
pub fn new_receiver_var_arg( name: impl AsRef<str>, expander: impl ReceiverMacroExpander + 'static, ) -> Result<Self, Error>
Creates a new receiver macro that accepts a variable number of arguments.
Variable-argument receiver macros can handle any number of arguments beyond the target expression. The expander receives the target and all arguments.
§Parameters
name: The method name that triggers this macro (as a string reference)expander: The expansion function that receives the target and arguments
§Returns
Ok(Macro): Successfully created macroErr(Error): Failed to create macro (e.g., invalid name or FFI error)
§Expander Function
The expander receives:
factory: A mutable reference toMacroExprFactoryfor creating new expressionstarget: The receiver expression (the object before the dot)args: A vector of argument expressions (can be empty)
The expander should return:
Some(Expr): The expanded expression to replace the original callNone: Keep the original expression unchanged
§Examples
// Macro: str.concat(parts...) concatenates multiple strings
let concat_macro = Macro::new_receiver_var_arg("concat", |factory, target, args| {
let mut result = target;
for arg in args {
result = factory.new_call("_+_", &[result, arg]);
}
Some(result)
})?;Sourcepub fn name(&self) -> &[u8] ⓘ
pub fn name(&self) -> &[u8] ⓘ
Returns the name of this macro as a byte slice.
This is the function or method name that triggers macro expansion. The returned byte slice is UTF-8 encoded.
§Examples
let name = macro_def.name();
let name_str = std::str::from_utf8(name).unwrap();
println!("Macro name: {}", name_str);Sourcepub fn argument_count(&self) -> Option<usize>
pub fn argument_count(&self) -> Option<usize>
Returns the expected number of arguments for this macro.
Returns Some(n) for fixed-argument macros requiring exactly n arguments,
or None for variable-argument macros that accept any number of arguments.
§Examples
match macro_def.argument_count() {
Some(n) => println!("Fixed macro with {} arguments", n),
None => println!("Variable-argument macro"),
}Sourcepub fn is_receiver_style(&self) -> bool
pub fn is_receiver_style(&self) -> bool
Returns whether this is a receiver-style macro.
Receiver-style macros are invoked as method calls (e.g., target.method(args)),
while non-receiver macros are invoked as function calls (e.g., function(args)).
§Returns
true: This is a receiver macro (created withnew_receiverornew_receiver_var_arg)false: This is a global macro (created withnew_globalornew_global_var_arg)
Sourcepub fn key(&self) -> &[u8] ⓘ
pub fn key(&self) -> &[u8] ⓘ
Returns the unique key identifying this macro.
The key is an internal identifier used by the CEL parser to match macro invocations. It encodes the macro name, receiver style, and argument count.
§Returns
A byte slice representing the macro’s unique key (UTF-8 encoded).
§Note
This method is primarily for internal use and debugging. Most users should
use name(), is_receiver_style(), and argument_count() instead.
Trait Implementations§
impl Eq for Macro
Auto Trait Implementations§
impl Freeze for Macro
impl RefUnwindSafe for Macro
impl Send for Macro
impl Sync for Macro
impl Unpin for Macro
impl UnwindSafe for Macro
Blanket Implementations§
§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more