Skip to main content

vortex_array/arrays/primitive/compute/
fill_null.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::ops::Not;
5
6use vortex_error::VortexExpect;
7use vortex_error::VortexResult;
8
9use crate::ArrayRef;
10use crate::ExecutionCtx;
11use crate::IntoArray;
12use crate::array::ArrayView;
13use crate::arrays::BoolArray;
14use crate::arrays::Primitive;
15use crate::arrays::PrimitiveArray;
16use crate::match_each_native_ptype;
17use crate::scalar::Scalar;
18use crate::scalar_fn::fns::fill_null::FillNullKernel;
19use crate::validity::Validity;
20
21impl FillNullKernel for Primitive {
22    fn fill_null(
23        array: ArrayView<'_, Primitive>,
24        fill_value: &Scalar,
25        ctx: &mut ExecutionCtx,
26    ) -> VortexResult<Option<ArrayRef>> {
27        let result_validity = Validity::from(fill_value.dtype().nullability());
28
29        Ok(Some(match array.validity()? {
30            Validity::Array(is_valid) => {
31                let is_invalid = is_valid.execute::<BoolArray>(ctx)?.into_bit_buffer().not();
32                match_each_native_ptype!(array.ptype(), |T| {
33                    let mut buffer = array.to_buffer::<T>().into_mut();
34                    let fill_value = fill_value
35                        .as_primitive()
36                        .typed_value::<T>()
37                        .vortex_expect("top-level fill_null ensure non-null fill value");
38                    for invalid_index in is_invalid.set_indices() {
39                        buffer[invalid_index] = fill_value;
40                    }
41                    PrimitiveArray::new(buffer.freeze(), result_validity).into_array()
42                })
43            }
44            _ => unreachable!("checked in entry point"),
45        }))
46    }
47}
48
49#[cfg(test)]
50mod test {
51    use vortex_buffer::buffer;
52
53    use crate::IntoArray;
54    use crate::VortexSessionExecute;
55    use crate::array_session;
56    use crate::arrays::PrimitiveArray;
57    use crate::arrays::primitive::compute::fill_null::BoolArray;
58    use crate::assert_arrays_eq;
59    use crate::builtins::ArrayBuiltins;
60    #[expect(deprecated)]
61    use crate::canonical::ToCanonical as _;
62    use crate::scalar::Scalar;
63    use crate::validity::Validity;
64
65    #[test]
66    fn fill_null_leading_none() {
67        let mut ctx = array_session().create_execution_ctx();
68        let arr = PrimitiveArray::from_option_iter([None, Some(8u8), None, Some(10), None]);
69        #[expect(deprecated)]
70        let p = arr
71            .into_array()
72            .fill_null(Scalar::from(42u8))
73            .unwrap()
74            .to_primitive();
75        assert_arrays_eq!(
76            p,
77            PrimitiveArray::from_iter([42u8, 8, 42, 10, 42]),
78            &mut ctx
79        );
80        assert!(
81            p.as_ref()
82                .validity()
83                .unwrap()
84                .execute_mask(
85                    p.as_ref().len(),
86                    &mut array_session().create_execution_ctx()
87                )
88                .unwrap()
89                .all_true()
90        );
91    }
92
93    #[test]
94    fn fill_null_all_none() {
95        let mut ctx = array_session().create_execution_ctx();
96        let arr = PrimitiveArray::from_option_iter([Option::<u8>::None, None, None, None, None]);
97
98        #[expect(deprecated)]
99        let p = arr
100            .into_array()
101            .fill_null(Scalar::from(255u8))
102            .unwrap()
103            .to_primitive();
104        assert_arrays_eq!(
105            p,
106            PrimitiveArray::from_iter([255u8, 255, 255, 255, 255]),
107            &mut ctx
108        );
109        assert!(
110            p.as_ref()
111                .validity()
112                .unwrap()
113                .execute_mask(
114                    p.as_ref().len(),
115                    &mut array_session().create_execution_ctx()
116                )
117                .unwrap()
118                .all_true()
119        );
120    }
121
122    #[test]
123    fn fill_null_nullable_non_null() {
124        let mut ctx = array_session().create_execution_ctx();
125        let arr = PrimitiveArray::new(
126            buffer![8u8, 10, 12, 14, 16],
127            Validity::Array(BoolArray::from_iter([true, true, true, true, true]).into_array()),
128        );
129        #[expect(deprecated)]
130        let p = arr
131            .into_array()
132            .fill_null(Scalar::from(255u8))
133            .unwrap()
134            .to_primitive();
135        assert_arrays_eq!(
136            p,
137            PrimitiveArray::from_iter([8u8, 10, 12, 14, 16]),
138            &mut ctx
139        );
140        assert!(
141            p.as_ref()
142                .validity()
143                .unwrap()
144                .execute_mask(
145                    p.as_ref().len(),
146                    &mut array_session().create_execution_ctx()
147                )
148                .unwrap()
149                .all_true()
150        );
151    }
152
153    #[test]
154    fn fill_null_non_nullable() {
155        let mut ctx = array_session().create_execution_ctx();
156        let arr = buffer![8u8, 10, 12, 14, 16].into_array();
157        #[expect(deprecated)]
158        let p = arr.fill_null(Scalar::from(255u8)).unwrap().to_primitive();
159        assert_arrays_eq!(
160            p,
161            PrimitiveArray::from_iter([8u8, 10, 12, 14, 16]),
162            &mut ctx
163        );
164        assert!(
165            p.as_ref()
166                .validity()
167                .unwrap()
168                .execute_mask(
169                    p.as_ref().len(),
170                    &mut array_session().create_execution_ctx()
171                )
172                .unwrap()
173                .all_true()
174        );
175    }
176}