Skip to main content

vortex_array/arrays/slice/
vtable.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::fmt::Debug;
5use std::fmt::Formatter;
6use std::hash::Hash;
7use std::hash::Hasher;
8use std::ops::Range;
9
10use vortex_error::VortexExpect;
11use vortex_error::VortexResult;
12use vortex_error::vortex_bail;
13use vortex_error::vortex_ensure;
14use vortex_error::vortex_panic;
15use vortex_session::VortexSession;
16use vortex_session::registry::CachedId;
17
18use crate::AnyCanonical;
19use crate::ArrayEq;
20use crate::ArrayHash;
21use crate::ArrayParts;
22use crate::ArrayRef;
23use crate::EqMode;
24use crate::array::Array;
25use crate::array::ArrayId;
26use crate::array::ArrayView;
27use crate::array::OperationsVTable;
28use crate::array::VTable;
29use crate::array::ValidityVTable;
30use crate::array::with_empty_buffers;
31use crate::arrays::slice::SliceArraySlotsExt;
32use crate::arrays::slice::array::SliceData;
33use crate::arrays::slice::array::SliceSlots;
34use crate::arrays::slice::rules::PARENT_RULES;
35use crate::buffer::BufferHandle;
36use crate::dtype::DType;
37use crate::executor::ExecutionCtx;
38use crate::executor::ExecutionResult;
39use crate::require_child;
40use crate::scalar::Scalar;
41use crate::serde::ArrayChildren;
42use crate::validity::Validity;
43
44/// A [`Slice`]-encoded Vortex array.
45pub type SliceArray = Array<Slice>;
46
47#[derive(Clone, Debug)]
48pub struct Slice;
49
50impl ArrayHash for SliceData {
51    fn array_hash<H: Hasher>(&self, state: &mut H, _accuracy: EqMode) {
52        self.range.start.hash(state);
53        self.range.end.hash(state);
54    }
55}
56
57impl ArrayEq for SliceData {
58    fn array_eq(&self, other: &Self, _accuracy: EqMode) -> bool {
59        self.range == other.range
60    }
61}
62
63impl VTable for Slice {
64    type TypedArrayData = SliceData;
65    type OperationsVTable = Self;
66    type ValidityVTable = Self;
67    fn id(&self) -> ArrayId {
68        static ID: CachedId = CachedId::new("vortex.slice");
69        *ID
70    }
71
72    fn validate(
73        &self,
74        data: &Self::TypedArrayData,
75        dtype: &DType,
76        len: usize,
77        slots: &[Option<ArrayRef>],
78    ) -> VortexResult<()> {
79        vortex_ensure!(
80            slots[SliceSlots::CHILD].is_some(),
81            "SliceArray child slot must be present"
82        );
83        let child = slots[SliceSlots::CHILD]
84            .as_ref()
85            .vortex_expect("validated child slot");
86        vortex_ensure!(
87            child.dtype() == dtype,
88            "SliceArray dtype {} does not match outer dtype {}",
89            child.dtype(),
90            dtype
91        );
92        vortex_ensure!(
93            data.len() == len,
94            "SliceArray length {} does not match outer length {}",
95            data.len(),
96            len
97        );
98        vortex_ensure!(
99            data.range.end <= child.len(),
100            "SliceArray range {:?} exceeds child length {}",
101            data.range,
102            child.len()
103        );
104        Ok(())
105    }
106
107    fn nbuffers(_array: ArrayView<'_, Self>) -> usize {
108        0
109    }
110
111    fn buffer(_array: ArrayView<'_, Self>, _idx: usize) -> BufferHandle {
112        vortex_panic!("SliceArray has no buffers")
113    }
114
115    fn buffer_name(_array: ArrayView<'_, Self>, _idx: usize) -> Option<String> {
116        None
117    }
118
119    fn with_buffers(
120        &self,
121        array: ArrayView<'_, Self>,
122        buffers: &[BufferHandle],
123    ) -> VortexResult<ArrayParts<Self>> {
124        with_empty_buffers(self, array, buffers)
125    }
126
127    fn slot_name(_array: ArrayView<'_, Self>, idx: usize) -> String {
128        SliceSlots::NAMES[idx].to_string()
129    }
130
131    fn serialize(
132        _array: ArrayView<'_, Self>,
133        _session: &VortexSession,
134    ) -> VortexResult<Option<Vec<u8>>> {
135        // TODO(joe): make this configurable
136        vortex_bail!("Slice array is not serializable")
137    }
138
139    fn deserialize(
140        &self,
141        _dtype: &DType,
142        _len: usize,
143        _metadata: &[u8],
144
145        _buffers: &[BufferHandle],
146        _children: &dyn ArrayChildren,
147        _session: &VortexSession,
148    ) -> VortexResult<ArrayParts<Self>> {
149        vortex_bail!("Slice array is not serializable")
150    }
151
152    fn execute(array: Array<Self>, _ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
153        let array = require_child!(array, array.child(), SliceSlots::CHILD => AnyCanonical);
154
155        debug_assert!(array.child().is_canonical());
156        // TODO(ngates): we should inline canonical slice logic here.
157        array
158            .child()
159            .slice(array.range.clone())
160            .map(ExecutionResult::done)
161    }
162
163    fn reduce_parent(
164        array: ArrayView<'_, Self>,
165        parent: &ArrayRef,
166        child_idx: usize,
167    ) -> VortexResult<Option<ArrayRef>> {
168        PARENT_RULES.evaluate(array, parent, child_idx)
169    }
170}
171impl OperationsVTable<Slice> for Slice {
172    fn scalar_at(
173        array: ArrayView<'_, Slice>,
174        index: usize,
175        ctx: &mut ExecutionCtx,
176    ) -> VortexResult<Scalar> {
177        array.child().execute_scalar(array.range.start + index, ctx)
178    }
179}
180
181impl ValidityVTable<Slice> for Slice {
182    fn validity(array: ArrayView<'_, Slice>) -> VortexResult<Validity> {
183        array.child().validity()?.slice(array.range.clone())
184    }
185}
186
187pub struct SliceMetadata(pub(super) Range<usize>);
188
189impl Debug for SliceMetadata {
190    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
191        write!(f, "{}..{}", self.0.start, self.0.end)
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use vortex_error::VortexResult;
198
199    use crate::IntoArray;
200    use crate::VortexSessionExecute;
201    use crate::array_session;
202    use crate::arrays::PrimitiveArray;
203    use crate::arrays::SliceArray;
204    use crate::assert_arrays_eq;
205
206    #[test]
207    fn test_slice_slice() -> VortexResult<()> {
208        let mut ctx = array_session().create_execution_ctx();
209        // Slice(1..4, Slice(2..8, base)) combines to Slice(3..6, base)
210        let arr = PrimitiveArray::from_iter(0i32..10).into_array();
211        let inner_slice = SliceArray::new(arr, 2..8).into_array();
212        let slice = inner_slice.slice(1..4)?;
213
214        assert_arrays_eq!(slice, PrimitiveArray::from_iter([3i32, 4, 5]), &mut ctx);
215
216        Ok(())
217    }
218}