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), [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::assert_arrays_eq;
131 use crate::dtype::DType;
132 use crate::dtype::Nullability;
133 use crate::expr::col;
134 use crate::expr::get_item;
135 use crate::expr::not;
136 use crate::expr::root;
137 use crate::expr::test_harness;
138 use crate::scalar_fn::fns::not::BoolArray;
139
140 #[test]
141 fn is_strict() {
142 assert!(
143 not(root())
144 .as_scalar()
145 .is_some_and(|f| f.signature().is_strict())
146 );
147 }
148
149 #[test]
150 fn preserves_nulls() -> VortexResult<()> {
151 let mut ctx = array_session().create_execution_ctx();
152 let input = BoolArray::from_iter([Some(false), None, Some(true)]).into_array();
153
154 let result = input.apply(¬(root()))?;
155
156 assert_arrays_eq!(
157 result,
158 BoolArray::from_iter([Some(true), None, Some(false)]),
159 &mut ctx
160 );
161 Ok(())
162 }
163
164 #[test]
165 fn invert_booleans() {
166 let mut ctx = array_session().create_execution_ctx();
167 let not_expr = not(root());
168 let bools = BoolArray::from_iter([false, true, false, false, true, true]);
169 let result = bools.into_array().apply(¬_expr).unwrap();
170 assert_arrays_eq!(
171 result,
172 BoolArray::from_iter([true, false, true, true, false, false]),
173 &mut ctx
174 );
175 }
176
177 #[test]
178 fn test_display_order_of_operations() {
179 let a = not(get_item("a", root()));
180 let b = get_item("a", not(root()));
181 assert_ne!(a.to_string(), b.to_string());
182 assert_eq!(a.to_string(), "vortex.not($.a)");
183 assert_eq!(b.to_string(), "vortex.not($).a");
184 }
185
186 #[test]
187 fn dtype() {
188 let not_expr = not(root());
189 let dtype = DType::Bool(Nullability::NonNullable);
190 assert_eq!(
191 not_expr.return_dtype(&dtype).unwrap(),
192 DType::Bool(Nullability::NonNullable)
193 );
194
195 let dtype = test_harness::struct_dtype();
196 assert_eq!(
197 not(col("bool1")).return_dtype(&dtype).unwrap(),
198 DType::Bool(Nullability::NonNullable)
199 );
200 }
201}