use std::any::TypeId;
use anyhow::bail;
use crate::func::def::{FunctionDef, MatchTestFailure, ParameterBindingProvider, Parameters};
use crate::func::utils::{bindings_must_have_same_type, must_be_same_type};
use crate::types::array::Array;
use crate::types::matcher::{AnyMatcher, ArrayMatcher, ExactMatcher, TupleMatcher};
use crate::types::{Type, BOOLEAN};
#[derive(Default, Clone)]
pub struct If2;
impl FunctionDef for If2 {
fn name(&self) -> &'static str {
"if"
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("condition", ExactMatcher::of(BOOLEAN))
.with("then", AnyMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
Ok(bindings.get_by_index(1)?.typ().clone())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct If3;
impl FunctionDef for If3 {
fn name(&self) -> &'static str {
"if"
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("condition", ExactMatcher::of(BOOLEAN))
.with("then", AnyMatcher::default())
.with("else", AnyMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
must_be_same_type(
vec![
bindings.get_by_index(1)?.typ(),
bindings.get_by_index(2)?.typ(),
]
.into_iter(),
)
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct Case;
impl FunctionDef for Case {
fn name(&self) -> &'static str {
"case"
}
fn parameters(&self) -> Parameters {
Parameters::new().with_var_args(TupleMatcher::of(
ExactMatcher::of(BOOLEAN),
AnyMatcher::default(),
))
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
if bindings.len() == 0 {
bail!(MatchTestFailure::msg("At least one argument is required"));
}
must_be_same_type(bindings.iter().map(|b| match b.typ() {
Type::Tuple(t) => t.elements[1].as_ref(),
_ => unreachable!(),
}))
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct Coalesce;
impl FunctionDef for Coalesce {
fn name(&self) -> &'static str {
"coalesce"
}
fn parameters(&self) -> Parameters {
Parameters::new().with_var_args(AnyMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
bindings_must_have_same_type(bindings)
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct ArrayCoalesce;
impl FunctionDef for ArrayCoalesce {
fn name(&self) -> &'static str {
"array_coalesce"
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("array", ArrayMatcher::default())
.with("default", AnyMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let array_type = bindings.get_by_index(0)?.typ();
let default_type = bindings.get_by_index(1)?.typ();
let element_type = match array_type {
Type::Array(arr) => arr.element_type.as_ref(),
_ => bail!(MatchTestFailure::msg(
"array_coalesce(array, default): first argument must be array"
)),
};
let merged = element_type
.clone()
.merge(default_type.clone())
.map_err(|e| anyhow::anyhow!(MatchTestFailure::wrap(e)))?;
Ok(Array::new(merged).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}