1use vortex_array::ArrayView;
5use vortex_array::ExecutionCtx;
6use vortex_array::dtype::PType;
7use vortex_array::scalar::Scalar;
8use vortex_array::vtable::OperationsVTable;
9use vortex_error::VortexExpect;
10use vortex_error::VortexResult;
11
12use crate::ALPRD;
13use crate::ALPRDArrayExt;
14
15impl OperationsVTable<ALPRD> for ALPRD {
16 fn scalar_at(
17 array: ArrayView<'_, ALPRD>,
18 index: usize,
19 ctx: &mut ExecutionCtx,
20 ) -> VortexResult<Scalar> {
21 let maybe_patched_value = match array.left_parts_patches() {
24 Some(patches) => patches.get_patched(index)?,
25 None => None,
26 };
27 let left = match maybe_patched_value {
28 Some(patched_value) => patched_value
29 .as_primitive()
30 .as_::<u16>()
31 .vortex_expect("patched values must be non-null"),
32 _ => {
33 let left_code: u16 = array
34 .left_parts()
35 .execute_scalar(index, ctx)?
36 .as_primitive()
37 .as_::<u16>()
38 .vortex_expect("left_code must be non-null");
39 array.left_parts_dictionary()[left_code as usize]
40 }
41 };
42
43 Ok(if array.dtype().as_ptype() == PType::F32 {
45 let right: u32 = array
46 .right_parts()
47 .execute_scalar(index, ctx)?
48 .as_primitive()
49 .as_::<u32>()
50 .vortex_expect("non-null");
51 let packed = f32::from_bits((left as u32) << array.right_bit_width() | right);
52 Scalar::primitive(packed, array.dtype().nullability())
53 } else {
54 let right: u64 = array
55 .right_parts()
56 .execute_scalar(index, ctx)?
57 .as_primitive()
58 .as_::<u64>()
59 .vortex_expect("non-null");
60 let packed = f64::from_bits(((left as u64) << array.right_bit_width()) | right);
61 Scalar::primitive(packed, array.dtype().nullability())
62 })
63 }
64}
65
66#[cfg(test)]
67mod test {
68 use std::sync::LazyLock;
69
70 use rstest::rstest;
71 use vortex_array::VortexSessionExecute;
72 use vortex_array::arrays::PrimitiveArray;
73 use vortex_array::assert_arrays_eq;
74 use vortex_array::scalar::Scalar;
75 use vortex_session::VortexSession;
76
77 use crate::ALPRDArrayExt;
78 use crate::ALPRDFloat;
79 use crate::RDEncoder;
80
81 static SESSION: LazyLock<VortexSession> = LazyLock::new(|| {
82 let session = vortex_array::array_session();
83 crate::initialize(&session);
84 session
85 });
86
87 #[rstest]
88 #[case(0.1f32, 0.2f32, 3e25f32)]
89 #[case(0.1f64, 0.2f64, 3e100f64)]
90 fn test_slice<T: ALPRDFloat>(#[case] a: T, #[case] b: T, #[case] outlier: T) {
91 let mut ctx = SESSION.create_execution_ctx();
92 let array = PrimitiveArray::from_iter([a, b, outlier]);
93 let encoded = RDEncoder::new(&[a, b]).encode(array.as_view());
94
95 assert!(encoded.left_parts_patches().is_some());
96 assert_arrays_eq!(encoded, array, &mut ctx);
97 }
98
99 #[rstest]
100 #[case(0.1f32, 0.2f32, 3e25f32)]
101 #[case(0.1f64, 0.2f64, 3e100f64)]
102 fn test_scalar_at<T: ALPRDFloat + Into<Scalar>>(
103 #[case] a: T,
104 #[case] b: T,
105 #[case] outlier: T,
106 ) {
107 let mut ctx = SESSION.create_execution_ctx();
108 let array = PrimitiveArray::from_iter([a, b, outlier]);
109 let encoded = RDEncoder::new(&[a, b]).encode(array.as_view());
110 assert!(encoded.left_parts_patches().is_some());
111 assert_arrays_eq!(encoded, array, &mut ctx);
112 }
113
114 #[test]
115 fn nullable_scalar_at() {
116 let mut ctx = SESSION.create_execution_ctx();
117 let a = 0.1f64;
118 let b = 0.2f64;
119 let outlier = 3e100f64;
120 let array = PrimitiveArray::from_option_iter([Some(a), Some(b), Some(outlier)]);
121 let encoded = RDEncoder::new(&[a, b]).encode(array.as_view());
122 assert!(encoded.left_parts_patches().is_some());
123 assert_arrays_eq!(
124 encoded,
125 PrimitiveArray::from_option_iter([Some(a), Some(b), Some(outlier)]),
126 &mut ctx
127 );
128 }
129}