use arrow::legacy::error::{polars_bail, PolarsResult};
use polars_core::prelude::Field;
use polars_core::schema::Schema;
use polars_utils::pl_str::PlSmallStr;
use super::{ColumnsUdf, Expr, GetOutput, OpaqueColumnUdf};
use crate::prelude::{new_column_udf, Context, FunctionOptions};
#[derive(Clone)]
pub struct UserDefinedFunction {
pub name: PlSmallStr,
pub input_fields: Vec<Field>,
pub return_type: GetOutput,
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("signature", &self.input_fields)
.field("fun", &"<FUNC>")
.field("options", &self.options)
.finish()
}
}
impl UserDefinedFunction {
pub fn new(
name: PlSmallStr,
input_fields: Vec<Field>,
return_type: GetOutput,
fun: impl ColumnsUdf + 'static,
) -> Self {
Self {
name,
input_fields,
return_type,
fun: new_column_udf(fun),
options: FunctionOptions::default(),
}
}
pub fn call(self, args: Vec<Expr>) -> PolarsResult<Expr> {
if args.len() != self.input_fields.len() {
polars_bail!(InvalidOperation: "expected {} arguments, got {}", self.input_fields.len(), args.len())
}
let schema = Schema::from_iter(self.input_fields);
if args
.iter()
.map(|e| e.to_field(&schema, Context::Default))
.collect::<PolarsResult<Vec<_>>>()
.is_err()
{
polars_bail!(InvalidOperation: "unexpected field in UDF \nexpected: {:?}\n received {:?}", schema, args)
};
Ok(Expr::AnonymousFunction {
input: args,
function: self.fun,
output_type: self.return_type,
options: self.options,
})
}
pub fn call_unchecked(self, args: Vec<Expr>) -> Expr {
Expr::AnonymousFunction {
input: args,
function: self.fun,
output_type: self.return_type.clone(),
options: self.options,
}
}
}