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