1use core::fmt;
5use std::fmt::Display;
6use std::fmt::Formatter;
7
8use vortex_error::VortexError;
9use vortex_error::VortexResult;
10use vortex_error::vortex_bail;
11use vortex_proto::expr::binary_opts::BinaryOp;
12
13use crate::compute;
14
15#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub enum Operator {
23 Eq,
25 NotEq,
27 Gt,
29 Gte,
31 Lt,
33 Lte,
35 And,
37 Or,
40 Add,
45 Sub,
51 Mul,
53 Div,
55}
56
57impl From<Operator> for i32 {
58 fn from(value: Operator) -> Self {
59 let op: BinaryOp = value.into();
60 op.into()
61 }
62}
63
64impl From<Operator> for BinaryOp {
65 fn from(value: Operator) -> Self {
66 match value {
67 Operator::Eq => BinaryOp::Eq,
68 Operator::NotEq => BinaryOp::NotEq,
69 Operator::Gt => BinaryOp::Gt,
70 Operator::Gte => BinaryOp::Gte,
71 Operator::Lt => BinaryOp::Lt,
72 Operator::Lte => BinaryOp::Lte,
73 Operator::And => BinaryOp::And,
74 Operator::Or => BinaryOp::Or,
75 Operator::Add => BinaryOp::Add,
76 Operator::Sub => BinaryOp::Sub,
77 Operator::Mul => BinaryOp::Mul,
78 Operator::Div => BinaryOp::Div,
79 }
80 }
81}
82
83impl TryFrom<i32> for Operator {
84 type Error = VortexError;
85
86 fn try_from(value: i32) -> Result<Self, Self::Error> {
87 Ok(BinaryOp::try_from(value)?.into())
88 }
89}
90
91impl From<BinaryOp> for Operator {
92 fn from(value: BinaryOp) -> Self {
93 match value {
94 BinaryOp::Eq => Operator::Eq,
95 BinaryOp::NotEq => Operator::NotEq,
96 BinaryOp::Gt => Operator::Gt,
97 BinaryOp::Gte => Operator::Gte,
98 BinaryOp::Lt => Operator::Lt,
99 BinaryOp::Lte => Operator::Lte,
100 BinaryOp::And => Operator::And,
101 BinaryOp::Or => Operator::Or,
102 BinaryOp::Add => Operator::Add,
103 BinaryOp::Sub => Operator::Sub,
104 BinaryOp::Mul => Operator::Mul,
105 BinaryOp::Div => Operator::Div,
106 }
107 }
108}
109
110impl Display for Operator {
111 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
112 let display = match &self {
113 Operator::Eq => "=",
114 Operator::NotEq => "!=",
115 Operator::Gt => ">",
116 Operator::Gte => ">=",
117 Operator::Lt => "<",
118 Operator::Lte => "<=",
119 Operator::And => "and",
120 Operator::Or => "or",
121 Operator::Add => "+",
122 Operator::Sub => "-",
123 Operator::Mul => "*",
124 Operator::Div => "/",
125 };
126 Display::fmt(display, f)
127 }
128}
129
130impl Operator {
131 pub fn inverse(self) -> Option<Self> {
132 match self {
133 Operator::Eq => Some(Operator::NotEq),
134 Operator::NotEq => Some(Operator::Eq),
135 Operator::Gt => Some(Operator::Lte),
136 Operator::Gte => Some(Operator::Lt),
137 Operator::Lt => Some(Operator::Gte),
138 Operator::Lte => Some(Operator::Gt),
139 Operator::And
140 | Operator::Or
141 | Operator::Add
142 | Operator::Sub
143 | Operator::Mul
144 | Operator::Div => None,
145 }
146 }
147
148 pub fn logical_inverse(self) -> Option<Self> {
149 match self {
150 Operator::And => Some(Operator::Or),
151 Operator::Or => Some(Operator::And),
152 _ => None,
153 }
154 }
155
156 pub fn swap(self) -> Option<Self> {
158 match self {
159 Operator::Eq => Some(Operator::Eq),
160 Operator::NotEq => Some(Operator::NotEq),
161 Operator::Gt => Some(Operator::Lt),
162 Operator::Gte => Some(Operator::Lte),
163 Operator::Lt => Some(Operator::Gt),
164 Operator::Lte => Some(Operator::Gte),
165 Operator::And => Some(Operator::And),
166 Operator::Or => Some(Operator::Or),
167 Operator::Add => Some(Operator::Add),
168 Operator::Mul => Some(Operator::Mul),
169 Operator::Sub | Operator::Div => None,
170 }
171 }
172
173 pub fn maybe_cmp_operator(self) -> Option<compute::Operator> {
174 match self {
175 Operator::Eq => Some(compute::Operator::Eq),
176 Operator::NotEq => Some(compute::Operator::NotEq),
177 Operator::Lt => Some(compute::Operator::Lt),
178 Operator::Lte => Some(compute::Operator::Lte),
179 Operator::Gt => Some(compute::Operator::Gt),
180 Operator::Gte => Some(compute::Operator::Gte),
181 _ => None,
182 }
183 }
184
185 pub fn is_arithmetic(&self) -> bool {
186 matches!(self, Self::Add | Self::Sub | Self::Mul | Self::Div)
187 }
188
189 pub fn is_comparison(&self) -> bool {
190 matches!(
191 self,
192 Self::Eq | Self::NotEq | Self::Gt | Self::Gte | Self::Lt | Self::Lte
193 )
194 }
195}
196
197impl From<compute::Operator> for Operator {
198 fn from(cmp_operator: compute::Operator) -> Self {
199 match cmp_operator {
200 compute::Operator::Eq => Operator::Eq,
201 compute::Operator::NotEq => Operator::NotEq,
202 compute::Operator::Gt => Operator::Gt,
203 compute::Operator::Gte => Operator::Gte,
204 compute::Operator::Lt => Operator::Lt,
205 compute::Operator::Lte => Operator::Lte,
206 }
207 }
208}
209
210impl TryInto<compute::Operator> for Operator {
211 type Error = VortexError;
212
213 fn try_into(self) -> VortexResult<compute::Operator> {
214 Ok(match self {
215 Operator::Eq => compute::Operator::Eq,
216 Operator::NotEq => compute::Operator::NotEq,
217 Operator::Gt => compute::Operator::Gt,
218 Operator::Gte => compute::Operator::Gte,
219 Operator::Lt => compute::Operator::Lt,
220 Operator::Lte => compute::Operator::Lte,
221 _ => vortex_bail!("Not a compute operator: {}", self),
222 })
223 }
224}
225
226impl TryFrom<compute::BooleanOperator> for Operator {
227 type Error = VortexError;
228
229 fn try_from(value: compute::BooleanOperator) -> VortexResult<Self> {
230 match value {
231 compute::BooleanOperator::AndKleene => Ok(Operator::And),
232 compute::BooleanOperator::OrKleene => Ok(Operator::Or),
233 other => vortex_bail!(
234 "Non-Kleene boolean operator {other:?} cannot be represented as an expression Operator"
235 ),
236 }
237 }
238}