vortex_array/arrays/scalar_fn/
array.rs1use std::fmt::Display;
5use std::fmt::Formatter;
6
7use smallvec::SmallVec;
8use vortex_error::VortexExpect;
9use vortex_error::VortexResult;
10use vortex_error::vortex_bail;
11use vortex_error::vortex_ensure;
12
13use crate::ArrayRef;
14use crate::ArraySlots;
15use crate::array::Array;
16use crate::array::ArrayParts;
17use crate::array::TypedArrayRef;
18use crate::arrays::ScalarFn;
19use crate::dtype::DType;
20use crate::scalar_fn::ScalarFnRef;
21use crate::scalar_fn::fns::literal::Literal;
22
23#[derive(Clone, Debug)]
26pub struct ScalarFnData {
27 pub(super) scalar_fn: ScalarFnRef,
28}
29
30impl Display for ScalarFnData {
31 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32 write!(f, "scalar_fn: {}", self.scalar_fn)
33 }
34}
35
36impl ScalarFnData {
37 #[allow(clippy::inline_always)]
39 #[inline(always)]
40 pub fn scalar_fn(&self) -> &ScalarFnRef {
41 &self.scalar_fn
42 }
43}
44
45pub trait ScalarFnArrayExt: TypedArrayRef<ScalarFn> {
46 fn scalar_fn(&self) -> &ScalarFnRef {
47 &self.scalar_fn
48 }
49
50 fn child_at(&self, idx: usize) -> &ArrayRef {
51 self.slots()[idx]
52 .as_ref()
53 .vortex_expect("ScalarFnArray child slot")
54 }
55
56 fn child_count(&self) -> usize {
57 self.slots().len()
58 }
59
60 fn nchildren(&self) -> usize {
61 self.child_count()
62 }
63
64 fn get_child(&self, idx: usize) -> &ArrayRef {
65 self.child_at(idx)
66 }
67
68 fn iter_children(&self) -> impl Iterator<Item = &ArrayRef> + '_ {
69 (0..self.child_count()).map(|idx| self.child_at(idx))
70 }
71
72 fn children(&self) -> Vec<ArrayRef> {
73 self.iter_children().cloned().collect()
74 }
75}
76impl<T: TypedArrayRef<ScalarFn>> ScalarFnArrayExt for T {}
77
78impl Array<ScalarFn> {
79 pub fn try_new(
81 scalar_fn: ScalarFnRef,
82 children: impl IntoIterator<Item = ArrayRef>,
83 ) -> VortexResult<Self> {
84 let slots: ArraySlots = children.into_iter().map(Some).collect();
85 let len = Self::infer_len(&slots)?;
86 Self::try_new_from_slots(scalar_fn, slots, len)
87 }
88
89 pub fn try_new_with_len(
94 scalar_fn: ScalarFnRef,
95 children: impl IntoIterator<Item = ArrayRef>,
96 len: usize,
97 ) -> VortexResult<Self> {
98 let slots: ArraySlots = children.into_iter().map(Some).collect();
99 Self::try_new_from_slots(scalar_fn, slots, len)
100 }
101
102 #[inline]
103 fn try_new_from_slots(
104 scalar_fn: ScalarFnRef,
105 slots: ArraySlots,
106 len: usize,
107 ) -> VortexResult<Self> {
108 Self::validate_not_literal(&scalar_fn)?;
109 Self::validate_arity(&scalar_fn, slots.len())?;
110 Self::validate_children_len(&slots, len)?;
111
112 let arg_dtypes = Self::arg_dtypes(&slots);
113 let dtype = scalar_fn.return_dtype(&arg_dtypes)?;
114
115 Ok(unsafe { Self::new_from_validated_slots(scalar_fn, dtype, slots, len) })
116 }
117
118 #[inline]
122 unsafe fn new_from_validated_slots(
123 scalar_fn: ScalarFnRef,
124 dtype: DType,
125 slots: ArraySlots,
126 len: usize,
127 ) -> Self {
128 let vtable = ScalarFn { id: scalar_fn.id() };
129 let data = ScalarFnData { scalar_fn };
130 unsafe { Array::from_parts_unchecked(ArrayParts::new(vtable, dtype, len, data, slots)) }
131 }
132
133 #[inline]
134 fn arg_dtypes(slots: &[Option<ArrayRef>]) -> SmallVec<[DType; 4]> {
135 let mut arg_dtypes = SmallVec::with_capacity(slots.len());
136 for child in slots.iter().flatten() {
137 arg_dtypes.push(child.dtype().clone());
138 }
139 arg_dtypes
140 }
141
142 #[inline]
143 fn infer_len(slots: &[Option<ArrayRef>]) -> VortexResult<usize> {
144 let Some(child) = slots.first().and_then(Option::as_ref) else {
145 vortex_bail!("ScalarFnArray length cannot be inferred without children");
146 };
147 Ok(child.len())
148 }
149
150 #[inline]
158 pub(super) fn validate_not_literal(scalar_fn: &ScalarFnRef) -> VortexResult<()> {
159 vortex_ensure!(
160 !scalar_fn.is::<Literal>(),
161 "ScalarFnArray cannot wrap a literal, use ConstantArray instead"
162 );
163 Ok(())
164 }
165
166 #[inline]
167 fn validate_arity(scalar_fn: &ScalarFnRef, child_count: usize) -> VortexResult<()> {
168 let arity = scalar_fn.signature().arity();
169 vortex_ensure!(
170 arity.matches(child_count),
171 "ScalarFnArray requires {arity} children, got {child_count}"
172 );
173 Ok(())
174 }
175
176 #[inline]
177 fn validate_children_len(slots: &[Option<ArrayRef>], len: usize) -> VortexResult<()> {
178 for child in slots.iter().flatten() {
179 vortex_ensure!(
180 child.len() == len,
181 "ScalarFnArray must have children equal to the array length"
182 );
183 }
184 Ok(())
185 }
186}