1use std::fmt;
4use std::ops::{Add, Div, Mul, Neg, Not, Rem, Sub};
5
6use crate::media::Color;
7use crate::numerics::{Matrix3x2, Matrix4x4, Quaternion, Vector2, Vector3, Vector4};
8use crate::utilities::span_helpers::InvariantF64;
9use crate::{Matrix, RelativePoint, RelativeScalar, RelativeUnit, Vector, Vector3D};
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
13pub enum VariantType {
14 #[default]
15 Invalid,
16 Boolean,
17 Double,
18 Vector2,
19 Vector3,
20 Vector4,
21 Vector,
22 Vector3D,
23 FerroMatrix,
24 Matrix3x2,
25 Matrix4x4,
26 Quaternion,
27 Color,
28 RelativePoint,
29 RelativeScalar,
30 RelativeUnit,
31}
32
33#[derive(Clone, Copy, Debug, PartialEq, Default)]
38pub enum ExpressionVariant {
39 #[default]
40 Invalid,
41 Boolean(bool),
42 Double(f64),
43 Vector2(Vector2),
44 Vector3(Vector3),
45 Vector4(Vector4),
46 Vector(Vector),
47 Vector3D(Vector3D),
48 FerroMatrix(Matrix),
49 Matrix3x2(Matrix3x2),
50 Matrix4x4(Matrix4x4),
51 Quaternion(Quaternion),
52 Color(Color),
53 RelativePoint(RelativePoint),
54 RelativeScalar(RelativeScalar),
55 RelativeUnit(RelativeUnit),
56}
57
58use ExpressionVariant as V;
59
60impl ExpressionVariant {
61 pub fn variant_type(&self) -> VariantType {
63 match self {
64 V::Invalid => VariantType::Invalid,
65 V::Boolean(_) => VariantType::Boolean,
66 V::Double(_) => VariantType::Double,
67 V::Vector2(_) => VariantType::Vector2,
68 V::Vector3(_) => VariantType::Vector3,
69 V::Vector4(_) => VariantType::Vector4,
70 V::Vector(_) => VariantType::Vector,
71 V::Vector3D(_) => VariantType::Vector3D,
72 V::FerroMatrix(_) => VariantType::FerroMatrix,
73 V::Matrix3x2(_) => VariantType::Matrix3x2,
74 V::Matrix4x4(_) => VariantType::Matrix4x4,
75 V::Quaternion(_) => VariantType::Quaternion,
76 V::Color(_) => VariantType::Color,
77 V::RelativePoint(_) => VariantType::RelativePoint,
78 V::RelativeScalar(_) => VariantType::RelativeScalar,
79 V::RelativeUnit(_) => VariantType::RelativeUnit,
80 }
81 }
82
83 pub fn get_property(&self, property: &str) -> ExpressionVariant {
86 match *self {
87 V::Vector2(v) => match property {
88 "X" => f(v.x),
89 "Y" => f(v.y),
90 _ => V::Invalid,
91 },
92
93 V::Vector(v) => match property {
94 "X" => v.x.into(),
95 "Y" => v.y.into(),
96 _ => V::Invalid,
97 },
98
99 V::Vector3(v) => match property {
100 "X" => f(v.x),
101 "Y" => f(v.y),
102 "Z" => f(v.z),
103 "XY" => Vector2::new(v.x, v.y).into(),
104 "YX" => Vector2::new(v.y, v.x).into(),
105 "XZ" => Vector2::new(v.x, v.z).into(),
106 "ZX" => Vector2::new(v.z, v.x).into(),
107 "YZ" => Vector2::new(v.y, v.z).into(),
108 "ZY" => Vector2::new(v.z, v.y).into(),
109 _ => V::Invalid,
110 },
111
112 V::Vector3D(v) => match property {
113 "X" => v.x.into(),
114 "Y" => v.y.into(),
115 "Z" => v.z.into(),
116 "XY" => Vector::new(v.x, v.y).into(),
117 "YX" => Vector::new(v.y, v.x).into(),
118 "XZ" => Vector::new(v.x, v.z).into(),
119 "ZX" => Vector::new(v.z, v.x).into(),
120 "YZ" => Vector::new(v.y, v.z).into(),
121 "ZY" => Vector::new(v.z, v.y).into(),
122 _ => V::Invalid,
123 },
124
125 V::Vector4(v) => match property {
126 "X" => f(v.x),
127 "Y" => f(v.y),
128 "Z" => f(v.z),
129 "W" => f(v.w),
130 _ => V::Invalid,
131 },
132
133 V::Matrix3x2(m) => match property {
134 "M11" => f(m.m11),
135 "M12" => f(m.m12),
136 "M21" => f(m.m21),
137 "M22" => f(m.m22),
138 "M31" => f(m.m31),
139 "M32" => f(m.m32),
140 _ => V::Invalid,
141 },
142
143 V::FerroMatrix(m) => match property {
144 "M11" => m.m11.into(),
145 "M12" => m.m12.into(),
146 "M13" => m.m13.into(),
147 "M21" => m.m21.into(),
148 "M22" => m.m22.into(),
149 "M23" => m.m23.into(),
150 "M31" => m.m31.into(),
151 "M32" => m.m32.into(),
152 "M33" => m.m33.into(),
153 _ => V::Invalid,
154 },
155
156 V::Matrix4x4(m) => match property {
157 "M11" => f(m.m11),
158 "M12" => f(m.m12),
159 "M13" => f(m.m13),
160 "M14" => f(m.m14),
161 "M21" => f(m.m21),
162 "M22" => f(m.m22),
163 "M23" => f(m.m23),
164 "M24" => f(m.m24),
165 "M31" => f(m.m31),
166 "M32" => f(m.m32),
167 "M33" => f(m.m33),
168 "M34" => f(m.m34),
169 "M41" => f(m.m41),
170 "M42" => f(m.m42),
171 "M43" => f(m.m43),
172 "M44" => f(m.m44),
173 _ => V::Invalid,
174 },
175
176 V::Quaternion(q) => match property {
177 "X" => f(q.x),
178 "Y" => f(q.y),
179 "Z" => f(q.z),
180 "W" => f(q.w),
181 _ => V::Invalid,
182 },
183
184 V::Color(c) => match property {
185 "A" => (c.a as f64).into(),
186 "R" => (c.r as f64).into(),
187 "G" => (c.g as f64).into(),
188 "B" => (c.b as f64).into(),
189 _ => V::Invalid,
190 },
191
192 V::RelativePoint(p) => match property {
195 "X" => f(p.point.x as f32),
196 "Y" => f(p.point.y as f32),
197 "Unit" => p.unit.into(),
198 _ => V::Invalid,
199 },
200
201 V::RelativeScalar(s) => match property {
202 "Scalar" => s.scalar.into(),
203 "Unit" => s.unit.into(),
204 _ => V::Invalid,
205 },
206
207 _ => V::Invalid,
208 }
209 }
210
211 pub fn equals_to(&self, right: ExpressionVariant) -> ExpressionVariant {
214 match (*self, right) {
215 (V::Double(l), V::Double(r)) => (l == r).into(),
216 (V::Vector2(l), V::Vector2(r)) => (l == r).into(),
217 (V::Vector(l), V::Vector(r)) => (l == r).into(),
218 (V::Vector3(l), V::Vector3(r)) => (l == r).into(),
219 (V::Vector3D(l), V::Vector3D(r)) => (l == r).into(),
220 (V::Vector4(l), V::Vector4(r)) => (l == r).into(),
221 (V::Boolean(l), V::Boolean(r)) => (l == r).into(),
222 (V::Matrix3x2(l), V::Matrix3x2(r)) => (l == r).into(),
223 (V::FerroMatrix(l), V::FerroMatrix(r)) => (l == r).into(),
224 (V::Matrix4x4(l), V::Matrix4x4(r)) => (l == r).into(),
225 (V::Quaternion(l), V::Quaternion(r)) => (l == r).into(),
226 (V::RelativePoint(l), V::RelativePoint(r)) => (l == r).into(),
227 (V::RelativeScalar(l), V::RelativeScalar(r)) => (l == r).into(),
228 (V::RelativeUnit(l), V::RelativeUnit(r)) => (l == r).into(),
229 _ => V::Invalid,
230 }
231 }
232
233 pub fn not_equals_to(&self, right: ExpressionVariant) -> ExpressionVariant {
235 match self.equals_to(right) {
236 V::Boolean(r) => (!r).into(),
237 _ => V::Invalid,
238 }
239 }
240
241 pub fn less_than(&self, right: ExpressionVariant) -> ExpressionVariant {
243 match (*self, right) {
244 (V::Double(l), V::Double(r)) => (l < r).into(),
245 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => (l.scalar < r.scalar).into(),
246 _ => V::Invalid,
247 }
248 }
249
250 pub fn more_than(&self, right: ExpressionVariant) -> ExpressionVariant {
252 match (*self, right) {
253 (V::Double(l), V::Double(r)) => (l > r).into(),
254 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => (l.scalar > r.scalar).into(),
255 _ => V::Invalid,
256 }
257 }
258
259 pub fn and(&self, right: ExpressionVariant) -> ExpressionVariant {
261 match (*self, right) {
262 (V::Boolean(l), V::Boolean(r)) => (l && r).into(),
263 _ => V::Invalid,
264 }
265 }
266
267 pub fn or(&self, right: ExpressionVariant) -> ExpressionVariant {
269 match (*self, right) {
270 (V::Boolean(l), V::Boolean(r)) => (l || r).into(),
271 _ => V::Invalid,
272 }
273 }
274
275 #[inline]
278 pub fn try_cast<T: ExpressionVariantValue>(&self) -> Option<T> {
279 T::try_from_variant(self)
280 }
281
282 #[inline]
284 pub fn create<T: ExpressionVariantValue>(v: T) -> ExpressionVariant {
285 v.into_variant()
286 }
287
288 #[inline]
290 pub fn cast_or_default<T: ExpressionVariantValue>(&self) -> T {
291 self.try_cast::<T>().unwrap_or_default()
292 }
293}
294
295#[inline]
297fn f(value: f32) -> ExpressionVariant {
298 V::Double(value as f64)
299}
300
301pub trait ExpressionVariantValue: Copy + Default + 'static {
303 const FFI_VARIANT_TYPE: Option<VariantType>;
306
307 fn try_from_variant(variant: &ExpressionVariant) -> Option<Self>;
309
310 fn into_variant(self) -> ExpressionVariant;
312}
313
314macro_rules! variant_value {
315 ($ty:ty, $variant:ident, $ffi:expr, |$v:ident| $cast:expr) => {
316 impl From<$ty> for ExpressionVariant {
317 #[inline]
318 fn from(value: $ty) -> ExpressionVariant {
319 ExpressionVariant::$variant(value)
320 }
321 }
322
323 impl ExpressionVariantValue for $ty {
324 const FFI_VARIANT_TYPE: Option<VariantType> = $ffi;
325
326 #[inline]
327 fn try_from_variant($v: &ExpressionVariant) -> Option<Self> {
328 $cast
329 }
330
331 #[inline]
332 fn into_variant(self) -> ExpressionVariant {
333 ExpressionVariant::$variant(self)
334 }
335 }
336 };
337 ($ty:ty, $variant:ident, $ffi:expr) => {
338 variant_value!($ty, $variant, $ffi, |v| match *v {
339 ExpressionVariant::$variant(value) => Some(value),
340 _ => None,
341 });
342 };
343}
344
345variant_value!(bool, Boolean, Some(VariantType::Boolean));
346variant_value!(f64, Double, Some(VariantType::Double));
347variant_value!(Vector2, Vector2, Some(VariantType::Vector2), |v| match *v {
348 V::Vector2(value) => Some(value),
349 V::Vector(value) => Some(value.into()),
350 _ => None,
351});
352variant_value!(Vector, Vector, Some(VariantType::Vector), |v| match *v {
353 V::Vector(value) => Some(value),
354 V::Vector2(value) => Some(value.into()),
355 _ => None,
356});
357variant_value!(Vector3, Vector3, Some(VariantType::Vector3), |v| match *v {
358 V::Vector3(value) => Some(value),
359 V::Vector3D(value) => Some(value.into()),
360 _ => None,
361});
362variant_value!(Vector3D, Vector3D, Some(VariantType::Vector3D), |v| match *v {
363 V::Vector3D(value) => Some(value),
364 V::Vector3(value) => Some(value.into()),
365 _ => None,
366});
367variant_value!(Vector4, Vector4, Some(VariantType::Vector4));
368variant_value!(Matrix3x2, Matrix3x2, Some(VariantType::Matrix3x2));
369variant_value!(Matrix, FerroMatrix, None);
372variant_value!(Matrix4x4, Matrix4x4, Some(VariantType::Matrix4x4));
373variant_value!(Quaternion, Quaternion, Some(VariantType::Quaternion));
374variant_value!(Color, Color, Some(VariantType::Color));
375variant_value!(RelativePoint, RelativePoint, Some(VariantType::RelativePoint));
376variant_value!(RelativeScalar, RelativeScalar, Some(VariantType::RelativeScalar));
377variant_value!(RelativeUnit, RelativeUnit, Some(VariantType::RelativeUnit));
378
379impl From<f32> for ExpressionVariant {
381 #[inline]
382 fn from(value: f32) -> ExpressionVariant {
383 V::Double(value as f64)
384 }
385}
386
387impl ExpressionVariantValue for f32 {
388 const FFI_VARIANT_TYPE: Option<VariantType> = Some(VariantType::Double);
389
390 #[inline]
391 fn try_from_variant(variant: &ExpressionVariant) -> Option<Self> {
392 match *variant {
393 V::Double(value) => Some(value as f32),
394 _ => None,
395 }
396 }
397
398 #[inline]
399 fn into_variant(self) -> ExpressionVariant {
400 self.into()
401 }
402}
403
404impl Add for ExpressionVariant {
405 type Output = ExpressionVariant;
406
407 fn add(self, right: ExpressionVariant) -> ExpressionVariant {
408 match (self, right) {
409 (V::Double(l), V::Double(r)) => (l + r).into(),
410 (V::Vector2(l), V::Vector2(r)) => (l + r).into(),
411 (V::Vector(l), V::Vector(r)) => (l + r).into(),
412 (V::Vector3(l), V::Vector3(r)) => (l + r).into(),
413 (V::Vector3D(l), V::Vector3D(r)) => Vector3D::add(l, r).into(),
414 (V::Vector4(l), V::Vector4(r)) => (l + r).into(),
415 (V::Matrix3x2(l), V::Matrix3x2(r)) => (l + r).into(),
416 (V::Matrix4x4(l), V::Matrix4x4(r)) => (l + r).into(),
417 (V::Quaternion(l), V::Quaternion(r)) => (l + r).into(),
418 (V::RelativePoint(l), V::RelativePoint(r)) if l.unit == r.unit => {
419 RelativePoint::new(l.point.x + r.point.x, l.point.y + r.point.y, l.unit).into()
420 }
421 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
422 RelativeScalar::new(l.scalar + r.scalar, l.unit).into()
423 }
424 _ => V::Invalid,
425 }
426 }
427}
428
429impl Sub for ExpressionVariant {
430 type Output = ExpressionVariant;
431
432 fn sub(self, right: ExpressionVariant) -> ExpressionVariant {
433 match (self, right) {
434 (V::Double(l), V::Double(r)) => (l - r).into(),
435 (V::Vector2(l), V::Vector2(r)) => (l - r).into(),
436 (V::Vector(l), V::Vector(r)) => (l - r).into(),
437 (V::Vector3(l), V::Vector3(r)) => (l - r).into(),
438 (V::Vector3D(l), V::Vector3D(r)) => Vector3D::add(l, -r).into(),
439 (V::Vector4(l), V::Vector4(r)) => (l - r).into(),
440 (V::Matrix3x2(l), V::Matrix3x2(r)) => (l - r).into(),
441 (V::Matrix4x4(l), V::Matrix4x4(r)) => (l - r).into(),
442 (V::Quaternion(l), V::Quaternion(r)) => (l - r).into(),
443 (V::RelativePoint(l), V::RelativePoint(r)) if l.unit == r.unit => {
444 RelativePoint::new(l.point.x - r.point.x, l.point.y - r.point.y, l.unit).into()
445 }
446 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
447 RelativeScalar::new(l.scalar - r.scalar, l.unit).into()
448 }
449 _ => V::Invalid,
450 }
451 }
452}
453
454impl Neg for ExpressionVariant {
455 type Output = ExpressionVariant;
456
457 fn neg(self) -> ExpressionVariant {
458 match self {
459 V::Double(l) => (-l).into(),
460 V::Vector2(l) => (-l).into(),
461 V::Vector(l) => (-l).into(),
462 V::Vector3(l) => (-l).into(),
463 V::Vector3D(l) => (-l).into(),
464 V::Vector4(l) => (-l).into(),
465 V::Matrix3x2(l) => (-l).into(),
466 V::FerroMatrix(l) => (-l).into(),
467 V::Matrix4x4(l) => (-l).into(),
468 V::Quaternion(l) => (-l).into(),
469 V::RelativePoint(l) => RelativePoint::new(-l.point.x, -l.point.y, l.unit).into(),
470 V::RelativeScalar(l) => RelativeScalar::new(-l.scalar, l.unit).into(),
471 _ => V::Invalid,
472 }
473 }
474}
475
476impl Mul for ExpressionVariant {
477 type Output = ExpressionVariant;
478
479 fn mul(self, right: ExpressionVariant) -> ExpressionVariant {
480 match (self, right) {
481 (V::Double(l), V::Double(r)) => (l * r).into(),
482 (V::Vector2(l), V::Vector2(r)) => (l * r).into(),
483 (V::Vector(l), V::Vector(r)) => Vector::multiply(l, r).into(),
484 (V::Vector2(l), V::Double(r)) => (l * (r as f32)).into(),
485 (V::Vector(l), V::Double(r)) => (l * r).into(),
486 (V::Vector3(l), V::Vector3(r)) => (l * r).into(),
487 (V::Vector3D(l), V::Vector3D(r)) => Vector3D::multiply(l, r).into(),
488 (V::Vector3(l), V::Double(r)) => (l * (r as f32)).into(),
489 (V::Vector3D(l), V::Double(r)) => Vector3D::multiply_scalar(l, r).into(),
490 (V::Vector4(l), V::Vector4(r)) => (l * r).into(),
491 (V::Vector4(l), V::Double(r)) => (l * (r as f32)).into(),
492 (V::Matrix3x2(l), V::Matrix3x2(r)) => (l * r).into(),
493 (V::Matrix3x2(l), V::Double(r)) => (l * (r as f32)).into(),
494 (V::FerroMatrix(l), V::FerroMatrix(r)) => (l * r).into(),
495 (V::Matrix4x4(l), V::Matrix4x4(r)) => (l * r).into(),
496 (V::Matrix4x4(l), V::Double(r)) => (l * (r as f32)).into(),
497 (V::Quaternion(l), V::Quaternion(r)) => (l * r).into(),
498 (V::Quaternion(l), V::Double(r)) => (l * (r as f32)).into(),
499 (V::RelativePoint(l), V::Double(r)) => RelativePoint::new(l.point.x * r, l.point.y * r, l.unit).into(),
500 (V::Double(l), V::RelativePoint(r)) => RelativePoint::new(l * r.point.x, l * r.point.y, r.unit).into(),
501 (V::RelativeScalar(l), V::Double(r)) => RelativeScalar::new(l.scalar * r, l.unit).into(),
502 (V::Double(l), V::RelativeScalar(r)) => RelativeScalar::new(l * r.scalar, r.unit).into(),
503 (V::RelativePoint(l), V::RelativePoint(r)) if l.unit == r.unit => {
504 RelativePoint::new(l.point.x * r.point.x, l.point.y * r.point.y, l.unit).into()
505 }
506 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
507 RelativeScalar::new(l.scalar * r.scalar, l.unit).into()
508 }
509 _ => V::Invalid,
510 }
511 }
512}
513
514impl Div for ExpressionVariant {
515 type Output = ExpressionVariant;
516
517 fn div(self, right: ExpressionVariant) -> ExpressionVariant {
518 match (self, right) {
519 (V::Double(l), V::Double(r)) => (l / r).into(),
520 (V::Vector2(l), V::Vector2(r)) => (l / r).into(),
521 (V::Vector(l), V::Vector(r)) => Vector::divide(l, r).into(),
522 (V::Vector2(l), V::Double(r)) => (l / (r as f32)).into(),
523 (V::Vector(l), V::Double(r)) => (l / r).into(),
524 (V::Vector3(l), V::Vector3(r)) => (l / r).into(),
525 (V::Vector3D(l), V::Vector3D(r)) => Vector3D::divide(l, r).into(),
526 (V::Vector3(l), V::Double(r)) => (l / (r as f32)).into(),
527 (V::Vector3D(l), V::Double(r)) => Vector3D::divide_scalar(l, r).into(),
528 (V::Vector4(l), V::Vector4(r)) => (l / r).into(),
529 (V::Vector4(l), V::Double(r)) => (l / (r as f32)).into(),
530 (V::Quaternion(l), V::Quaternion(r)) => (l / r).into(),
531 (V::RelativePoint(l), V::Double(r)) => RelativePoint::new(l.point.x / r, l.point.y / r, l.unit).into(),
532 (V::RelativeScalar(l), V::Double(r)) => RelativeScalar::new(l.scalar / r, l.unit).into(),
533 (V::RelativePoint(l), V::RelativePoint(r)) if l.unit == r.unit => {
534 RelativePoint::new(l.point.x / r.point.x, l.point.y / r.point.y, l.unit).into()
535 }
536 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
537 RelativeScalar::new(l.scalar / r.scalar, l.unit).into()
538 }
539 _ => V::Invalid,
540 }
541 }
542}
543
544impl Not for ExpressionVariant {
545 type Output = ExpressionVariant;
546
547 fn not(self) -> ExpressionVariant {
548 match self {
549 V::Boolean(v) => (!v).into(),
550 _ => V::Invalid,
551 }
552 }
553}
554
555impl Rem for ExpressionVariant {
556 type Output = ExpressionVariant;
557
558 fn rem(self, right: ExpressionVariant) -> ExpressionVariant {
559 match (self, right) {
560 (V::Double(l), V::Double(r)) => (l % r).into(),
561 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
562 RelativeScalar::new(l.scalar % r.scalar, l.unit).into()
563 }
564 _ => V::Invalid,
565 }
566 }
567}
568
569impl fmt::Display for ExpressionVariant {
570 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571 match self {
572 V::Boolean(v) => f.write_str(if *v { "True" } else { "False" }),
573 V::Double(v) => write!(f, "{}", InvariantF64(*v)),
574 V::Vector2(v) => v.fmt(f),
575 V::Vector(v) => v.fmt(f),
576 V::Vector3(v) => v.fmt(f),
577 V::Vector3D(v) => v.fmt(f),
578 V::Vector4(v) => v.fmt(f),
579 V::Quaternion(v) => v.fmt(f),
580 V::Matrix3x2(v) => v.fmt(f),
581 V::FerroMatrix(v) => v.fmt(f),
582 V::Matrix4x4(v) => v.fmt(f),
583 V::Color(v) => v.fmt(f),
584 V::RelativePoint(v) => v.fmt(f),
585 V::RelativeScalar(v) => v.fmt(f),
586 V::RelativeUnit(v) => fmt::Debug::fmt(v, f),
587 V::Invalid => f.write_str("Invalid"),
588 }
589 }
590}