• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 17073077835

19 Aug 2025 02:40PM UTC coverage: 24.083%. First build
17073077835

Pull #4177

github

web-flow
Merge b42e5758f into 431a8f2b5
Pull Request #4177: feat: ArrayOperations infallible, eager validation + new_unchecked

197 of 1455 new or added lines in 154 files covered. (13.54%)

8646 of 35901 relevant lines covered (24.08%)

142.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.4
/vortex-array/src/compute/nan_count.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use std::sync::LazyLock;
5

6
use arcref::ArcRef;
7
use vortex_dtype::DType;
8
use vortex_error::{VortexExpect, VortexResult, vortex_bail, vortex_err};
9
use vortex_scalar::{Scalar, ScalarValue};
10

11
use crate::Array;
12
use crate::compute::{ComputeFn, ComputeFnVTable, InvocationArgs, Kernel, Output, UnaryArgs};
13
use crate::stats::{Precision, Stat, StatsProviderExt};
14
use crate::vtable::VTable;
15

16
static NAN_COUNT_FN: LazyLock<ComputeFn> = LazyLock::new(|| {
2✔
17
    let compute = ComputeFn::new("nan_count".into(), ArcRef::new_ref(&NaNCount));
2✔
18
    for kernel in inventory::iter::<NaNCountKernelRef> {
6✔
19
        compute.register_kernel(kernel.0.clone());
4✔
20
    }
4✔
21
    compute
2✔
22
});
2✔
23

24
/// Computes the number of NaN values in the array.
25
pub fn nan_count(array: &dyn Array) -> VortexResult<usize> {
8✔
26
    Ok(NAN_COUNT_FN
8✔
27
        .invoke(&InvocationArgs {
8✔
28
            inputs: &[array.into()],
8✔
29
            options: &(),
8✔
30
        })?
8✔
31
        .unwrap_scalar()?
8✔
32
        .as_primitive()
8✔
33
        .as_::<usize>()
8✔
34
        .vortex_expect("NaN count should not return null"))
8✔
35
}
8✔
36

37
struct NaNCount;
38

39
impl ComputeFnVTable for NaNCount {
40
    fn invoke(
8✔
41
        &self,
8✔
42
        args: &InvocationArgs,
8✔
43
        kernels: &[ArcRef<dyn Kernel>],
8✔
44
    ) -> VortexResult<Output> {
8✔
45
        let UnaryArgs { array, .. } = UnaryArgs::<()>::try_from(args)?;
8✔
46

47
        let nan_count = nan_count_impl(array, kernels)?;
8✔
48

49
        // Update the stats set with the computed NaN count
50
        array.statistics().set(
8✔
51
            Stat::NaNCount,
8✔
52
            Precision::Exact(ScalarValue::from(nan_count as u64)),
8✔
53
        );
54

55
        Ok(Scalar::from(nan_count as u64).into())
8✔
56
    }
8✔
57

58
    fn return_dtype(&self, args: &InvocationArgs) -> VortexResult<DType> {
8✔
59
        let UnaryArgs { array, .. } = UnaryArgs::<()>::try_from(args)?;
8✔
60
        Stat::NaNCount
8✔
61
            .dtype(array.dtype())
8✔
62
            .ok_or_else(|| vortex_err!("Cannot compute NaN count for dtype {}", array.dtype()))
8✔
63
    }
8✔
64

65
    fn return_len(&self, _args: &InvocationArgs) -> VortexResult<usize> {
8✔
66
        Ok(1)
8✔
67
    }
8✔
68

69
    fn is_elementwise(&self) -> bool {
8✔
70
        false
8✔
71
    }
8✔
72
}
73

74
/// Computes the min and max of an array, returning the (min, max) values
75
pub trait NaNCountKernel: VTable {
76
    fn nan_count(&self, array: &Self::Array) -> VortexResult<usize>;
77
}
78

79
pub struct NaNCountKernelRef(ArcRef<dyn Kernel>);
80
inventory::collect!(NaNCountKernelRef);
81

82
#[derive(Debug)]
83
pub struct NaNCountKernelAdapter<V: VTable>(pub V);
84

85
impl<V: VTable + NaNCountKernel> NaNCountKernelAdapter<V> {
86
    pub const fn lift(&'static self) -> NaNCountKernelRef {
×
87
        NaNCountKernelRef(ArcRef::new_ref(self))
×
88
    }
×
89
}
90

91
impl<V: VTable + NaNCountKernel> Kernel for NaNCountKernelAdapter<V> {
92
    fn invoke(&self, args: &InvocationArgs) -> VortexResult<Option<Output>> {
8✔
93
        let UnaryArgs { array, .. } = UnaryArgs::<()>::try_from(args)?;
8✔
94
        let Some(array) = array.as_opt::<V>() else {
8✔
95
            return Ok(None);
×
96
        };
97
        let nan_count = V::nan_count(&self.0, array)?;
8✔
98
        Ok(Some(Scalar::from(nan_count as u64).into()))
8✔
99
    }
8✔
100
}
101

102
fn nan_count_impl(array: &dyn Array, kernels: &[ArcRef<dyn Kernel>]) -> VortexResult<usize> {
8✔
103
    if array.is_empty() || array.valid_count()? == 0 {
8✔
104
        return Ok(0);
×
105
    }
8✔
106

107
    if let Some(nan_count) = array
8✔
108
        .statistics()
8✔
109
        .get_as::<usize>(Stat::NaNCount)
8✔
110
        .and_then(Precision::as_exact)
8✔
111
    {
112
        // If the NaN count is already computed, return it
113
        return Ok(nan_count);
×
114
    }
8✔
115

116
    let args = InvocationArgs {
8✔
117
        inputs: &[array.into()],
8✔
118
        options: &(),
8✔
119
    };
8✔
120

121
    for kernel in kernels {
8✔
122
        if let Some(output) = kernel.invoke(&args)? {
8✔
123
            return output
8✔
124
                .unwrap_scalar()?
8✔
125
                .as_primitive()
8✔
126
                .as_::<usize>()
8✔
127
                .ok_or_else(|| vortex_err!("NaN count should not return null"));
8✔
128
        }
×
129
    }
130
    if let Some(output) = array.invoke(&NAN_COUNT_FN, &args)? {
×
131
        return output
×
132
            .unwrap_scalar()?
×
133
            .as_primitive()
×
NEW
134
            .as_::<usize>()
×
135
            .ok_or_else(|| vortex_err!("NaN count should not return null"));
×
136
    }
×
137

138
    if !array.is_canonical() {
×
139
        let canonical = array.to_canonical()?;
×
140
        return nan_count(canonical.as_ref());
×
141
    }
×
142

143
    vortex_bail!(
×
144
        "No NaN count kernel found for array type: {}",
×
145
        array.dtype()
×
146
    )
147
}
8✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc