vortex_array/arrays/primitive/array/
cast.rs1use vortex_error::VortexExpect;
5use vortex_error::vortex_panic;
6
7use super::PrimitiveData;
8use crate::dtype::NativePType;
9
10impl PrimitiveData {
11 pub fn as_slice<T: NativePType>(&self) -> &[T] {
19 if T::PTYPE != self.ptype() {
20 vortex_panic!(
21 "Attempted to get slice of type {} from array of type {}",
22 T::PTYPE,
23 self.ptype()
24 )
25 }
26
27 let byte_buffer = self
28 .buffer
29 .as_host_opt()
30 .vortex_expect("as_slice must be called on host buffer");
31 let raw_slice = byte_buffer.as_ptr();
32
33 unsafe { std::slice::from_raw_parts(raw_slice.cast(), byte_buffer.len() / size_of::<T>()) }
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use std::sync::LazyLock;
41
42 use rstest::rstest;
43 use vortex_buffer::Buffer;
44 use vortex_buffer::buffer;
45 use vortex_session::VortexSession;
46
47 use crate::VortexSessionExecute;
48 use crate::arrays::PrimitiveArray;
49 use crate::arrays::primitive::PrimitiveArrayExt;
50 use crate::assert_arrays_eq;
51 use crate::dtype::DType;
52 use crate::dtype::Nullability;
53 use crate::dtype::PType;
54 use crate::validity::Validity;
55
56 static SESSION: LazyLock<VortexSession> = LazyLock::new(crate::array_session);
57
58 #[test]
59 fn test_downcast_all_invalid() {
60 let array = PrimitiveArray::new(
61 buffer![0_u32, 0, 0, 0, 0, 0, 0, 0, 0, 0],
62 Validity::AllInvalid,
63 );
64
65 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
66 assert_eq!(
67 result.dtype(),
68 &DType::Primitive(PType::U8, Nullability::Nullable)
69 );
70 assert!(matches!(result.validity(), Ok(Validity::AllInvalid)));
71 assert_arrays_eq!(
72 result,
73 PrimitiveArray::from_option_iter([None::<u8>; 10]),
74 &mut SESSION.create_execution_ctx()
75 );
76 }
77
78 #[rstest]
79 #[case(vec![0_i64, 127], PType::U8)]
80 #[case(vec![-128_i64, 127], PType::I8)]
81 #[case(vec![-129_i64, 127], PType::I16)]
82 #[case(vec![-128_i64, 128], PType::I16)]
83 #[case(vec![-32768_i64, 32767], PType::I16)]
84 #[case(vec![-32769_i64, 32767], PType::I32)]
85 #[case(vec![-32768_i64, 32768], PType::I32)]
86 #[case(vec![i32::MIN as i64, i32::MAX as i64], PType::I32)]
87 fn test_downcast_signed(#[case] values: Vec<i64>, #[case] expected_ptype: PType) {
88 let array = PrimitiveArray::from_iter(values.iter().copied());
89 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
90 assert_eq!(
91 result.dtype(),
92 &DType::Primitive(expected_ptype, Nullability::NonNullable)
93 );
94 assert_eq!(result.len(), values.len());
95 let mut ctx = SESSION.create_execution_ctx();
96 for (index, expected) in values.into_iter().enumerate() {
97 assert_eq!(
98 result
99 .execute_scalar(index, &mut ctx)
100 .unwrap()
101 .as_primitive()
102 .as_::<i64>(),
103 Some(expected)
104 );
105 }
106 }
107
108 #[rstest]
109 #[case(vec![0_u64, 255], PType::U8)]
110 #[case(vec![0_u64, 256], PType::U16)]
111 #[case(vec![0_u64, 65535], PType::U16)]
112 #[case(vec![0_u64, 65536], PType::U32)]
113 #[case(vec![0_u64, u32::MAX as u64], PType::U32)]
114 fn test_downcast_unsigned(#[case] values: Vec<u64>, #[case] expected_ptype: PType) {
115 let array = PrimitiveArray::from_iter(values.iter().copied());
116 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
117 assert_eq!(
118 result.dtype(),
119 &DType::Primitive(expected_ptype, Nullability::NonNullable)
120 );
121 assert_eq!(result.len(), values.len());
122 let mut ctx = SESSION.create_execution_ctx();
123 for (index, expected) in values.into_iter().enumerate() {
124 assert_eq!(
125 result
126 .execute_scalar(index, &mut ctx)
127 .unwrap()
128 .as_primitive()
129 .as_::<u64>(),
130 Some(expected)
131 );
132 }
133 }
134
135 #[test]
136 fn test_downcast_keeps_original_if_too_large() {
137 let array = PrimitiveArray::from_iter(vec![0_u64, u64::MAX]);
138 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
139 assert_eq!(result.ptype(), PType::U64);
140 assert_arrays_eq!(
141 result,
142 PrimitiveArray::from_iter([0u64, u64::MAX]),
143 &mut SESSION.create_execution_ctx()
144 );
145 }
146
147 #[test]
148 fn test_downcast_preserves_nullability() {
149 let array = PrimitiveArray::from_option_iter([Some(0_i32), None, Some(127)]);
150 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
151 assert_eq!(
152 result.dtype(),
153 &DType::Primitive(PType::U8, Nullability::Nullable)
154 );
155 assert!(matches!(result.validity(), Ok(Validity::Array(_))));
157 assert_arrays_eq!(
158 result,
159 PrimitiveArray::from_option_iter([Some(0u8), None, Some(127)]),
160 &mut SESSION.create_execution_ctx()
161 );
162 }
163
164 #[test]
165 fn test_downcast_preserves_values() {
166 let values = vec![-100_i16, 0, 100];
167 let array = PrimitiveArray::from_iter(values);
168 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
169
170 assert_eq!(result.ptype(), PType::I8);
171 let downscaled_values: Vec<i8> = result.as_slice::<i8>().to_vec();
173 assert_eq!(downscaled_values, vec![-100_i8, 0, 100]);
174 }
175
176 #[test]
177 fn test_downcast_with_mixed_signs_chooses_signed() {
178 let array = PrimitiveArray::from_iter(vec![-1_i32, 200]);
179 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
180 assert_eq!(result.ptype(), PType::I16);
181 assert_arrays_eq!(
182 result,
183 PrimitiveArray::from_iter([-1i16, 200]),
184 &mut SESSION.create_execution_ctx()
185 );
186 }
187
188 #[test]
189 fn test_downcast_floats() {
190 let array = PrimitiveArray::from_iter(vec![1.0_f32, 2.0, 3.0]);
191 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
192 assert_eq!(result.ptype(), PType::F32);
194 assert_arrays_eq!(
195 result,
196 PrimitiveArray::from_iter([1f32, 2., 3.]),
197 &mut SESSION.create_execution_ctx()
198 );
199 }
200
201 #[test]
202 fn test_downcast_empty_array() {
203 let array = PrimitiveArray::new(Buffer::<i32>::empty(), Validity::AllInvalid);
204 let result = array.narrow(&mut SESSION.create_execution_ctx()).unwrap();
205 let array2 = PrimitiveArray::new(Buffer::<i64>::empty(), Validity::NonNullable);
206 let result2 = array2.narrow(&mut SESSION.create_execution_ctx()).unwrap();
207 assert!(result.is_empty());
208 assert!(result2.is_empty());
209 assert!(matches!(result.validity(), Ok(Validity::AllInvalid)));
211 assert!(matches!(result2.validity(), Ok(Validity::NonNullable)));
212 }
213}