vortex_expr/
not.rs

1use std::any::Any;
2use std::fmt::Display;
3use std::hash::Hash;
4use std::sync::Arc;
5
6use vortex_array::compute::invert;
7use vortex_array::{Array, ArrayRef};
8use vortex_dtype::DType;
9use vortex_error::VortexResult;
10
11use crate::{ExprRef, VortexExpr};
12
13#[derive(Debug, Eq, Hash)]
14// We cannot auto derive PartialEq because ExprRef, since its a Arc<..> and derive doesn't work
15#[allow(clippy::derived_hash_with_manual_eq)]
16pub struct Not {
17    child: ExprRef,
18}
19
20impl Not {
21    pub fn new_expr(child: ExprRef) -> ExprRef {
22        Arc::new(Self { child })
23    }
24
25    pub fn child(&self) -> &ExprRef {
26        &self.child
27    }
28}
29
30impl Display for Not {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        write!(f, "!")?;
33        self.child.fmt(f)
34    }
35}
36
37#[cfg(feature = "proto")]
38pub(crate) mod proto {
39    use expr::kind;
40    use vortex_error::VortexResult;
41    use vortex_proto::expr;
42    use vortex_proto::expr::kind::Kind;
43
44    use crate::{ExprDeserialize, ExprRef, ExprSerializable, Id, Not};
45
46    pub struct NotSerde;
47
48    impl Id for NotSerde {
49        fn id(&self) -> &'static str {
50            "not"
51        }
52    }
53
54    impl ExprDeserialize for NotSerde {
55        fn deserialize(&self, _expr: &Kind, mut children: Vec<ExprRef>) -> VortexResult<ExprRef> {
56            Ok(Not::new_expr(children.remove(0)))
57        }
58    }
59
60    impl ExprSerializable for Not {
61        fn id(&self) -> &'static str {
62            NotSerde.id()
63        }
64
65        fn serialize_kind(&self) -> VortexResult<Kind> {
66            Ok(Kind::Not(kind::Not {}))
67        }
68    }
69}
70
71impl VortexExpr for Not {
72    fn as_any(&self) -> &dyn Any {
73        self
74    }
75
76    fn unchecked_evaluate(&self, batch: &dyn Array) -> VortexResult<ArrayRef> {
77        let child_result = self.child.evaluate(batch)?;
78        invert(&child_result)
79    }
80
81    fn children(&self) -> Vec<&ExprRef> {
82        vec![&self.child]
83    }
84
85    fn replacing_children(self: Arc<Self>, mut children: Vec<ExprRef>) -> ExprRef {
86        assert_eq!(children.len(), 0);
87        Self::new_expr(children.remove(0))
88    }
89
90    fn return_dtype(&self, scope_dtype: &DType) -> VortexResult<DType> {
91        self.child.return_dtype(scope_dtype)
92    }
93}
94
95impl PartialEq for Not {
96    fn eq(&self, other: &Not) -> bool {
97        other.child.eq(&self.child)
98    }
99}
100
101pub fn not(operand: ExprRef) -> ExprRef {
102    Not::new_expr(operand)
103}
104
105#[cfg(test)]
106mod tests {
107    use vortex_array::ToCanonical;
108    use vortex_array::arrays::BoolArray;
109    use vortex_dtype::{DType, Nullability};
110
111    use crate::{col, ident, not, test_harness};
112
113    #[test]
114    fn invert_booleans() {
115        let not_expr = not(ident());
116        let bools = BoolArray::from_iter([false, true, false, false, true, true]);
117        assert_eq!(
118            not_expr
119                .evaluate(&bools)
120                .unwrap()
121                .to_bool()
122                .unwrap()
123                .boolean_buffer()
124                .iter()
125                .collect::<Vec<_>>(),
126            vec![true, false, true, true, false, false]
127        );
128    }
129
130    #[test]
131    fn dtype() {
132        let not_expr = not(ident());
133        assert_eq!(
134            not_expr
135                .return_dtype(&DType::Bool(Nullability::NonNullable))
136                .unwrap(),
137            DType::Bool(Nullability::NonNullable)
138        );
139
140        let dtype = test_harness::struct_dtype();
141        assert_eq!(
142            not(col("bool1")).return_dtype(&dtype).unwrap(),
143            DType::Bool(Nullability::NonNullable)
144        );
145    }
146}