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

vortex-data / vortex / 16139349253

08 Jul 2025 09:26AM UTC coverage: 78.057% (-0.2%) from 78.253%
16139349253

push

github

web-flow
VortexExpr VTables (#3713)

Adds the same vtable machinery as arrays and layouts already use. It
uses the "Encoding" naming scheme from arrays and layouts. I don't
particularly like it, but it's consistent. Open to renames later.

Further, adds an expression registry to the Vortex session that will be
used for deserialization.

Expressions only decide their "options" serialization. So in theory, can
support many container formats, not just proto, provided each expression
can deserialize their own options format.

---------

Signed-off-by: Nicholas Gates <nick@nickgates.com>

800 of 1190 new or added lines in 38 files covered. (67.23%)

40 existing lines in 13 files now uncovered.

44100 of 56497 relevant lines covered (78.06%)

54989.55 hits per line

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

55.91
/vortex-expr/src/exprs/not.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use std::fmt::Display;
5
use std::hash::Hash;
6

7
use vortex_array::compute::invert;
8
use vortex_array::{ArrayRef, DeserializeMetadata, EmptyMetadata};
9
use vortex_dtype::DType;
10
use vortex_error::{VortexResult, vortex_bail};
11

12
use crate::{
13
    AnalysisExpr, ExprEncodingRef, ExprId, ExprRef, IntoExpr, Scope, ScopeDType, VTable, vtable,
14
};
15

16
vtable!(Not);
17

18
#[allow(clippy::derived_hash_with_manual_eq)]
19
#[derive(Clone, Debug, Hash)]
20
pub struct NotExpr {
21
    child: ExprRef,
22
}
23

24
impl PartialEq for NotExpr {
NEW
25
    fn eq(&self, other: &Self) -> bool {
×
NEW
26
        self.child.eq(&other.child)
×
UNCOV
27
    }
×
28
}
29

30
pub struct NotExprEncoding;
31

32
impl VTable for NotVTable {
33
    type Expr = NotExpr;
34
    type Encoding = NotExprEncoding;
35
    type Metadata = EmptyMetadata;
36

37
    fn id(_encoding: &Self::Encoding) -> ExprId {
106✔
38
        ExprId::new_ref("not")
106✔
39
    }
106✔
40

NEW
41
    fn encoding(_expr: &Self::Expr) -> ExprEncodingRef {
×
NEW
42
        ExprEncodingRef::new_ref(NotExprEncoding.as_ref())
×
NEW
43
    }
×
44

NEW
45
    fn metadata(_expr: &Self::Expr) -> Option<Self::Metadata> {
×
NEW
46
        Some(EmptyMetadata)
×
UNCOV
47
    }
×
48

NEW
49
    fn children(expr: &Self::Expr) -> Vec<&ExprRef> {
×
NEW
50
        vec![&expr.child]
×
UNCOV
51
    }
×
52

NEW
53
    fn with_children(_expr: &Self::Expr, children: Vec<ExprRef>) -> VortexResult<Self::Expr> {
×
NEW
54
        if children.len() != 1 {
×
NEW
55
            vortex_bail!(
×
NEW
56
                "Not expression expects exactly one child, got {}",
×
NEW
57
                children.len()
×
NEW
58
            );
×
UNCOV
59
        }
×
NEW
60
        Ok(NotExpr::new(children[0].clone()))
×
NEW
61
    }
×
62

NEW
63
    fn build(
×
NEW
64
        _encoding: &Self::Encoding,
×
NEW
65
        _metadata: &<Self::Metadata as DeserializeMetadata>::Output,
×
NEW
66
        children: Vec<ExprRef>,
×
NEW
67
    ) -> VortexResult<Self::Expr> {
×
NEW
68
        if children.len() != 1 {
×
NEW
69
            vortex_bail!(
×
NEW
70
                "Not expression expects exactly one child, got {}",
×
NEW
71
                children.len()
×
NEW
72
            );
×
UNCOV
73
        }
×
NEW
74
        Ok(NotExpr::new(children[0].clone()))
×
UNCOV
75
    }
×
76

77
    fn evaluate(expr: &Self::Expr, scope: &Scope) -> VortexResult<ArrayRef> {
23✔
78
        let child_result = expr.child.unchecked_evaluate(scope)?;
23✔
79
        invert(&child_result)
23✔
80
    }
23✔
81

82
    fn return_dtype(expr: &Self::Expr, scope: &ScopeDType) -> VortexResult<DType> {
25✔
83
        let child = expr.child.return_dtype(scope)?;
25✔
84
        if !matches!(child, DType::Bool(_)) {
25✔
NEW
85
            vortex_bail!("Not expression expects a boolean child, got: {}", child);
×
86
        }
25✔
87
        Ok(child)
25✔
88
    }
25✔
89
}
90

91
impl NotExpr {
92
    pub fn new(child: ExprRef) -> Self {
26✔
93
        Self { child }
26✔
94
    }
26✔
95

NEW
96
    pub fn new_expr(child: ExprRef) -> ExprRef {
×
NEW
97
        Self::new(child).into_expr()
×
UNCOV
98
    }
×
99

NEW
100
    pub fn child(&self) -> &ExprRef {
×
NEW
101
        &self.child
×
UNCOV
102
    }
×
103
}
104

105
impl Display for NotExpr {
106
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1✔
107
        write!(f, "!{}", self.child)
1✔
108
    }
1✔
109
}
110

111
impl AnalysisExpr for NotExpr {}
112

113
pub fn not(operand: ExprRef) -> ExprRef {
26✔
114
    NotExpr::new(operand).into_expr()
26✔
115
}
26✔
116

117
#[cfg(test)]
118
mod tests {
119
    use vortex_array::ToCanonical;
120
    use vortex_array::arrays::BoolArray;
121
    use vortex_dtype::{DType, Nullability};
122

123
    use crate::{Scope, ScopeDType, col, not, root, test_harness};
124

125
    #[test]
126
    fn invert_booleans() {
1✔
127
        let not_expr = not(root());
1✔
128
        let bools = BoolArray::from_iter([false, true, false, false, true, true]);
1✔
129
        assert_eq!(
1✔
130
            not_expr
1✔
131
                .evaluate(&Scope::new(bools.to_array()))
1✔
132
                .unwrap()
1✔
133
                .to_bool()
1✔
134
                .unwrap()
1✔
135
                .boolean_buffer()
1✔
136
                .iter()
1✔
137
                .collect::<Vec<_>>(),
1✔
138
            vec![true, false, true, true, false, false]
1✔
139
        );
1✔
140
    }
1✔
141

142
    #[test]
143
    fn dtype() {
1✔
144
        let not_expr = not(root());
1✔
145
        let dtype = DType::Bool(Nullability::NonNullable);
1✔
146
        assert_eq!(
1✔
147
            not_expr.return_dtype(&ScopeDType::new(dtype)).unwrap(),
1✔
148
            DType::Bool(Nullability::NonNullable)
1✔
149
        );
1✔
150

151
        let dtype = test_harness::struct_dtype();
1✔
152
        assert_eq!(
1✔
153
            not(col("bool1"))
1✔
154
                .return_dtype(&ScopeDType::new(dtype))
1✔
155
                .unwrap(),
1✔
156
            DType::Bool(Nullability::NonNullable)
1✔
157
        );
1✔
158
    }
1✔
159
}
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