use std::{cell::RefCell, sync::Arc};
use super::{
binary::{self, BinaryOperator},
concatenate, copying,
datetime::{self as datetime_ops, DatetimeComponent, DatetimeRoundingFrequency},
reduction::{self, ReduceAgg, ScanAgg, ScanType},
replace::{self, FillPolicy},
search,
strings::{self as string_ops, StringSliceOptions, StripSide},
unary::{self, UnaryOperator},
};
use crate::{
core::{
column::Column,
error::{Error, ErrorCode, Result},
scalar::{Scalar, ScalarValue},
types::{DataType, NullPolicy, TimestampResolution, TypeId},
},
frame::{dataframe::DataFrame, series::Series},
hash::{FastHashMap, fast_hash_map_with_capacity},
internal::resolve::missing_column_error,
runtime::{
Exec,
execution_domain::{EnteredExecution, ExecutionDomain},
},
};
struct ExprEvalContext<'df> {
df: &'df DataFrame,
output_domain: Arc<ExecutionDomain>,
exec_options: EnteredExecution,
operation: &'static str,
normalized_columns: RefCell<FastHashMap<String, Series>>,
}
impl<'df> ExprEvalContext<'df> {
fn new(df: &'df DataFrame, overrides: Exec<'_>, operation: &'static str) -> Result<Self> {
let output_domain = overrides.resolve_output_domain(df.execution_domain())?;
let exec_options = output_domain.enter_execution()?;
Ok(Self {
df,
output_domain,
exec_options,
operation,
normalized_columns: RefCell::new(fast_hash_map_with_capacity(df.num_columns())),
})
}
fn with_output_domain(
df: &'df DataFrame,
output_domain: Arc<ExecutionDomain>,
operation: &'static str,
) -> Result<Self> {
let exec_options = output_domain.enter_execution()?;
Ok(Self {
df,
output_domain,
exec_options,
operation,
normalized_columns: RefCell::new(fast_hash_map_with_capacity(df.num_columns())),
})
}
fn required_exec_options(&self) -> &cudf_sys::cudf_exec_options_t {
self.exec_options.options()
}
fn output_domain(&self) -> Arc<ExecutionDomain> {
Arc::clone(&self.output_domain)
}
fn column(&self, name: &str) -> Result<Series> {
if let Some(series) = self.normalized_columns.borrow().get(name) {
return Ok(series.clone());
}
let column =
self.df.columns_map().get(name).cloned().ok_or_else(|| missing_column_error(self.operation, name))?;
let normalized = if ExecutionDomain::same_provenance(column.execution_domain(), &self.output_domain) {
column
} else {
Arc::new(
column
.copy_into_domain(Arc::clone(&self.output_domain), self.operation)
.map_err(|error| error.with_column(name.to_string()))?,
)
};
let normalized = Series::from_column_arc(normalized).map_err(|error| error.with_column(name.to_string()))?;
self.normalized_columns.borrow_mut().insert(name.to_string(), normalized.clone());
Ok(normalized)
}
fn literal(&self, value: &ScalarValue) -> Result<Series> {
let scalar = Scalar::from_scalar_value_in_domain(value, &self.output_domain)?;
let col = Column::from_scalar(&scalar, self.df.num_rows())?;
Series::from_column(col)
}
fn wrap_column(&self, column: Column) -> Result<Series> {
Series::from_column(column)
}
}
pub(crate) fn eval_many_in_context<'a, I>(
df: &DataFrame,
overrides: Exec<'_>,
operation: &'static str,
exprs: I,
) -> Result<(Arc<ExecutionDomain>, Vec<Series>)>
where
I: IntoIterator<Item = &'a Expr>,
{
let ctx = ExprEvalContext::new(df, overrides, operation)?;
let output_domain = ctx.output_domain();
let results = exprs.into_iter().map(|expr| expr.eval_with_context(&ctx)).collect::<Result<_>>()?;
Ok((output_domain, results))
}
pub(crate) fn eval_in_output_domain(
df: &DataFrame,
output_domain: Arc<ExecutionDomain>,
operation: &'static str,
expr: &Expr,
) -> Result<Series> {
let ctx = ExprEvalContext::with_output_domain(df, output_domain, operation)?;
expr.eval_with_context(&ctx)
}
mod agg;
mod core;
mod datetime;
mod lit;
mod strings;
mod when;
pub use core::{Expr, IntoExpr, col, concat};
pub use agg::ExprAggNamespace;
pub use datetime::ExprDatetimeNamespace;
pub use lit::{lit, lit_null};
pub use strings::{ExprStringNamespace, StringOperator};
pub use when::{ThenBuilder, WhenBuilder, when};