vortex_expr/exprs/
not.rs

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