use polars_core::prelude::{AnyValue, Column, DataType, Field};
use polars_core::scalar::Scalar;
use polars_error::{PolarsResult, polars_err};
use polars_utils::pl_str::PlSmallStr;
use super::{AnonymousColumnsUdf, Expr, OpaqueColumnUdf};
use crate::prelude::{FunctionOptions, new_column_udf};
#[derive(Clone)]
pub struct UserDefinedFunction {
pub name: PlSmallStr,
pub fun: OpaqueColumnUdf,
pub options: FunctionOptions,
}
impl std::fmt::Debug for UserDefinedFunction {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("UserDefinedFunction")
.field("name", &self.name)
.field("fun", &"<FUNC>")
.field("options", &self.options)
.finish()
}
}
impl UserDefinedFunction {
pub fn new(name: PlSmallStr, fun: impl AnonymousColumnsUdf + 'static) -> Self {
Self {
name,
fun: new_column_udf(fun),
options: FunctionOptions::default(),
}
}
pub fn call(self, args: Vec<Expr>) -> Expr {
Expr::AnonymousFunction {
input: args,
function: self.fun,
options: self.options,
fmt_str: Box::new(PlSmallStr::EMPTY),
}
}
}
pub fn infer_udf_output_dtype(
f: &dyn Fn(&[Column]) -> PolarsResult<Column>,
input_fields: &[Field],
) -> Option<DataType> {
{
let numeric_to_one = true;
let num_list_values = 1;
let params = input_fields
.iter()
.map(|f| {
let av = AnyValue::default_value(f.dtype(), numeric_to_one, num_list_values);
let scalar = Scalar::new(f.dtype().clone(), av);
Column::new_scalar(f.name().clone(), scalar, 2)
})
.collect::<Vec<_>>();
if let Ok(c) = f(¶ms) {
return Some(c.dtype().clone());
}
}
None
}
pub fn try_infer_udf_output_dtype(
f: &dyn Fn(&[Column]) -> PolarsResult<Column>,
input_fields: &[Field],
) -> PolarsResult<DataType> {
infer_udf_output_dtype(f, input_fields).ok_or_else(||
polars_err!(
InvalidOperation:
"UDF called without return type, but was not able to infer the output type.\n\nThis used to be allowed but lead to unpredictable results. To fix this problem, either provide a return datatype or execute the UDF in an eager context (e.g. in `map_columns`)."
)
)
}