vortex_array/scalar_fn/fns/not/
mod.rs1mod kernel;
5
6pub use kernel::*;
7use vortex_error::VortexResult;
8use vortex_error::vortex_bail;
9use vortex_session::VortexSession;
10
11use crate::ArrayRef;
12use crate::ExecutionCtx;
13use crate::IntoArray;
14use crate::arrays::Bool;
15use crate::arrays::BoolArray;
16use crate::arrays::ConstantArray;
17use crate::arrays::bool::BoolArrayExt;
18use crate::builtins::ArrayBuiltins;
19use crate::dtype::DType;
20use crate::scalar::Scalar;
21use crate::scalar_fn::Arity;
22use crate::scalar_fn::ChildName;
23use crate::scalar_fn::EmptyOptions;
24use crate::scalar_fn::ExecutionArgs;
25use crate::scalar_fn::ScalarFnId;
26use crate::scalar_fn::ScalarFnVTable;
27
28#[derive(Clone)]
30pub struct Not;
31
32impl ScalarFnVTable for Not {
33 type Options = EmptyOptions;
34
35 fn id(&self) -> ScalarFnId {
36 ScalarFnId::new("vortex.not")
37 }
38
39 fn serialize(&self, _options: &Self::Options) -> VortexResult<Option<Vec<u8>>> {
40 Ok(Some(vec![]))
41 }
42
43 fn deserialize(
44 &self,
45 _metadata: &[u8],
46 _session: &VortexSession,
47 ) -> VortexResult<Self::Options> {
48 Ok(EmptyOptions)
49 }
50
51 fn arity(&self, _options: &Self::Options) -> Arity {
52 Arity::Exact(1)
53 }
54
55 fn child_name(&self, _options: &Self::Options, child_idx: usize) -> ChildName {
56 match child_idx {
57 0 => ChildName::from("input"),
58 _ => unreachable!("Invalid child index {} for Not expression", child_idx),
59 }
60 }
61
62 fn return_dtype(&self, _options: &Self::Options, arg_dtypes: &[DType]) -> VortexResult<DType> {
63 let child_dtype = &arg_dtypes[0];
64 if !matches!(child_dtype, DType::Bool(_)) {
65 vortex_bail!(
66 "Not expression expects a boolean child, got: {}",
67 child_dtype
68 );
69 }
70 Ok(child_dtype.clone())
71 }
72
73 fn execute(
74 &self,
75 _data: &Self::Options,
76 args: &dyn ExecutionArgs,
77 ctx: &mut ExecutionCtx,
78 ) -> VortexResult<ArrayRef> {
79 let child = args.get(0)?;
80
81 if let Some(scalar) = child.as_constant() {
83 let value = match scalar.as_bool().value() {
84 Some(b) => Scalar::bool(!b, child.dtype().nullability()),
85 None => Scalar::null(child.dtype().clone()),
86 };
87 return Ok(ConstantArray::new(value, args.row_count()).into_array());
88 }
89
90 if let Some(bool) = child.as_opt::<Bool>() {
92 return Ok(BoolArray::new(!bool.to_bit_buffer(), bool.validity()?).into_array());
93 }
94
95 child.execute::<ArrayRef>(ctx)?.not()
97 }
98
99 fn is_null_sensitive(&self, _options: &Self::Options) -> bool {
100 false
101 }
102
103 fn is_fallible(&self, _options: &Self::Options) -> bool {
104 false
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use crate::IntoArray;
111 #[expect(deprecated)]
112 use crate::ToCanonical as _;
113 use crate::arrays::bool::BoolArrayExt;
114 use crate::dtype::DType;
115 use crate::dtype::Nullability;
116 use crate::expr::col;
117 use crate::expr::get_item;
118 use crate::expr::not;
119 use crate::expr::root;
120 use crate::expr::test_harness;
121 use crate::scalar_fn::fns::not::BoolArray;
122
123 #[test]
124 fn invert_booleans() {
125 let not_expr = not(root());
126 let bools = BoolArray::from_iter([false, true, false, false, true, true]);
127 #[expect(deprecated)]
128 let result = bools.into_array().apply(¬_expr).unwrap().to_bool();
129 assert_eq!(
130 result.to_bit_buffer().iter().collect::<Vec<_>>(),
131 vec![true, false, true, true, false, false]
132 );
133 }
134
135 #[test]
136 fn test_display_order_of_operations() {
137 let a = not(get_item("a", root()));
138 let b = get_item("a", not(root()));
139 assert_ne!(a.to_string(), b.to_string());
140 assert_eq!(a.to_string(), "vortex.not($.a)");
141 assert_eq!(b.to_string(), "vortex.not($).a");
142 }
143
144 #[test]
145 fn dtype() {
146 let not_expr = not(root());
147 let dtype = DType::Bool(Nullability::NonNullable);
148 assert_eq!(
149 not_expr.return_dtype(&dtype).unwrap(),
150 DType::Bool(Nullability::NonNullable)
151 );
152
153 let dtype = test_harness::struct_dtype();
154 assert_eq!(
155 not(col("bool1")).return_dtype(&dtype).unwrap(),
156 DType::Bool(Nullability::NonNullable)
157 );
158 }
159}