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;
10use vortex_session::registry::CachedId;
11
12use crate::ArrayRef;
13use crate::ExecutionCtx;
14use crate::IntoArray;
15use crate::arrays::Bool;
16use crate::arrays::BoolArray;
17use crate::arrays::ConstantArray;
18use crate::arrays::ScalarFnArray;
19use crate::arrays::bool::BoolArrayExt;
20use crate::builtins::ArrayBuiltins;
21use crate::dtype::DType;
22use crate::scalar::Scalar;
23use crate::scalar_fn::Arity;
24use crate::scalar_fn::ChildName;
25use crate::scalar_fn::EmptyOptions;
26use crate::scalar_fn::ExecutionArgs;
27use crate::scalar_fn::ScalarFnId;
28use crate::scalar_fn::ScalarFnVTable;
29use crate::scalar_fn::ScalarFnVTableExt;
30
31#[derive(Clone)]
33pub struct Not;
34
35impl Not {
36 pub fn try_new(input: ArrayRef) -> VortexResult<ScalarFnArray> {
42 ScalarFnArray::try_new(Not.bind(EmptyOptions), vec![input])
43 }
44}
45
46impl ScalarFnVTable for Not {
47 type Options = EmptyOptions;
48
49 fn id(&self) -> ScalarFnId {
50 static ID: CachedId = CachedId::new("vortex.not");
51 *ID
52 }
53
54 fn serialize(&self, _options: &Self::Options) -> VortexResult<Option<Vec<u8>>> {
55 Ok(Some(vec![]))
56 }
57
58 fn deserialize(
59 &self,
60 _metadata: &[u8],
61 _session: &VortexSession,
62 ) -> VortexResult<Self::Options> {
63 Ok(EmptyOptions)
64 }
65
66 fn arity(&self, _options: &Self::Options) -> Arity {
67 Arity::Exact(1)
68 }
69
70 fn child_name(&self, _options: &Self::Options, child_idx: usize) -> ChildName {
71 match child_idx {
72 0 => ChildName::from("input"),
73 _ => unreachable!("Invalid child index {} for Not expression", child_idx),
74 }
75 }
76
77 fn return_dtype(&self, _options: &Self::Options, arg_dtypes: &[DType]) -> VortexResult<DType> {
78 let child_dtype = &arg_dtypes[0];
79 if !matches!(child_dtype, DType::Bool(_)) {
80 vortex_bail!(
81 "Not expression expects a boolean child, got: {}",
82 child_dtype
83 );
84 }
85 Ok(child_dtype.clone())
86 }
87
88 fn execute(
89 &self,
90 _data: &Self::Options,
91 args: &dyn ExecutionArgs,
92 ctx: &mut ExecutionCtx,
93 ) -> VortexResult<ArrayRef> {
94 let child = args.get(0)?;
95
96 if let Some(scalar) = child.as_constant() {
98 let value = match scalar.as_bool().value() {
99 Some(b) => Scalar::bool(!b, child.dtype().nullability()),
100 None => Scalar::null(child.dtype().clone()),
101 };
102 return Ok(ConstantArray::new(value, args.row_count()).into_array());
103 }
104
105 if let Some(bool) = child.as_opt::<Bool>() {
107 return Ok(BoolArray::new(!bool.to_bit_buffer(), bool.validity()?).into_array());
108 }
109
110 child.execute::<ArrayRef>(ctx)?.not()
112 }
113
114 fn is_strict(&self, _options: &Self::Options) -> bool {
115 true
116 }
117
118 fn is_infallible(&self, _options: &Self::Options) -> bool {
119 true
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use vortex_error::VortexResult;
126
127 use crate::IntoArray;
128 use crate::VortexSessionExecute;
129 use crate::array_session;
130 use crate::arrays::bool::BoolArrayExt;
131 use crate::assert_arrays_eq;
132 use crate::dtype::DType;
133 use crate::dtype::Nullability;
134 use crate::expr::col;
135 use crate::expr::get_item;
136 use crate::expr::not;
137 use crate::expr::root;
138 use crate::expr::test_harness;
139 use crate::scalar_fn::fns::not::BoolArray;
140
141 #[test]
142 fn is_strict() {
143 assert!(
144 not(root())
145 .as_scalar()
146 .is_some_and(|f| f.signature().is_strict())
147 );
148 }
149
150 #[test]
151 fn preserves_nulls() -> VortexResult<()> {
152 let mut ctx = array_session().create_execution_ctx();
153 let input = BoolArray::from_iter([Some(false), None, Some(true)]).into_array();
154
155 let result = input.apply(¬(root()))?;
156
157 assert_arrays_eq!(
158 result,
159 BoolArray::from_iter([Some(true), None, Some(false)]),
160 &mut ctx
161 );
162 Ok(())
163 }
164
165 #[test]
166 fn invert_booleans() {
167 let mut ctx = array_session().create_execution_ctx();
168 let not_expr = not(root());
169 let bools = BoolArray::from_iter([false, true, false, false, true, true]);
170 let result = bools
171 .into_array()
172 .apply(¬_expr)
173 .unwrap()
174 .execute::<BoolArray>(&mut ctx)
175 .unwrap();
176 assert_eq!(
177 result.to_bit_buffer().iter().collect::<Vec<_>>(),
178 vec![true, false, true, true, false, false]
179 );
180 }
181
182 #[test]
183 fn test_display_order_of_operations() {
184 let a = not(get_item("a", root()));
185 let b = get_item("a", not(root()));
186 assert_ne!(a.to_string(), b.to_string());
187 assert_eq!(a.to_string(), "vortex.not($.a)");
188 assert_eq!(b.to_string(), "vortex.not($).a");
189 }
190
191 #[test]
192 fn dtype() {
193 let not_expr = not(root());
194 let dtype = DType::Bool(Nullability::NonNullable);
195 assert_eq!(
196 not_expr.return_dtype(&dtype).unwrap(),
197 DType::Bool(Nullability::NonNullable)
198 );
199
200 let dtype = test_harness::struct_dtype();
201 assert_eq!(
202 not(col("bool1")).return_dtype(&dtype).unwrap(),
203 DType::Bool(Nullability::NonNullable)
204 );
205 }
206}