use std::borrow::Cow;
use std::fmt;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::hash::Hash;
use arcref::ArcRef;
use vortex_error::VortexExpect;
use vortex_error::VortexResult;
use vortex_error::vortex_bail;
use vortex_error::vortex_err;
use vortex_session::VortexSession;
use crate::ArrayRef;
use crate::ExecutionCtx;
use crate::IntoArray;
use crate::arrays::ScalarFn;
use crate::arrays::ScalarFnArray;
use crate::dtype::DType;
use crate::expr::BoundExpression;
use crate::expr::Expression;
use crate::expr::display::ExprDisplay;
use crate::scalar_fn::ScalarFnId;
use crate::scalar_fn::ScalarFnRef;
use crate::scalar_fn::TypedScalarFnInstance;
pub trait ScalarFnVTable: 'static + Sized + Clone + Send + Sync {
type Options: 'static + Send + Sync + Clone + Debug + Display + PartialEq + Eq + Hash;
fn id(&self) -> ScalarFnId;
fn serialize(&self, options: &Self::Options) -> VortexResult<Option<Vec<u8>>> {
_ = options;
Ok(None)
}
fn deserialize(
&self,
_metadata: &[u8],
_session: &VortexSession,
) -> VortexResult<Self::Options> {
vortex_bail!("Expression {} is not deserializable", self.id());
}
fn arity(&self, options: &Self::Options) -> Arity;
fn child_name(&self, options: &Self::Options, child_idx: usize) -> ChildName;
fn fmt_sql(
&self,
options: &Self::Options,
expr: &dyn ExprDisplay,
f: &mut Formatter<'_>,
) -> fmt::Result {
write!(f, "{}(", self.id())?;
let nchildren = expr.display_children_count();
for i in 0..nchildren {
Display::fmt(expr.display_child(i), f)?;
if i + 1 < nchildren {
write!(f, ", ")?;
}
}
let opts = format!("{}", options);
if !opts.is_empty() {
write!(f, ", opts={}", opts)?;
}
write!(f, ")")
}
fn return_dtype(&self, options: &Self::Options, args: &[DType]) -> VortexResult<DType>;
fn execute(
&self,
options: &Self::Options,
args: &dyn ExecutionArgs,
ctx: &mut ExecutionCtx,
) -> VortexResult<ArrayRef>;
fn reduce<T: ReduceNode>(&self, options: &Self::Options, node: &T) -> VortexResult<Option<T>> {
_ = options;
_ = node;
Ok(None)
}
fn simplify(
&self,
options: &Self::Options,
expr: &Expression,
ctx: &dyn SimplifyCtx,
) -> VortexResult<Option<Expression>> {
_ = options;
_ = expr;
_ = ctx;
Ok(None)
}
fn simplify_untyped(
&self,
options: &Self::Options,
expr: &Expression,
) -> VortexResult<Option<Expression>> {
_ = options;
_ = expr;
Ok(None)
}
fn validity(
&self,
options: &Self::Options,
expression: &Expression,
) -> VortexResult<Option<Expression>> {
_ = (options, expression);
Ok(None)
}
fn is_strict(&self, options: &Self::Options) -> bool {
_ = options;
false
}
fn is_infallible(&self, options: &Self::Options) -> bool {
_ = options;
false
}
}
pub trait ReduceNode: Clone {
fn node_dtype(&self) -> VortexResult<DType>;
fn scalar_fn(&self) -> Option<&ScalarFnRef>;
fn child(&self, idx: usize) -> Self;
fn child_count(&self) -> usize;
fn new_node(&self, scalar_fn: ScalarFnRef, children: &[Self]) -> VortexResult<Self>;
}
#[derive(Clone)]
pub struct ExpressionReduceNode<'a> {
expression: Cow<'a, Expression>,
scope: &'a DType,
}
impl<'a> ExpressionReduceNode<'a> {
pub fn new(expression: &'a Expression, scope: &'a DType) -> Self {
Self {
expression: Cow::Borrowed(expression),
scope,
}
}
pub fn expression(&self) -> &Expression {
&self.expression
}
pub fn into_expression(self) -> Expression {
self.expression.into_owned()
}
}
impl ReduceNode for ExpressionReduceNode<'_> {
fn node_dtype(&self) -> VortexResult<DType> {
self.expression.return_dtype(self.scope)
}
fn scalar_fn(&self) -> Option<&ScalarFnRef> {
self.expression.as_scalar()
}
fn child(&self, idx: usize) -> Self {
let expression = match &self.expression {
Cow::Borrowed(expression) => Cow::Borrowed(expression.child(idx)),
Cow::Owned(expression) => Cow::Owned(expression.child(idx).clone()),
};
Self {
expression,
scope: self.scope,
}
}
fn child_count(&self) -> usize {
self.expression.children().len()
}
fn new_node(&self, scalar_fn: ScalarFnRef, children: &[Self]) -> VortexResult<Self> {
let expression = Expression::try_new(
scalar_fn,
children
.iter()
.map(|c| c.expression.as_ref().clone())
.collect::<Vec<_>>(),
)?;
Ok(Self {
expression: Cow::Owned(expression),
scope: self.scope,
})
}
}
#[derive(Clone)]
pub struct ArrayReduceNode<'a> {
array: Cow<'a, ArrayRef>,
}
impl<'a> ArrayReduceNode<'a> {
pub fn new(array: &'a ArrayRef) -> Self {
Self {
array: Cow::Borrowed(array),
}
}
pub fn array(&self) -> &ArrayRef {
&self.array
}
pub fn into_array(self) -> ArrayRef {
self.array.into_owned()
}
}
impl ReduceNode for ArrayReduceNode<'_> {
fn node_dtype(&self) -> VortexResult<DType> {
Ok(self.array.dtype().clone())
}
fn scalar_fn(&self) -> Option<&ScalarFnRef> {
self.array
.as_opt::<ScalarFn>()
.map(|a| a.data().scalar_fn())
}
fn child(&self, idx: usize) -> Self {
let array = match &self.array {
Cow::Borrowed(array) => Cow::Borrowed(
array
.children_iter()
.nth(idx)
.vortex_expect("child idx out of bounds"),
),
Cow::Owned(array) => Cow::Owned(
array
.nth_child(idx)
.vortex_expect("child idx out of bounds"),
),
};
Self { array }
}
fn child_count(&self) -> usize {
self.array.nchildren()
}
fn new_node(&self, scalar_fn: ScalarFnRef, children: &[Self]) -> VortexResult<Self> {
let array = ScalarFnArray::try_new_with_len(
scalar_fn,
children.iter().map(|c| c.array.as_ref().clone()).collect(),
self.array.len(),
)?;
Ok(Self {
array: Cow::Owned(array.into_array()),
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Arity {
Exact(usize),
Variadic { min: usize, max: Option<usize> },
}
impl Display for Arity {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Arity::Exact(n) => write!(f, "{}", n),
Arity::Variadic { min, max } => match max {
Some(max) if min == max => write!(f, "{}", min),
Some(max) => write!(f, "{}..{}", min, max),
None => write!(f, "{}+", min),
},
}
}
}
impl Arity {
pub fn matches(&self, arg_count: usize) -> bool {
match self {
Arity::Exact(m) => *m == arg_count,
Arity::Variadic { min, max } => {
if arg_count < *min {
return false;
}
if let Some(max) = max
&& arg_count > *max
{
return false;
}
true
}
}
}
}
pub trait SimplifyCtx {
fn return_dtype(&self, expr: &Expression) -> VortexResult<DType>;
}
pub trait ExecutionArgs {
fn get(&self, index: usize) -> VortexResult<ArrayRef>;
fn num_inputs(&self) -> usize;
fn row_count(&self) -> usize;
}
pub struct VecExecutionArgs {
inputs: Vec<ArrayRef>,
row_count: usize,
}
impl VecExecutionArgs {
pub fn new(inputs: Vec<ArrayRef>, row_count: usize) -> Self {
Self { inputs, row_count }
}
}
impl ExecutionArgs for VecExecutionArgs {
fn get(&self, index: usize) -> VortexResult<ArrayRef> {
self.inputs.get(index).cloned().ok_or_else(|| {
vortex_err!(
"Input index {} out of bounds (num_inputs={})",
index,
self.inputs.len()
)
})
}
fn num_inputs(&self) -> usize {
self.inputs.len()
}
fn row_count(&self) -> usize {
self.row_count
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct EmptyOptions;
impl Display for EmptyOptions {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "")
}
}
pub trait ScalarFnVTableExt: ScalarFnVTable {
fn bind(&self, options: Self::Options) -> ScalarFnRef {
TypedScalarFnInstance::new(self.clone(), options).erased()
}
fn new_expr(
&self,
options: Self::Options,
children: impl IntoIterator<Item = Expression>,
) -> Expression {
Self::try_new_expr(self, options, children).vortex_expect("Failed to create expression")
}
fn try_new_expr(
&self,
options: Self::Options,
children: impl IntoIterator<Item = Expression>,
) -> VortexResult<Expression> {
Expression::try_new(self.bind(options), children)
}
fn try_new_bound_expr(
&self,
options: Self::Options,
children: impl IntoIterator<Item = BoundExpression>,
) -> VortexResult<BoundExpression> {
BoundExpression::try_new(self.bind(options), children)
}
}
impl<V: ScalarFnVTable> ScalarFnVTableExt for V {}
pub type ChildName = ArcRef<str>;