#[macro_export]
macro_rules! impl_conversions {
($($target_type:ty => $value_variant:path as $cel_type:ty),* $(,)?) => {
$(
impl From<$target_type> for Value {
fn from(value: $target_type) -> Self {
$value_variant(value)
}
}
impl<'context, 'call> $crate::magic::IntoResolveResult<'context, 'call> for $target_type {
fn into_resolve_result(self) -> Result<$crate::common::value::CowVal<'context, 'call>, ExecutionError> {
Ok($crate::common::value::CowVal::owned(<$cel_type>::from(self)))
}
}
impl<'context, 'call> $crate::magic::IntoResolveResult<'context, 'call> for Result<$target_type, ExecutionError> {
fn into_resolve_result(self) -> Result<$crate::common::value::CowVal<'context, 'call>, ExecutionError> {
$crate::magic::IntoResolveResult::into_resolve_result(self?)
}
}
impl<'a, 'context, 'call> FromContext<'a, 'context, 'call> for $target_type {
fn from_context(ctx: &'a mut FunctionContext<'context, 'call>) -> Result<Self, ExecutionError>
where
Self: Sized,
{
$crate::magic::arg_val_from_context(ctx)
.and_then(|v| $crate::magic::FromVal::from_val(v.as_ref()))
}
}
)*
}
}
#[macro_export]
macro_rules! impl_handler {
($($t:ty),*) => {
pastey::paste! {
impl<F, $($t,)* R> IntoFunction<($($t,)*)> for F
where
F: Fn($($t,)*) -> R + Send + Sync + 'static,
$($t: for<'a, 'context, 'call> $crate::FromContext<'a, 'context, 'call>,)*
R: for<'context, 'call> IntoResolveResult<'context, 'call>,
{
fn into_function(self) -> Function {
Box::new(move |_ftx| {
$(
let [<arg_ $t:lower>] = $t::from_context(_ftx)?;
)*
self($([<arg_ $t:lower>],)*).into_resolve_result()
})
}
}
impl<F, $($t,)* R> IntoFunction<(WithFunctionContext, $($t,)*)> for F
where
F: Fn(&FunctionContext, $($t,)*) -> R + Send + Sync + 'static,
$($t: for<'a, 'context, 'call> $crate::FromContext<'a, 'context, 'call>,)*
R: for<'context, 'call> IntoResolveResult<'context, 'call>,
{
fn into_function(self) -> Function {
Box::new(move |_ftx| {
$(
let [<arg_ $t:lower>] = $t::from_context(_ftx)?;
)*
self(_ftx, $([<arg_ $t:lower>],)*).into_resolve_result()
})
}
}
}
};
}
pub(crate) use impl_conversions;
#[doc(hidden)]
pub fn to_camel_case(snake: &str) -> String {
let mut out = String::with_capacity(snake.len());
let mut upper_next = false;
for c in snake.chars() {
if c == '_' {
upper_next = !out.is_empty();
} else if upper_next {
out.push(c.to_ascii_uppercase());
upper_next = false;
} else {
out.push(c);
}
}
out
}
#[doc(hidden)]
#[macro_export]
macro_rules! __overload_result {
(owned, $ret:ty, $call:expr) => {{
let __v: $ret = $call;
::std::result::Result::Ok($crate::common::value::CowVal::owned(__v))
}};
(borrowed, $ret:ty, $call:expr) => {{
let __v: &$ret = $call;
::std::result::Result::Ok($crate::common::value::CowVal::Borrowed(__v))
}};
(try_owned, $ret:ty, $call:expr) => {{
let __v: $ret = $call?;
::std::result::Result::Ok($crate::common::value::CowVal::owned(__v))
}};
(try_borrowed, $ret:ty, $call:expr) => {{
let __v: &$ret = $call?;
::std::result::Result::Ok($crate::common::value::CowVal::Borrowed(__v))
}};
}
#[macro_export]
macro_rules! add_member_overload {
(
$env:expr,
fn $fn:ident : ( $this:ty $(, $other:ty )* $(,)? ) -> Result<&$ret:ty $(, $err:ty)?>
$(, $key:ident = $val:expr )* $(,)?
) => {
$crate::__add_member_overload!(
try_borrowed, $env, fn $fn: ($this $(, $other)*) -> $ret $(, $key = $val)*)
};
(
$env:expr,
fn $fn:ident : ( $this:ty $(, $other:ty )* $(,)? ) -> Result<$ret:ty $(, $err:ty)?>
$(, $key:ident = $val:expr )* $(,)?
) => {
$crate::__add_member_overload!(
try_owned, $env, fn $fn: ($this $(, $other)*) -> $ret $(, $key = $val)*)
};
(
$env:expr,
fn $fn:ident : ( $this:ty $(, $other:ty )* $(,)? ) -> &$ret:ty
$(, $key:ident = $val:expr )* $(,)?
) => {
$crate::__add_member_overload!(
borrowed, $env, fn $fn: ($this $(, $other)*) -> $ret $(, $key = $val)*)
};
(
$env:expr,
fn $fn:ident : ( $this:ty $(, $other:ty )* $(,)? ) -> $ret:ty
$(, $key:ident = $val:expr )* $(,)?
) => {
$crate::__add_member_overload!(
owned, $env, fn $fn: ($this $(, $other)*) -> $ret $(, $key = $val)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __add_member_overload {
(
$shape:ident, $env:expr,
fn $fn:ident : ( $this:ty $(, $other:ty )* ) -> $ret:ty
$(, $key:ident = $val:expr )*
) => {{
fn __wrapper<'b, 'v>(
args: ::std::vec::Vec<$crate::common::value::CowVal<'b, 'v>>,
) -> ::std::result::Result<
$crate::common::value::CowVal<'b, 'v>,
$crate::ExecutionError,
> {
const __ARITY: usize =
[::std::stringify!($this) $(, ::std::stringify!($other))*].len();
let __actual = args.len();
let mut __at = 0usize;
$crate::__overload_result!($shape, $ret, $fn(
$crate::__member_overload_extract!(args, __at, $this, __ARITY, __actual)
$(, $crate::__member_overload_extract!(args, __at, $other, __ARITY, __actual) )*
))
}
let __receiver: ::std::option::Option<$crate::common::types::Type> =
::std::option::Option::None;
$( $crate::__overload_receiver_override!(__receiver, $key = $val); )*
let __receiver: $crate::common::types::Type = __receiver
.unwrap_or_else(|| <$this as $crate::common::value::Val>::cel_type().to_owned());
let __name: ::std::string::String =
$crate::to_camel_case(::std::stringify!($fn));
$( $crate::__overload_name_override!(__name, $key = $val); )*
let __rest_types: ::std::vec::Vec<&str> = ::std::vec![
$( <$other as $crate::common::value::Val>::cel_type().name() ),*
];
let __id: ::std::string::String = ::std::format!(
"{}.{}({})",
__receiver.name(),
__name,
__rest_types.join(","),
);
$( $crate::__overload_id_override!(__id, $key = $val); )*
$env.add_member_overload(
&__name,
&__id,
__receiver,
::std::vec![
$( <$other as $crate::common::value::Val>::cel_type().to_owned() ),*
],
__wrapper,
)
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __member_overload_extract {
($args:ident, $idx:ident, $ty:ty, $arity:ident, $actual:ident) => {{
let __arg = $args
.get($idx)
.ok_or_else(|| $crate::ExecutionError::invalid_argument_count($arity, $actual))?
.as_ref();
$idx += 1;
__arg
.downcast_ref::<$ty>()
.ok_or_else(|| $crate::ExecutionError::UnexpectedType {
got: __arg.get_type().name().to_owned(),
want: <$ty as $crate::common::value::Val>::cel_type()
.name()
.to_owned(),
})?
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __overload_name_override {
($bind:ident, name = $val:expr) => {
let $bind: ::std::string::String = ::std::string::String::from($val);
};
($bind:ident, id = $val:expr) => {};
($bind:ident, receiver = $val:expr) => {};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __overload_id_override {
($bind:ident, id = $val:expr) => {
let $bind: ::std::string::String = ::std::string::String::from($val);
};
($bind:ident, name = $val:expr) => {};
($bind:ident, receiver = $val:expr) => {};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __overload_receiver_override {
($bind:ident, receiver = $val:expr) => {
let $bind: ::std::option::Option<$crate::common::types::Type> =
::std::option::Option::Some($val);
};
($bind:ident, name = $val:expr) => {};
($bind:ident, id = $val:expr) => {};
}
#[macro_export]
macro_rules! add_overload {
(
$env:expr,
fn $fn:ident : ( $($arg:ty),* $(,)? ) -> Result<&$ret:ty $(, $err:ty)?>
$(, $key:ident = $val:expr )* $(,)?
) => {
$crate::__add_overload!(try_borrowed, $env, fn $fn: ($($arg),*) -> $ret $(, $key = $val)*)
};
(
$env:expr,
fn $fn:ident : ( $($arg:ty),* $(,)? ) -> Result<$ret:ty $(, $err:ty)?>
$(, $key:ident = $val:expr )* $(,)?
) => {
$crate::__add_overload!(try_owned, $env, fn $fn: ($($arg),*) -> $ret $(, $key = $val)*)
};
(
$env:expr,
fn $fn:ident : ( $($arg:ty),* $(,)? ) -> &$ret:ty
$(, $key:ident = $val:expr )* $(,)?
) => {
$crate::__add_overload!(borrowed, $env, fn $fn: ($($arg),*) -> $ret $(, $key = $val)*)
};
(
$env:expr,
fn $fn:ident : ( $($arg:ty),* $(,)? ) -> $ret:ty
$(, $key:ident = $val:expr )* $(,)?
) => {
$crate::__add_overload!(owned, $env, fn $fn: ($($arg),*) -> $ret $(, $key = $val)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __add_overload {
(
$shape:ident, $env:expr,
fn $fn:ident : ( $($arg:ty),* ) -> $ret:ty
$(, $key:ident = $val:expr )*
) => {{
fn __wrapper<'b, 'v>(
args: ::std::vec::Vec<$crate::common::value::CowVal<'b, 'v>>,
) -> ::std::result::Result<
$crate::common::value::CowVal<'b, 'v>,
$crate::ExecutionError,
> {
const __ARITY: usize = {
const __ARGS: &[&str] = &[$(::std::stringify!($arg)),*];
__ARGS.len()
};
let _ = &args;
let __actual = args.len();
let mut __at = 0usize;
let _ = &mut __at;
$crate::__overload_result!($shape, $ret, $fn(
$( $crate::__member_overload_extract!(args, __at, $arg, __ARITY, __actual) ),*
))
}
let __name: ::std::string::String =
$crate::to_camel_case(::std::stringify!($fn));
$( $crate::__overload_name_override!(__name, $key = $val); )*
let __arg_types: ::std::vec::Vec<&str> = ::std::vec![
$( <$arg as $crate::common::value::Val>::cel_type().name() ),*
];
let __id: ::std::string::String =
::std::format!("{}({})", __name, __arg_types.join(","));
$( $crate::__overload_id_override!(__id, $key = $val); )*
$env.add_overload(
&__name,
&__id,
::std::vec![
$( <$arg as $crate::common::value::Val>::cel_type().to_owned() ),*
],
__wrapper,
)
}};
}
pub(crate) use impl_handler;
#[cfg(test)]
mod tests {
use crate::common::types::{self, CelBool, CelInt, CelString};
use crate::common::value::{CowVal, Val};
use crate::{Env, ExecutionError};
fn ping(_x: &CelString<'_>) -> CelInt {
CelInt::from(0)
}
fn ping2(_a: &CelString<'_>, _b: &CelString<'_>) -> CelInt {
CelInt::from(0)
}
fn ping2_bool(_a: &CelString<'_>, _b: &CelString<'_>) -> CelBool {
CelBool::from(false)
}
fn ends_with(_a: &CelString<'_>, _b: &CelString<'_>) -> CelBool {
CelBool::from(false)
}
fn ping0() -> CelInt {
CelInt::from(0)
}
fn fallible(_x: &CelString<'_>) -> Result<CelInt, ExecutionError> {
Ok(CelInt::from(0))
}
fn borrows(_x: &CelString<'_>) -> &'static CelBool {
&CelBool::TRUE
}
fn fallible_borrows(_x: &CelString<'_>) -> Result<&'static CelBool, ExecutionError> {
Ok(&CelBool::TRUE)
}
fn noop<'b, 'v>(_args: Vec<CowVal<'b, 'v>>) -> Result<CowVal<'b, 'v>, ExecutionError> {
Ok(CowVal::owned(CelInt::from(0)))
}
#[test]
fn to_camel_case_single_word() {
assert_eq!(super::to_camel_case("matches"), "matches");
}
#[test]
fn to_camel_case_two_words() {
assert_eq!(super::to_camel_case("ends_with"), "endsWith");
}
#[test]
fn to_camel_case_three_words() {
assert_eq!(super::to_camel_case("day_of_year"), "dayOfYear");
}
#[test]
fn to_camel_case_leading_and_trailing_underscores_dropped() {
assert_eq!(super::to_camel_case("_foo_bar_"), "fooBar");
}
#[test]
fn to_camel_case_collapses_repeated_underscores() {
assert_eq!(super::to_camel_case("foo__bar"), "fooBar");
}
fn string_arg<'b, 'v>() -> CowVal<'b, 'v> {
CowVal::owned(CelString::from(""))
}
fn string_args<'b, 'v>(arity: usize) -> Vec<CowVal<'b, 'v>> {
(0..arity).map(|_| string_arg()).collect()
}
fn name_registered(env: &Env, name: &str, arity: usize) -> bool {
env.find_overload(name, &string_args(arity)).is_some()
}
fn member_name_registered(env: &Env, name: &str, arity: usize) -> bool {
env.find_member_overload(name, &string_args(arity))
.is_some()
}
#[test]
fn add_overload_default_name_snake_to_camel() {
let mut env = Env::default();
crate::add_overload!(env, fn ends_with: (CelString, CelString) -> CelBool).unwrap();
assert!(name_registered(&env, "endsWith", 2));
assert!(!name_registered(&env, "ends_with", 2));
}
#[test]
fn add_overload_default_name_single_word_unchanged() {
let mut env = Env::default();
crate::add_overload!(env, fn ping: (CelString) -> CelInt).unwrap();
assert!(name_registered(&env, "ping", 1));
}
#[test]
fn add_member_overload_default_name_snake_to_camel() {
let mut env = Env::default();
crate::add_member_overload!(env, fn ends_with: (CelString, CelString) -> CelBool).unwrap();
assert!(member_name_registered(&env, "endsWith", 2));
assert!(!member_name_registered(&env, "ends_with", 2));
}
#[test]
fn add_member_overload_id_default_uses_camel_cased_name() {
let mut env = Env::default();
crate::add_member_overload!(env, fn ends_with: (CelString, CelString) -> CelBool).unwrap();
assert!(env
.add_member_overload(
"endsWith",
"string.endsWith(string)",
types::STRING_TYPE,
vec![types::STRING_TYPE],
noop,
)
.is_err());
}
#[test]
fn add_overload_default_id_matches_cel_cpp_one_arg() {
let mut env = Env::default();
crate::add_overload!(env, fn ping: (CelString) -> CelInt).unwrap();
assert!(
env.add_overload("ping", "ping(string)", vec![types::STRING_TYPE], noop)
.is_err(),
"default id should be `ping(string)`",
);
}
#[test]
fn add_overload_default_id_matches_cel_cpp_two_args() {
let mut env = Env::default();
crate::add_overload!(env, fn ping2: (CelString, CelString) -> CelInt).unwrap();
assert!(env
.add_overload(
"ping2",
"ping2(string,string)",
vec![types::STRING_TYPE, types::STRING_TYPE],
noop,
)
.is_err());
}
#[test]
fn add_overload_default_id_matches_cel_cpp_zero_args() {
let mut env = Env::default();
crate::add_overload!(env, fn ping0: () -> CelInt).unwrap();
assert!(env.add_overload("ping0", "ping0()", vec![], noop).is_err());
}
#[test]
fn add_overload_id_default_uses_resolved_name_override() {
let mut env = Env::default();
crate::add_overload!(env, fn ping: (CelString) -> CelInt, name = "renamed").unwrap();
assert!(
env.add_overload("renamed", "renamed(string)", vec![types::STRING_TYPE], noop)
.is_err(),
"id default should follow the overridden name",
);
assert!(env
.add_overload("renamed", "ping(string)", vec![types::INT_TYPE], noop)
.is_ok());
}
#[test]
fn add_overload_explicit_id_wins_over_default() {
let mut env = Env::default();
crate::add_overload!(env, fn ping: (CelString) -> CelInt, id = "explicit").unwrap();
assert!(env
.add_overload("ping", "explicit", vec![types::STRING_TYPE], noop)
.is_err());
}
fn call(env: &Env, name: &str) -> CowVal<'static, 'static> {
let wrapper = env.find_overload(name, &[string_arg()]).unwrap();
wrapper(vec![string_arg()]).unwrap()
}
#[test]
fn a_plain_value_is_wrapped_as_owned() {
let mut env = Env::default();
crate::add_overload!(env, fn ping: (CelString) -> CelInt).unwrap();
let out = call(&env, "ping");
assert!(out.is_owned());
assert_eq!(out.downcast_ref::<CelInt>(), Some(&CelInt::from(0)));
}
#[test]
fn a_result_value_is_wrapped_as_owned() {
let mut env = Env::default();
crate::add_overload!(env, fn fallible: (CelString) -> Result<CelInt>).unwrap();
let out = call(&env, "fallible");
assert!(out.is_owned());
assert_eq!(out.downcast_ref::<CelInt>(), Some(&CelInt::from(0)));
}
#[test]
fn a_result_shape_accepts_an_explicit_error_type() {
let mut env = Env::default();
crate::add_overload!(env, fn fallible: (CelString) -> Result<CelInt, ExecutionError>)
.unwrap();
assert_eq!(
call(&env, "fallible").downcast_ref::<CelInt>(),
Some(&CelInt::from(0))
);
}
#[test]
fn a_reference_is_kept_as_a_borrow() {
let mut env = Env::default();
crate::add_overload!(env, fn borrows: (CelString) -> &CelBool).unwrap();
let out = call(&env, "borrows");
assert!(out.is_borrowed(), "a `&T` result should not be boxed");
assert_eq!(out.downcast_ref::<CelBool>(), Some(&CelBool::TRUE));
}
#[test]
fn a_result_reference_is_kept_as_a_borrow() {
let mut env = Env::default();
crate::add_overload!(env, fn fallible_borrows: (CelString) -> Result<&CelBool>).unwrap();
let out = call(&env, "fallibleBorrows");
assert!(out.is_borrowed(), "a `&T` result should not be boxed");
assert_eq!(out.downcast_ref::<CelBool>(), Some(&CelBool::TRUE));
}
#[test]
fn a_result_shape_propagates_the_error() {
fn boom(_x: &CelString<'_>) -> Result<CelInt, ExecutionError> {
Err(ExecutionError::function_error("boom", "nope"))
}
let mut env = Env::default();
crate::add_overload!(env, fn boom: (CelString) -> Result<CelInt>).unwrap();
let wrapper = env.find_overload("boom", &[string_arg()]).unwrap();
assert_eq!(
wrapper(vec![string_arg()]).err(),
Some(ExecutionError::function_error("boom", "nope")),
);
}
#[test]
fn a_receiver_override_supplies_the_type_and_drives_the_id() {
use crate::common::types::Type;
let mut env = Env::default();
crate::add_member_overload!(env, fn ping: (CelString) -> CelInt,
receiver = Type::new_opaque_type("HttpRequest"))
.unwrap();
assert!(env
.add_member_overload(
"ping",
"HttpRequest.ping()",
Type::new_opaque_type("HttpRequest"),
vec![],
noop,
)
.is_err());
assert!(env
.add_member_overload("ping", "string.ping()", types::STRING_TYPE, vec![], noop)
.is_ok());
}
#[test]
fn a_receiver_override_composes_with_an_explicit_id() {
use crate::common::types::Type;
let mut env = Env::default();
crate::add_member_overload!(env, fn ping: (CelString) -> CelInt,
receiver = Type::new_opaque_type("Req"), id = "explicit")
.unwrap();
assert!(env
.add_member_overload(
"ping",
"explicit",
Type::new_opaque_type("Req"),
vec![],
noop
)
.is_err());
}
#[test]
#[should_panic(expected = "no static `Val::cel_type()`")]
fn a_struct_receiver_without_the_override_panics() {
use crate::common::types::CelStruct;
fn on_struct(_this: &CelStruct<'_>) -> CelInt {
CelInt::from(0)
}
let mut env = Env::default();
crate::add_member_overload!(env, fn on_struct: (CelStruct) -> CelInt).unwrap();
}
#[test]
fn a_struct_receiver_registers_with_the_override() {
use crate::common::types::{CelStruct, Type};
fn on_struct(_this: &CelStruct<'_>) -> CelInt {
CelInt::from(0)
}
let mut env = Env::default();
crate::add_member_overload!(env, fn on_struct: (CelStruct) -> CelInt,
receiver = Type::new_struct_type("HttpRequest"), name = "onStruct")
.unwrap();
assert!(env
.add_member_overload(
"onStruct",
"HttpRequest.onStruct()",
Type::new_struct_type("HttpRequest"),
vec![],
noop,
)
.is_err());
}
fn unexpected(got: &str, want: &str) -> ExecutionError {
ExecutionError::UnexpectedType {
got: got.to_owned(),
want: want.to_owned(),
}
}
#[test]
fn wrapper_reports_an_owned_argument_of_the_wrong_type() {
let mut env = Env::default();
crate::add_overload!(env, fn ping: (CelString) -> CelInt).unwrap();
let wrapper = env.find_overload("ping", &[string_arg()]).unwrap();
let int: Box<dyn Val> = Box::new(CelInt::from(1));
assert_eq!(
wrapper(vec![CowVal::Owned(int)]).err(),
Some(unexpected(
types::INT_TYPE.name(),
types::STRING_TYPE.name()
)),
);
}
#[test]
fn wrapper_reports_a_borrowed_argument_of_the_wrong_type() {
let mut env = Env::default();
crate::add_overload!(env, fn ping: (CelString) -> CelInt).unwrap();
let wrapper = env.find_overload("ping", &[string_arg()]).unwrap();
let int = CelInt::from(1);
assert_eq!(
wrapper(vec![CowVal::Borrowed(&int)]).err(),
Some(unexpected(
types::INT_TYPE.name(),
types::STRING_TYPE.name()
)),
);
}
#[test]
fn wrapper_reports_the_wanted_type_of_the_argument_that_is_wrong() {
let mut env = Env::default();
crate::add_overload!(env, fn ping2: (CelString, CelString) -> CelInt).unwrap();
let wrapper = env
.find_overload("ping2", &[string_arg(), string_arg()])
.unwrap();
let int: Box<dyn Val> = Box::new(CelInt::from(1));
assert_eq!(
wrapper(vec![string_arg(), CowVal::Owned(int)]).err(),
Some(unexpected(
types::INT_TYPE.name(),
types::STRING_TYPE.name()
)),
);
}
#[test]
fn wrapper_reports_missing_arguments_against_the_arity() {
let mut env = Env::default();
crate::add_overload!(env, fn ping2: (CelString, CelString) -> CelInt).unwrap();
let wrapper = env
.find_overload("ping2", &[string_arg(), string_arg()])
.unwrap();
assert_eq!(
wrapper(vec![]).err(),
Some(ExecutionError::invalid_argument_count(2, 0)),
);
assert_eq!(
wrapper(vec![string_arg()]).err(),
Some(ExecutionError::invalid_argument_count(2, 1)),
);
}
#[test]
fn member_wrapper_reports_errors_the_same_way() {
let mut env = Env::default();
crate::add_member_overload!(env, fn ping2: (CelString, CelString) -> CelInt).unwrap();
let wrapper = env
.find_member_overload("ping2", &[string_arg(), string_arg()])
.unwrap();
assert_eq!(
wrapper(vec![string_arg()]).err(),
Some(ExecutionError::invalid_argument_count(2, 1)),
);
let int: Box<dyn Val> = Box::new(CelInt::from(1));
assert_eq!(
wrapper(vec![CowVal::Owned(int), string_arg()]).err(),
Some(unexpected(
types::INT_TYPE.name(),
types::STRING_TYPE.name()
)),
);
}
#[test]
fn add_member_overload_default_id_matches_cel_cpp_no_extra_args() {
let mut env = Env::default();
crate::add_member_overload!(env, fn ping: (CelString) -> CelInt).unwrap();
assert!(env
.add_member_overload("ping", "string.ping()", types::STRING_TYPE, vec![], noop)
.is_err());
}
#[test]
fn add_member_overload_default_id_matches_cel_cpp_one_extra_arg() {
let mut env = Env::default();
crate::add_member_overload!(env, fn ping2: (CelString, CelString) -> CelInt).unwrap();
assert!(env
.add_member_overload(
"ping2",
"string.ping2(string)",
types::STRING_TYPE,
vec![types::STRING_TYPE],
noop,
)
.is_err());
}
#[test]
fn add_member_overload_id_default_uses_resolved_name_override() {
let mut env = Env::default();
crate::add_member_overload!(env, fn ping2_bool: (CelString, CelString) -> CelBool,
name = "endsWith")
.unwrap();
assert!(env
.add_member_overload(
"endsWith",
"string.endsWith(string)",
types::STRING_TYPE,
vec![types::STRING_TYPE],
noop,
)
.is_err());
}
#[test]
fn add_member_overload_explicit_id_wins_over_default() {
let mut env = Env::default();
crate::add_member_overload!(env, fn ping: (CelString) -> CelInt, id = "explicit").unwrap();
assert!(env
.add_member_overload("ping", "explicit", types::STRING_TYPE, vec![], noop)
.is_err());
}
}