1use core::fmt;
5use std::fmt::{Display, Formatter};
6
7use vortex_array::compute;
8use vortex_error::{VortexError, VortexResult, vortex_bail};
9use vortex_proto::expr::binary_opts::BinaryOp;
10
11#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub enum Operator {
19    Eq,
21    NotEq,
23    Gt,
25    Gte,
27    Lt,
29    Lte,
31    And,
33    Or,
35    Add,
39    Sub,
45}
46
47impl From<Operator> for i32 {
48    fn from(value: Operator) -> Self {
49        let op: BinaryOp = value.into();
50        op.into()
51    }
52}
53
54impl From<Operator> for BinaryOp {
55    fn from(value: Operator) -> Self {
56        match value {
57            Operator::Eq => BinaryOp::Eq,
58            Operator::NotEq => BinaryOp::NotEq,
59            Operator::Gt => BinaryOp::Gt,
60            Operator::Gte => BinaryOp::Gte,
61            Operator::Lt => BinaryOp::Lt,
62            Operator::Lte => BinaryOp::Lte,
63            Operator::And => BinaryOp::And,
64            Operator::Or => BinaryOp::Or,
65            Operator::Add => BinaryOp::Add,
66            Operator::Sub => BinaryOp::Sub,
67        }
68    }
69}
70
71impl TryFrom<i32> for Operator {
72    type Error = VortexError;
73
74    fn try_from(value: i32) -> Result<Self, Self::Error> {
75        Ok(BinaryOp::try_from(value)?.into())
76    }
77}
78
79impl From<BinaryOp> for Operator {
80    fn from(value: BinaryOp) -> Self {
81        match value {
82            BinaryOp::Eq => Operator::Eq,
83            BinaryOp::NotEq => Operator::NotEq,
84            BinaryOp::Gt => Operator::Gt,
85            BinaryOp::Gte => Operator::Gte,
86            BinaryOp::Lt => Operator::Lt,
87            BinaryOp::Lte => Operator::Lte,
88            BinaryOp::And => Operator::And,
89            BinaryOp::Or => Operator::Or,
90            BinaryOp::Add => Operator::Add,
91            BinaryOp::Sub => Operator::Sub,
92        }
93    }
94}
95
96impl Display for Operator {
97    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
98        let display = match &self {
99            Operator::Eq => "=",
100            Operator::NotEq => "!=",
101            Operator::Gt => ">",
102            Operator::Gte => ">=",
103            Operator::Lt => "<",
104            Operator::Lte => "<=",
105            Operator::And => "and",
106            Operator::Or => "or",
107            Operator::Add => "+",
108            Operator::Sub => "-",
109        };
110        Display::fmt(display, f)
111    }
112}
113
114impl Operator {
115    pub fn inverse(self) -> Option<Self> {
116        match self {
117            Operator::Eq => Some(Operator::NotEq),
118            Operator::NotEq => Some(Operator::Eq),
119            Operator::Gt => Some(Operator::Lte),
120            Operator::Gte => Some(Operator::Lt),
121            Operator::Lt => Some(Operator::Gte),
122            Operator::Lte => Some(Operator::Gt),
123            Operator::And | Operator::Or | Operator::Add | Operator::Sub => None,
124        }
125    }
126
127    pub fn logical_inverse(self) -> Option<Self> {
128        match self {
129            Operator::And => Some(Operator::Or),
130            Operator::Or => Some(Operator::And),
131            _ => None,
132        }
133    }
134
135    pub fn swap(self) -> Self {
137        match self {
138            Operator::Eq => Operator::Eq,
139            Operator::NotEq => Operator::NotEq,
140            Operator::Gt => Operator::Lt,
141            Operator::Gte => Operator::Lte,
142            Operator::Lt => Operator::Gt,
143            Operator::Lte => Operator::Gte,
144            Operator::And => Operator::And,
145            Operator::Or => Operator::Or,
146            Operator::Add => Operator::Add,
147            Operator::Sub => Operator::Sub,
148        }
149    }
150
151    pub fn maybe_cmp_operator(self) -> Option<compute::Operator> {
152        match self {
153            Operator::Eq => Some(compute::Operator::Eq),
154            Operator::NotEq => Some(compute::Operator::NotEq),
155            Operator::Lt => Some(compute::Operator::Lt),
156            Operator::Lte => Some(compute::Operator::Lte),
157            Operator::Gt => Some(compute::Operator::Gt),
158            Operator::Gte => Some(compute::Operator::Gte),
159            _ => None,
160        }
161    }
162}
163
164impl From<compute::Operator> for Operator {
165    fn from(cmp_operator: compute::Operator) -> Self {
166        match cmp_operator {
167            compute::Operator::Eq => Operator::Eq,
168            compute::Operator::NotEq => Operator::NotEq,
169            compute::Operator::Gt => Operator::Gt,
170            compute::Operator::Gte => Operator::Gte,
171            compute::Operator::Lt => Operator::Lt,
172            compute::Operator::Lte => Operator::Lte,
173        }
174    }
175}
176
177impl TryInto<compute::Operator> for Operator {
178    type Error = VortexError;
179
180    fn try_into(self) -> VortexResult<compute::Operator> {
181        Ok(match self {
182            Operator::Eq => compute::Operator::Eq,
183            Operator::NotEq => compute::Operator::NotEq,
184            Operator::Gt => compute::Operator::Gt,
185            Operator::Gte => compute::Operator::Gte,
186            Operator::Lt => compute::Operator::Lt,
187            Operator::Lte => compute::Operator::Lte,
188            _ => vortex_bail!("Not a compute operator: {}", self),
189        })
190    }
191}