use std::fmt;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::hash::Hash;
use std::sync::Arc;
use itertools::Itertools;
use vortex_error::VortexExpect;
use vortex_error::VortexResult;
use vortex_error::vortex_ensure;
use crate::dtype::DType;
use crate::expr::display::DisplayTreeExpr;
use crate::expr::traversal::TraversalOrder;
use crate::expr::traversal::pre_order_visit_down;
use crate::scalar_fn::ScalarFnRef;
use crate::scalar_fn::ScalarFnVTable;
const NO_CHILDREN: &[Expression] = &[];
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Expression {
Scalar {
scalar_fn: ScalarFnRef,
children: Arc<Vec<Expression>>,
},
Root,
}
impl Expression {
pub fn try_new(
scalar_fn: ScalarFnRef,
children: impl IntoIterator<Item = Expression>,
) -> VortexResult<Self> {
let children = Vec::from_iter(children);
vortex_ensure!(
scalar_fn.signature().arity().matches(children.len()),
"Expression arity mismatch: expected {} children but got {}",
scalar_fn.signature().arity(),
children.len()
);
Ok(Self::Scalar {
scalar_fn,
children: children.into(),
})
}
pub fn is_root(&self) -> bool {
matches!(self, Self::Root)
}
pub fn as_scalar(&self) -> Option<&ScalarFnRef> {
match self {
Self::Scalar { scalar_fn, .. } => Some(scalar_fn),
Self::Root => None,
}
}
pub fn is<V: ScalarFnVTable>(&self) -> bool {
self.as_scalar().is_some_and(|sf| sf.is::<V>())
}
pub fn as_opt<V: ScalarFnVTable>(&self) -> Option<&V::Options> {
self.as_scalar().and_then(|sf| sf.as_opt::<V>())
}
pub fn as_<V: ScalarFnVTable>(&self) -> &V::Options {
self.as_opt::<V>()
.vortex_expect("Expression options type mismatch")
}
pub fn children(&self) -> &[Expression] {
match self {
Self::Scalar { children, .. } => children.as_slice(),
Self::Root => NO_CHILDREN,
}
}
pub fn child(&self, n: usize) -> &Expression {
&self.children()[n]
}
pub fn with_children(
self,
children: impl IntoIterator<Item = Expression>,
) -> VortexResult<Self> {
let children = Vec::from_iter(children);
match &self {
Self::Root => {
vortex_ensure!(
children.is_empty(),
"Expression arity mismatch: root expects 0 children but got {}",
children.len()
);
Ok(Self::Root)
}
Self::Scalar { scalar_fn, .. } => {
vortex_ensure!(
scalar_fn.signature().arity().matches(children.len()),
"Expression arity mismatch: expected {} children but got {}",
scalar_fn.signature().arity(),
children.len()
);
Ok(Self::Scalar {
scalar_fn: scalar_fn.clone(),
children: children.into(),
})
}
}
}
pub fn return_dtype(&self, scope: &DType) -> VortexResult<DType> {
match self {
Self::Root => Ok(scope.clone()),
Self::Scalar {
scalar_fn,
children,
} => {
let dtypes: Vec<_> = children
.iter()
.map(|c| c.return_dtype(scope))
.try_collect()?;
scalar_fn.return_dtype(&dtypes)
}
}
}
pub fn validity(&self) -> VortexResult<Expression> {
match self {
Self::Root => Ok(Self::Root),
Self::Scalar { scalar_fn, .. } => scalar_fn.validity(self),
}
}
pub fn fmt_sql(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Root => write!(f, "$"),
Self::Scalar { scalar_fn, .. } => scalar_fn.fmt_sql(self, f),
}
}
pub fn display_tree(&self) -> impl Display {
DisplayTreeExpr(self)
}
pub fn contains<E: ScalarFnVTable>(&self) -> VortexResult<bool> {
let mut contains = false;
pre_order_visit_down(self, |node| {
if node.is::<E>() {
contains = true;
return Ok(TraversalOrder::Stop);
}
Ok(TraversalOrder::Continue)
})?;
Ok(contains)
}
}
impl Display for Expression {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.fmt_sql(f)
}
}
impl Drop for Expression {
fn drop(&mut self) {
let Self::Scalar { children, .. } = self else {
return;
};
let Some(children) = Arc::get_mut(children) else {
return;
};
let mut children_to_drop = std::mem::take(children);
while let Some(mut child) = children_to_drop.pop() {
if let Self::Scalar { children, .. } = &mut child
&& let Some(expr_children) = Arc::get_mut(children)
{
children_to_drop.append(expr_children);
}
}
}
}