vortex_array/expr/functions/
scalar.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::any::Any;
5use std::fmt::Debug;
6use std::fmt::Display;
7use std::fmt::Formatter;
8use std::hash::Hash;
9use std::hash::Hasher;
10
11use vortex_dtype::DType;
12use vortex_error::VortexResult;
13use vortex_utils::debug_with::DebugWith;
14use vortex_vector::Datum;
15
16use crate::expr::Expression;
17use crate::expr::StatsCatalog;
18use crate::expr::functions::ArgName;
19use crate::expr::functions::Arity;
20use crate::expr::functions::FunctionId;
21use crate::expr::functions::NullHandling;
22use crate::expr::functions::ScalarFnVTable;
23use crate::expr::functions::VTable;
24use crate::expr::functions::execution::ExecutionArgs;
25use crate::expr::stats::Stat;
26
27/// An instance of a scalar function bound to some invocation options.
28pub struct ScalarFn {
29    vtable: ScalarFnVTable,
30    options: Box<dyn Any + Send + Sync>,
31}
32
33impl ScalarFn {
34    /// Create a new scalar function instance.
35    pub fn new<V: VTable>(vtable: V, options: V::Options) -> ScalarFn {
36        let vtable = ScalarFnVTable::new::<V>(vtable);
37        let options = Box::new(options);
38        ScalarFn { vtable, options }
39    }
40
41    /// Create a new scalar function instance from a static vtable.
42    pub fn new_static<V: VTable>(vtable: &'static V, options: V::Options) -> ScalarFn {
43        let vtable = ScalarFnVTable::new_static(vtable);
44        let options = Box::new(options);
45        ScalarFn { vtable, options }
46    }
47
48    /// Create a new scalar function instance.
49    ///
50    /// # Safety
51    ///
52    /// The options must be of the correct type for the given vtable.
53    pub(crate) unsafe fn new_unchecked(
54        vtable: ScalarFnVTable,
55        options: Box<dyn Any + Send + Sync>,
56    ) -> Self {
57        Self { vtable, options }
58    }
59
60    /// Return the function ID for this scalar function.
61    pub fn id(&self) -> FunctionId {
62        self.vtable.id()
63    }
64
65    /// Return the vtable of this scalar function.
66    pub fn vtable(&self) -> &ScalarFnVTable {
67        &self.vtable
68    }
69
70    /// Get the options for this scalar function.
71    pub fn options(&self) -> ScalarFnOptions<'_> {
72        ScalarFnOptions {
73            vtable: &self.vtable,
74            options: self.options.as_ref(),
75        }
76    }
77
78    /// Return the signature information for this scalar function.
79    pub fn signature(&self) -> ScalarFnSignature<'_> {
80        ScalarFnSignature {
81            vtable: &self.vtable,
82            options: self.options.as_ref(),
83        }
84    }
85
86    pub fn stat_falsification(
87        &self,
88        expr: &Expression,
89        catalog: &dyn StatsCatalog,
90    ) -> Option<Expression> {
91        self.vtable
92            .as_dyn()
93            .stat_falsification(self.options.as_ref(), expr, catalog)
94    }
95
96    pub fn stat_expression(
97        &self,
98        expr: &Expression,
99        stat: Stat,
100        catalog: &dyn StatsCatalog,
101    ) -> Option<Expression> {
102        self.vtable
103            .as_dyn()
104            .stat_expression(self.options.as_ref(), expr, stat, catalog)
105    }
106
107    pub fn return_dtype(&self, arg_types: &[DType]) -> VortexResult<DType> {
108        self.vtable
109            .as_dyn()
110            .return_dtype(self.options.as_ref(), arg_types)
111    }
112
113    pub fn execute(&self, args: &ExecutionArgs) -> VortexResult<Datum> {
114        self.vtable.as_dyn().execute(self.options.as_ref(), args)
115    }
116}
117
118impl Clone for ScalarFn {
119    fn clone(&self) -> Self {
120        Self {
121            vtable: self.vtable.clone(),
122            options: self.vtable.as_dyn().options_clone(self.options.as_ref()),
123        }
124    }
125}
126
127impl Debug for ScalarFn {
128    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
129        f.debug_struct("ScalarFn")
130            .field("id", &self.vtable.id())
131            .field(
132                "options",
133                &DebugWith(|fmt| {
134                    self.vtable
135                        .as_dyn()
136                        .options_debug(self.options.as_ref(), fmt)
137                }),
138            )
139            .finish()
140    }
141}
142
143impl Display for ScalarFn {
144    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
145        write!(f, "{}(", self.vtable.id())?;
146        self.vtable
147            .as_dyn()
148            .options_display(self.options.as_ref(), f)?;
149        write!(f, ")")
150    }
151}
152
153impl PartialEq for ScalarFn {
154    fn eq(&self, other: &Self) -> bool {
155        self.vtable.id() == other.vtable.id()
156            && self
157                .vtable
158                .as_dyn()
159                .options_eq(self.options.as_ref(), other.options.as_ref())
160    }
161}
162impl Eq for ScalarFn {}
163
164impl Hash for ScalarFn {
165    fn hash<H: Hasher>(&self, state: &mut H) {
166        self.vtable.id().hash(state);
167        self.vtable
168            .as_dyn()
169            .options_hash(self.options.as_ref(), state);
170    }
171}
172
173/// Opaque reference to scalar function signature information.
174pub struct ScalarFnSignature<'a> {
175    pub(crate) vtable: &'a ScalarFnVTable,
176    pub(crate) options: &'a dyn Any,
177}
178
179impl ScalarFnSignature<'_> {
180    pub fn arity(&self) -> Arity {
181        self.vtable.as_dyn().arity(self.options)
182    }
183
184    pub fn null_handling(&self) -> NullHandling {
185        self.vtable.as_dyn().null_handling(self.options)
186    }
187
188    pub fn arg_name(&self, arg_idx: usize) -> ArgName {
189        self.vtable.as_dyn().arg_name(self.options, arg_idx)
190    }
191}
192
193/// Opaque reference to scalar function options.
194pub struct ScalarFnOptions<'a> {
195    pub(crate) vtable: &'a ScalarFnVTable,
196    pub(crate) options: &'a dyn Any,
197}
198
199impl<'a> ScalarFnOptions<'a> {
200    /// Get the options as a `dyn Any`.
201    pub fn as_any(&self) -> &'a dyn Any {
202        self.options
203    }
204}
205
206impl Display for ScalarFnOptions<'_> {
207    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
208        self.vtable.as_dyn().options_display(self.options, f)
209    }
210}
211
212impl Debug for ScalarFnOptions<'_> {
213    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
214        self.vtable.as_dyn().options_debug(self.options, f)
215    }
216}
217
218impl ScalarFnOptions<'_> {
219    /// Serializes the options into a byte vector.
220    pub fn serialize(&self) -> VortexResult<Option<Vec<u8>>> {
221        self.vtable.as_dyn().options_serialize(self.options)
222    }
223}