1use std::{
2 cmp::Ordering,
3 ops::{Add, Div, Mul, Neg, Not, Rem, Sub},
4};
5
6use crate::{Numeric, PaxValue, Percent, Size, ToPaxValue};
7
8use super::{PaxAny, ToFromPaxAny};
9
10const ANY_ARITH_UNSUPPORTED: &'static str =
11 "types that are not representable as PaxValues are not supported in arithmetic expressions";
12impl Add for PaxValue {
14 type Output = Self;
15
16 fn add(self, rhs: Self) -> Self::Output {
17 match (self, rhs) {
18 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => (a + b).to_pax_value(),
20 (PaxValue::String(a), PaxValue::String(b)) => (a + &b).to_pax_value(),
21 (PaxValue::String(a), PaxValue::Numeric(b)) => (a + &b.to_string()).to_pax_value(),
22 (PaxValue::Numeric(a), PaxValue::String(b)) => (a.to_string() + &b).to_pax_value(),
23
24 (PaxValue::Size(a), PaxValue::Size(b)) => (a + b).to_pax_value(),
26 (PaxValue::Percent(a), PaxValue::Percent(b)) => (Percent(a.0 + b.0)).to_pax_value(),
27 (PaxValue::Percent(a), PaxValue::Size(b))
28 | (PaxValue::Size(b), PaxValue::Percent(a)) => (Size::Percent(a.0) + b).to_pax_value(),
29 (PaxValue::Bool(a), PaxValue::Numeric(b))
30 | (PaxValue::Numeric(b), PaxValue::Bool(a)) => {
31 (Numeric::I64(a as i64) + b).to_pax_value()
32 }
33 (PaxValue::Size(a), PaxValue::Numeric(b))
34 | (PaxValue::Numeric(b), PaxValue::Size(a)) => match a {
35 Size::Pixels(px) => Size::Pixels(px + b).to_pax_value(),
36 Size::Percent(per) => Size::Percent(per + b).to_pax_value(),
37 Size::Combined(px, per) => Size::Combined(px + b, per + b).to_pax_value(),
38 },
39 (PaxValue::Numeric(a), PaxValue::Percent(b)) => Size::Combined(a, b.0).to_pax_value(),
40 (PaxValue::Percent(a), PaxValue::Numeric(b)) => Size::Combined(b, a.0).to_pax_value(),
41 (a, b) => {
42 log::warn!("can't add {:?} and {:?}", a, b);
43 PaxValue::default()
44 }
45 }
46 }
47}
48
49impl Mul for PaxValue {
50 type Output = Self;
51
52 fn mul(self, rhs: Self) -> Self::Output {
53 match (self, rhs) {
54 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => (a * b).to_pax_value(),
55 (PaxValue::Bool(a), PaxValue::Numeric(b))
56 | (PaxValue::Numeric(b), PaxValue::Bool(a)) => {
57 (Numeric::I64(a as i64) * b).to_pax_value()
58 }
59 (PaxValue::Bool(a), PaxValue::Percent(b))
60 | (PaxValue::Percent(b), PaxValue::Bool(a)) => {
61 if a {
62 return PaxValue::Percent(b);
63 } else {
64 return PaxValue::Percent(Percent(0.into()));
65 }
66 }
67 (PaxValue::Size(a), PaxValue::Numeric(b))
68 | (PaxValue::Numeric(b), PaxValue::Size(a)) => match a {
69 Size::Pixels(px) => Size::Pixels(px * b).to_pax_value(),
70 Size::Percent(per) => Size::Percent(per * b).to_pax_value(),
71 Size::Combined(px, per) => Size::Combined(px * b, per * b).to_pax_value(),
72 },
73 (a, b) => {
74 log::warn!("can't multiply {:?} and {:?}", a, b);
75 PaxValue::default()
76 }
77 }
78 }
79}
80
81impl Sub for PaxValue {
82 type Output = Self;
83
84 fn sub(self, rhs: Self) -> Self::Output {
85 match (self, rhs) {
86 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => (a - b).to_pax_value(),
87 (PaxValue::Size(a), PaxValue::Size(b)) => (a - b).to_pax_value(),
89 (PaxValue::Percent(a), PaxValue::Percent(b)) => (Percent(a.0 - b.0)).to_pax_value(),
90 (PaxValue::Percent(a), PaxValue::Size(b)) => (Size::Percent(a.0) - b).to_pax_value(),
91 (PaxValue::Size(a), PaxValue::Percent(b)) => (a - Size::Percent(b.0)).to_pax_value(),
92 (PaxValue::Size(a), PaxValue::Numeric(b))
93 | (PaxValue::Numeric(b), PaxValue::Size(a)) => match a {
94 Size::Pixels(px) => Size::Pixels(px - b).to_pax_value(),
95 Size::Percent(per) => Size::Percent(per - b).to_pax_value(),
96 Size::Combined(px, per) => Size::Combined(px - b, per - b).to_pax_value(),
97 },
98 (a, b) => {
99 log::warn!("can't subtract {:?} and {:?}", a, b);
100 PaxValue::default()
101 }
102 }
103 }
104}
105
106impl Div for PaxValue {
107 type Output = Self;
108
109 fn div(self, rhs: Self) -> Self::Output {
110 match (self, rhs) {
111 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => (a / b).to_pax_value(),
112 (PaxValue::Size(a), PaxValue::Numeric(b))
113 | (PaxValue::Numeric(b), PaxValue::Size(a)) => match a {
114 Size::Pixels(px) => Size::Pixels(px / b).to_pax_value(),
115 Size::Percent(per) => Size::Percent(per / b).to_pax_value(),
116 Size::Combined(px, per) => Size::Combined(px / b, per / b).to_pax_value(),
117 },
118 (a, b) => {
119 log::warn!("can't divide {:?} and {:?}", a, b);
120 PaxValue::default()
121 }
122 }
123 }
124}
125
126impl Neg for PaxValue {
127 type Output = Self;
128
129 fn neg(self) -> Self::Output {
130 match self {
131 PaxValue::Numeric(a) => (-a).to_pax_value(),
132 PaxValue::Size(a) => (-a).to_pax_value(),
133 PaxValue::Percent(p) => (-p.0).to_pax_value(),
134 PaxValue::Rotation(r) => (-r).to_pax_value(),
135 a => {
136 log::warn!("can't negate {:?}", a);
137 PaxValue::default()
138 }
139 }
140 }
141}
142
143impl PartialOrd for PaxValue {
144 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
145 match (self, rhs) {
146 (PaxValue::Bool(a), PaxValue::Bool(b)) => a.partial_cmp(b),
147 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => a.partial_cmp(b),
148 (PaxValue::String(a), PaxValue::String(b)) => a.partial_cmp(b),
149 (a, b) => {
150 log::warn!("can't compare {:?} and {:?}", a, b);
151 None
152 }
153 }
154 }
155}
156
157impl Rem for PaxValue {
158 type Output = Self;
159
160 fn rem(self, rhs: Self) -> Self::Output {
161 match (self, rhs) {
162 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => (a % b).to_pax_value(),
163 (a, b) => {
164 log::warn!("can't take remainder of {:?} and {:?}", a, b);
165 PaxValue::default()
166 }
167 }
168 }
169}
170
171impl Not for PaxValue {
172 type Output = PaxValue;
173
174 fn not(self) -> Self::Output {
175 match self {
176 PaxValue::Bool(v) => PaxValue::Bool(!v),
177 v => {
178 log::warn!("can't use not(!) operator on {:?}", v);
179 PaxValue::default()
180 }
181 }
182 }
183}
184
185impl PaxValue {
186 pub fn op_and(self, rhs: Self) -> Self {
189 match (self, rhs) {
190 (PaxValue::Bool(a), PaxValue::Bool(b)) => PaxValue::Bool(a && b),
191 (a, b) => {
192 log::warn!("&& operator not valid for {:?} and {:?}", a, b);
194 PaxValue::default()
195 }
196 }
197 }
198 pub fn op_or(self, rhs: Self) -> Self {
201 match (self, rhs) {
202 (PaxValue::Bool(a), PaxValue::Bool(b)) => PaxValue::Bool(a || b),
203 (a, b) => {
204 log::warn!("&& operator not valid for {:?} and {:?}", a, b);
206 PaxValue::default()
207 }
208 }
209 }
210
211 pub fn op_not(self) -> Self {
212 match self {
213 PaxValue::Bool(v) => PaxValue::Bool(!v),
214 v => {
215 log::warn!("! operator not valid for {:?}", v);
216 PaxValue::default()
217 }
218 }
219 }
220
221 pub fn pow(self, exp: Self) -> Self {
223 match (self, exp) {
224 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => a.pow(b).to_pax_value(),
225 (a, b) => {
226 log::warn!("exponentiation not valid between {:?} and {:?}", a, b);
227 PaxValue::default()
228 }
229 }
230 }
231
232 pub fn min(self, rhs: Self) -> Self {
233 match (self, rhs) {
234 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => a.min(b).to_pax_value(),
235 (a, b) => {
236 log::warn!("min not valid between {:?} and {:?}", a, b);
237 PaxValue::default()
238 }
239 }
240 }
241
242 pub fn max(self, rhs: Self) -> Self {
243 match (self, rhs) {
244 (PaxValue::Numeric(a), PaxValue::Numeric(b)) => a.max(b).to_pax_value(),
245 (a, b) => {
246 log::warn!("max not valid between {:?} and {:?}", a, b);
247 PaxValue::default()
248 }
249 }
250 }
251}
252
253impl Add for PaxAny {
255 type Output = Self;
256
257 fn add(self, rhs: Self) -> Self::Output {
258 match (self, rhs) {
259 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => (a + b).to_pax_any(),
260 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
261 }
262 }
263}
264
265impl Mul for PaxAny {
266 type Output = Self;
267
268 fn mul(self, rhs: Self) -> Self::Output {
269 match (self, rhs) {
270 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => (a * b).to_pax_any(),
271 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
272 }
273 }
274}
275
276impl Sub for PaxAny {
277 type Output = Self;
278
279 fn sub(self, rhs: Self) -> Self::Output {
280 match (self, rhs) {
281 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => (a - b).to_pax_any(),
282 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
283 }
284 }
285}
286
287impl Div for PaxAny {
288 type Output = Self;
289
290 fn div(self, rhs: Self) -> Self::Output {
291 match (self, rhs) {
292 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => (a / b).to_pax_any(),
293 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
294 }
295 }
296}
297
298impl Rem for PaxAny {
299 type Output = Self;
300
301 fn rem(self, rhs: Self) -> Self::Output {
302 match (self, rhs) {
303 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => (a % b).to_pax_any(),
304 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
305 }
306 }
307}
308
309impl Neg for PaxAny {
310 type Output = Self;
311
312 fn neg(self) -> Self::Output {
313 match self {
314 PaxAny::Builtin(a) => (-a).to_pax_any(),
315 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
316 }
317 }
318}
319
320impl PartialEq for PaxAny {
321 fn eq(&self, rhs: &Self) -> bool {
322 match (self, rhs) {
323 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => a == b,
324 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
325 }
326 }
327}
328
329impl PartialOrd for PaxAny {
330 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
331 match (self, rhs) {
332 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => a.partial_cmp(b),
333 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
334 }
335 }
336}
337
338impl Not for PaxAny {
339 type Output = PaxAny;
340
341 fn not(self) -> Self::Output {
342 match self {
343 PaxAny::Builtin(v) => (!v).to_pax_any(),
344 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
345 }
346 }
347}
348
349impl PaxAny {
350 pub fn op_and(self, rhs: Self) -> Self {
353 match (self, rhs) {
354 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => a.op_and(b).to_pax_any(),
355 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
356 }
357 }
358 pub fn op_or(self, rhs: Self) -> Self {
361 match (self, rhs) {
362 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => a.op_or(b).to_pax_any(),
363 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
364 }
365 }
366
367 pub fn pow(self, exp: Self) -> Self {
369 match (self, exp) {
370 (PaxAny::Builtin(a), PaxAny::Builtin(b)) => a.pow(b).to_pax_any(),
371 _ => panic!("{}", ANY_ARITH_UNSUPPORTED),
372 }
373 }
374}