#[macro_export]
macro_rules! define_function_enum {
(
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$(
$(#[$variant_meta:meta])*
$variant:ident => {
name: $func_name:literal,
arity: $arity:expr,
variadic: $variadic:expr,
description: $desc:literal,
handler: $handler:expr
}
),* $(,)?
}
) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
$vis enum $name {
$(
$(#[$variant_meta])*
$variant,
)*
}
impl $name {
$vis fn name(&self) -> &str {
match self {
$(Self::$variant => $func_name,)*
}
}
$vis fn arity(&self) -> usize {
match self {
$(Self::$variant => $arity,)*
}
}
$vis fn is_variadic(&self) -> bool {
match self {
$(Self::$variant => $variadic,)*
}
}
$vis fn description(&self) -> &str {
match self {
$(Self::$variant => $desc,)*
}
}
$vis fn execute(&self, args: &[linkrs_core::Value]) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
if !self.is_variadic() && args.len() != self.arity() {
return Err($crate::executor::expression::ExpressionError::invalid_arity(
self.name(),
self.arity(),
args.len(),
));
}
let handler: fn(&[linkrs_core::Value]) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> = match self {
$(Self::$variant => $handler,)*
};
handler(args)
}
}
};
}
#[macro_export]
macro_rules! define_unary_float_fn {
($name:ident, $op:expr, $desc:literal) => {
fn $name(
args: &[linkrs_core::Value],
) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
let op = $op;
match &args[0] {
Value::SmallInt(i) => Ok(Value::Float(op(*i as f32))),
Value::Int(i) => Ok(Value::Float(op(*i as f32))),
Value::BigInt(i) => Ok(Value::Double(op(*i as f32) as f64)),
Value::Float(f) => Ok(Value::Float(op(*f))),
Value::Double(f) => Ok(Value::Double(op(*f as f32) as f64)),
Value::Null(_) => Ok(Value::Null(NullType::Null)),
_ => Err($crate::executor::expression::ExpressionError::type_error(
concat!($desc, "Functions require numeric types"),
)),
}
}
};
}
#[macro_export]
macro_rules! define_unary_numeric_fn {
($name:ident, int: $int_op:expr, float: $float_op:expr, $desc:literal) => {
fn $name(
args: &[linkrs_core::Value],
) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
match &args[0] {
Value::SmallInt(i) => $int_op(*i as i32),
Value::Int(i) => $int_op(*i),
Value::BigInt(i) => $int_op(*i as i32),
Value::Float(f) => $float_op(*f),
Value::Double(f) => $float_op(*f as f32),
Value::Null(_) => Ok(Value::Null(NullType::Null)),
_ => Err($crate::executor::expression::ExpressionError::type_error(
concat!($desc, "Functions require numeric types"),
)),
}
}
};
}
#[macro_export]
macro_rules! define_unary_string_fn {
($name:ident, $op:expr, $desc:literal) => {
fn $name(
args: &[linkrs_core::Value],
) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
let op = $op;
match &args[0] {
Value::String(s) => Ok(Value::string(op(s))),
Value::Null(_) => Ok(Value::Null(NullType::Null)),
_ => Err($crate::executor::expression::ExpressionError::type_error(
concat!($desc, "Functions require a string type"),
)),
}
}
};
}
#[macro_export]
macro_rules! define_datetime_extractor {
($name:ident, Date => $date_field:ident, DateTime => $datetime_field:ident) => {
fn $name(
args: &[linkrs_core::Value],
) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
match &args[0] {
Value::Date(d) => Ok(Value::BigInt(d.$date_field as i64)),
Value::DateTime(dt) => Ok(Value::BigInt(dt.$datetime_field as i64)),
Value::Null(_) => Ok(Value::Null(NullType::Null)),
_ => Err($crate::executor::expression::ExpressionError::type_error(
concat!(
stringify!($name),
"Functions require a date or datetime type"
),
)),
}
}
};
($name:ident, Time => $time_field:ident, DateTime => $datetime_field:ident) => {
fn $name(
args: &[linkrs_core::Value],
) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
match &args[0] {
Value::Time(t) => Ok(Value::BigInt(t.$time_field as i64)),
Value::DateTime(dt) => Ok(Value::BigInt(dt.$datetime_field as i64)),
Value::Null(_) => Ok(Value::Null(NullType::Null)),
_ => Err($crate::executor::expression::ExpressionError::type_error(
concat!(
stringify!($name),
"Functions require a time or datetime type"
),
)),
}
}
};
}
#[macro_export]
macro_rules! define_binary_numeric_fn {
($name:ident, $op:expr, $desc:literal) => {
fn $name(
args: &[linkrs_core::Value],
) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
let op = $op;
match (&args[0], &args[1]) {
(Value::SmallInt(a), Value::SmallInt(b)) => op(*a as f32, *b as f32),
(Value::Int(a), Value::Int(b)) => op(*a as f32, *b as f32),
(Value::BigInt(a), Value::BigInt(b)) => op(*a as f32, *b as f32),
(Value::SmallInt(a), Value::Int(b)) => op(*a as f32, *b as f32),
(Value::Int(a), Value::SmallInt(b)) => op(*a as f32, *b as f32),
(Value::Float(a), Value::Float(b)) => op(*a, *b),
(Value::Double(a), Value::Double(b)) => op(*a as f32, *b as f32),
(Value::Float(a), Value::Double(b)) => op(*a, *b as f32),
(Value::Double(a), Value::Float(b)) => op(*a as f32, *b),
(Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
_ => Err($crate::executor::expression::ExpressionError::type_error(
concat!($desc, "Functions require numeric types"),
)),
}
}
};
}
#[macro_export]
macro_rules! define_binary_string_bool_fn {
($name:ident, $op:expr, $desc:literal) => {
fn $name(
args: &[linkrs_core::Value],
) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
let op = $op;
match (&args[0], &args[1]) {
(Value::String(a), Value::String(b)) => Ok(Value::Bool(op(a, b))),
(Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
_ => Err($crate::executor::expression::ExpressionError::type_error(
concat!($desc, "Functions require a string type"),
)),
}
}
};
}
#[macro_export]
macro_rules! define_binary_geography_fn {
($name:ident, $op:expr, $desc:literal) => {
fn $name(
args: &[linkrs_core::Value],
) -> Result<linkrs_core::Value, $crate::executor::expression::ExpressionError> {
let op = $op;
match (&args[0], &args[1]) {
(Value::Geography(geo1), Value::Geography(geo2)) => op(geo1, geo2),
(Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
_ => Err($crate::executor::expression::ExpressionError::type_error(
concat!($desc, "Functions require geo-typed parameters"),
)),
}
}
};
}