use arrow::datatypes::DataType;
pub const TIMEZONE_WILDCARD: &str = "+TZ";
pub const FIXED_SIZE_LIST_WILDCARD: i32 = i32::MIN;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum Volatility {
Immutable,
Stable,
Volatile,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
pub enum TypeSignature {
Variadic(Vec<DataType>),
UserDefined,
VariadicAny,
Uniform(usize, Vec<DataType>),
Exact(Vec<DataType>),
Coercible(Vec<DataType>),
Any(usize),
OneOf(Vec<TypeSignature>),
ArraySignature(ArrayFunctionSignature),
Numeric(usize),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
pub enum ArrayFunctionSignature {
ArrayAndElement,
ElementAndArray,
ArrayAndIndex,
ArrayAndElementAndOptionalIndex,
Array,
MapArray,
}
impl std::fmt::Display for ArrayFunctionSignature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ArrayFunctionSignature::ArrayAndElement => {
write!(f, "array, element")
}
ArrayFunctionSignature::ArrayAndElementAndOptionalIndex => {
write!(f, "array, element, [index]")
}
ArrayFunctionSignature::ElementAndArray => {
write!(f, "element, array")
}
ArrayFunctionSignature::ArrayAndIndex => {
write!(f, "array, index")
}
ArrayFunctionSignature::Array => {
write!(f, "array")
}
ArrayFunctionSignature::MapArray => {
write!(f, "map_array")
}
}
}
}
impl TypeSignature {
pub fn to_string_repr(&self) -> Vec<String> {
match self {
TypeSignature::Variadic(types) => {
vec![format!("{}, ..", Self::join_types(types, "/"))]
}
TypeSignature::Uniform(arg_count, valid_types) => {
vec![std::iter::repeat(Self::join_types(valid_types, "/"))
.take(*arg_count)
.collect::<Vec<String>>()
.join(", ")]
}
TypeSignature::Numeric(num) => {
vec![format!("Numeric({})", num)]
}
TypeSignature::Exact(types) | TypeSignature::Coercible(types) => {
vec![Self::join_types(types, ", ")]
}
TypeSignature::Any(arg_count) => {
vec![std::iter::repeat("Any")
.take(*arg_count)
.collect::<Vec<&str>>()
.join(", ")]
}
TypeSignature::UserDefined => {
vec!["UserDefined".to_string()]
}
TypeSignature::VariadicAny => vec!["Any, .., Any".to_string()],
TypeSignature::OneOf(sigs) => {
sigs.iter().flat_map(|s| s.to_string_repr()).collect()
}
TypeSignature::ArraySignature(array_signature) => {
vec![array_signature.to_string()]
}
}
}
pub fn join_types<T: std::fmt::Display>(types: &[T], delimiter: &str) -> String {
types
.iter()
.map(|t| t.to_string())
.collect::<Vec<String>>()
.join(delimiter)
}
pub fn supports_zero_argument(&self) -> bool {
match &self {
TypeSignature::Exact(vec) => vec.is_empty(),
TypeSignature::Uniform(0, _) | TypeSignature::Any(0) => true,
TypeSignature::OneOf(types) => types
.iter()
.any(|type_sig| type_sig.supports_zero_argument()),
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
pub struct Signature {
pub type_signature: TypeSignature,
pub volatility: Volatility,
}
impl Signature {
pub fn new(type_signature: TypeSignature, volatility: Volatility) -> Self {
Signature {
type_signature,
volatility,
}
}
pub fn variadic(common_types: Vec<DataType>, volatility: Volatility) -> Self {
Self {
type_signature: TypeSignature::Variadic(common_types),
volatility,
}
}
pub fn user_defined(volatility: Volatility) -> Self {
Self {
type_signature: TypeSignature::UserDefined,
volatility,
}
}
pub fn numeric(arg_count: usize, volatility: Volatility) -> Self {
Self {
type_signature: TypeSignature::Numeric(arg_count),
volatility,
}
}
pub fn variadic_any(volatility: Volatility) -> Self {
Self {
type_signature: TypeSignature::VariadicAny,
volatility,
}
}
pub fn uniform(
arg_count: usize,
valid_types: Vec<DataType>,
volatility: Volatility,
) -> Self {
Self {
type_signature: TypeSignature::Uniform(arg_count, valid_types),
volatility,
}
}
pub fn exact(exact_types: Vec<DataType>, volatility: Volatility) -> Self {
Signature {
type_signature: TypeSignature::Exact(exact_types),
volatility,
}
}
pub fn coercible(target_types: Vec<DataType>, volatility: Volatility) -> Self {
Self {
type_signature: TypeSignature::Coercible(target_types),
volatility,
}
}
pub fn any(arg_count: usize, volatility: Volatility) -> Self {
Signature {
type_signature: TypeSignature::Any(arg_count),
volatility,
}
}
pub fn one_of(type_signatures: Vec<TypeSignature>, volatility: Volatility) -> Self {
Signature {
type_signature: TypeSignature::OneOf(type_signatures),
volatility,
}
}
pub fn array_and_element(volatility: Volatility) -> Self {
Signature {
type_signature: TypeSignature::ArraySignature(
ArrayFunctionSignature::ArrayAndElement,
),
volatility,
}
}
pub fn array_and_element_and_optional_index(volatility: Volatility) -> Self {
Signature {
type_signature: TypeSignature::ArraySignature(
ArrayFunctionSignature::ArrayAndElementAndOptionalIndex,
),
volatility,
}
}
pub fn element_and_array(volatility: Volatility) -> Self {
Signature {
type_signature: TypeSignature::ArraySignature(
ArrayFunctionSignature::ElementAndArray,
),
volatility,
}
}
pub fn array_and_index(volatility: Volatility) -> Self {
Signature {
type_signature: TypeSignature::ArraySignature(
ArrayFunctionSignature::ArrayAndIndex,
),
volatility,
}
}
pub fn array(volatility: Volatility) -> Self {
Signature {
type_signature: TypeSignature::ArraySignature(ArrayFunctionSignature::Array),
volatility,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn supports_zero_argument_tests() {
let positive_cases = vec![
TypeSignature::Exact(vec![]),
TypeSignature::Uniform(0, vec![DataType::Float64]),
TypeSignature::Any(0),
TypeSignature::OneOf(vec![
TypeSignature::Exact(vec![DataType::Int8]),
TypeSignature::Any(0),
TypeSignature::Uniform(1, vec![DataType::Int8]),
]),
];
for case in positive_cases {
assert!(
case.supports_zero_argument(),
"Expected {:?} to support zero arguments",
case
);
}
let negative_cases = vec![
TypeSignature::Exact(vec![DataType::Utf8]),
TypeSignature::Uniform(1, vec![DataType::Float64]),
TypeSignature::Any(1),
TypeSignature::VariadicAny,
TypeSignature::OneOf(vec![
TypeSignature::Exact(vec![DataType::Int8]),
TypeSignature::Uniform(1, vec![DataType::Int8]),
]),
];
for case in negative_cases {
assert!(
!case.supports_zero_argument(),
"Expected {:?} not to support zero arguments",
case
);
}
}
#[test]
fn type_signature_partial_ord() {
assert!(TypeSignature::UserDefined < TypeSignature::VariadicAny);
assert!(TypeSignature::UserDefined < TypeSignature::Any(1));
assert!(
TypeSignature::Uniform(1, vec![DataType::Null])
< TypeSignature::Uniform(1, vec![DataType::Boolean])
);
assert!(
TypeSignature::Uniform(1, vec![DataType::Null])
< TypeSignature::Uniform(2, vec![DataType::Null])
);
assert!(
TypeSignature::Uniform(usize::MAX, vec![DataType::Null])
< TypeSignature::Exact(vec![DataType::Null])
);
}
}