use std::fmt;
use std::marker::PhantomData;
use std::sync::Arc;
use crate::spec::function::builtin::*;
use crate::VariantValue;
pub mod builtin;
mod expr;
pub use expr::*;
mod types;
pub use types::*;
mod value;
pub use value::*;
pub type Evaluator<T> = Box<dyn Fn(Vec<SPathValue<T>>) -> SPathValue<T>>;
pub struct Function<T: VariantValue> {
name: &'static str,
argument_types: Vec<SPathType>,
result_type: SPathType,
evaluator: Evaluator<T>,
}
impl<T: VariantValue> fmt::Debug for Function<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Function")
.field("name", &self.name)
.field("argument_types", &self.argument_types)
.field("result_type", &self.result_type)
.finish_non_exhaustive()
}
}
impl<T: VariantValue> Function<T> {
pub fn new(
name: &'static str,
argument_types: Vec<SPathType>,
result_type: SPathType,
evaluator: Evaluator<T>,
) -> Self {
Self {
name,
argument_types,
result_type,
evaluator,
}
}
pub fn name(&self) -> &str {
self.name
}
pub fn argument_types(&self) -> &[SPathType] {
self.argument_types.as_slice()
}
pub fn result_type(&self) -> SPathType {
self.result_type
}
pub fn evaluate<'a>(&self, args: Vec<SPathValue<'a, T>>) -> SPathValue<'a, T> {
(self.evaluator)(args)
}
pub fn validate<Registry: FunctionRegistry<Value = T>>(
&self,
args: &[FunctionExprArg],
registry: &Registry,
) -> Result<(), FunctionValidationError> {
let argument_types = self.argument_types();
if args.len() != argument_types.len() {
return Err(FunctionValidationError::NumberOfArgsMismatch {
name: self.name().to_string(),
expected: 1,
received: args.len(),
});
}
for (i, arg) in args.iter().enumerate() {
let ty = argument_types[i];
let kind = arg.as_type_kind(registry)?;
if !kind.converts_to(ty) {
return Err(FunctionValidationError::MismatchTypeKind {
name: self.name().to_string(),
expected: ty,
received: kind,
position: i,
});
}
}
Ok(())
}
}
#[doc(hidden)]
pub trait FunctionRegistry {
type Value: VariantValue;
fn get(&self, name: &str) -> Option<Function<Self::Value>>;
}
impl<Registry> FunctionRegistry for Arc<Registry>
where
Registry: FunctionRegistry,
{
type Value = Registry::Value;
fn get(&self, name: &str) -> Option<Function<Self::Value>> {
(**self).get(name)
}
}
#[derive(Debug, Clone, Copy)]
pub struct BuiltinFunctionRegistry<T: VariantValue> {
phantom: PhantomData<T>,
}
impl<T: VariantValue> Default for BuiltinFunctionRegistry<T> {
fn default() -> Self {
Self {
phantom: PhantomData,
}
}
}
impl<T: VariantValue> FunctionRegistry for BuiltinFunctionRegistry<T> {
type Value = T;
fn get(&self, name: &str) -> Option<Function<Self::Value>> {
match name.to_lowercase().as_str() {
"count" => Some(count()),
"length" => Some(length()),
"value" => Some(value()),
#[cfg(feature = "regex")]
"match" => Some(matches()),
#[cfg(feature = "regex")]
"search" => Some(search()),
_ => None,
}
}
}