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 unify(*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
295fn unify(left: ExpressionVariant, right: ExpressionVariant) -> (ExpressionVariant, ExpressionVariant) {
304 match (left, right) {
305 (V::Vector3(l), V::Vector3D(r)) => (V::Vector3D(l.into()), V::Vector3D(r)),
306 (V::Vector3D(l), V::Vector3(r)) => (V::Vector3D(l), V::Vector3D(r.into())),
307 (V::Vector2(l), V::Vector(r)) => (V::Vector(l.into()), V::Vector(r)),
308 (V::Vector(l), V::Vector2(r)) => (V::Vector(l), V::Vector(r.into())),
309 pair => pair,
310 }
311}
312
313#[inline]
315fn f(value: f32) -> ExpressionVariant {
316 V::Double(value as f64)
317}
318
319pub trait ExpressionVariantValue: Copy + Default + 'static {
321 const FFI_VARIANT_TYPE: Option<VariantType>;
324
325 fn try_from_variant(variant: &ExpressionVariant) -> Option<Self>;
327
328 fn into_variant(self) -> ExpressionVariant;
330}
331
332macro_rules! variant_value {
333 ($ty:ty, $variant:ident, $ffi:expr, |$v:ident| $cast:expr) => {
334 impl From<$ty> for ExpressionVariant {
335 #[inline]
336 fn from(value: $ty) -> ExpressionVariant {
337 ExpressionVariant::$variant(value)
338 }
339 }
340
341 impl ExpressionVariantValue for $ty {
342 const FFI_VARIANT_TYPE: Option<VariantType> = $ffi;
343
344 #[inline]
345 fn try_from_variant($v: &ExpressionVariant) -> Option<Self> {
346 $cast
347 }
348
349 #[inline]
350 fn into_variant(self) -> ExpressionVariant {
351 ExpressionVariant::$variant(self)
352 }
353 }
354 };
355 ($ty:ty, $variant:ident, $ffi:expr) => {
356 variant_value!($ty, $variant, $ffi, |v| match *v {
357 ExpressionVariant::$variant(value) => Some(value),
358 _ => None,
359 });
360 };
361}
362
363variant_value!(bool, Boolean, Some(VariantType::Boolean));
364variant_value!(f64, Double, Some(VariantType::Double));
365variant_value!(Vector2, Vector2, Some(VariantType::Vector2), |v| match *v {
366 V::Vector2(value) => Some(value),
367 V::Vector(value) => Some(value.into()),
368 _ => None,
369});
370variant_value!(Vector, Vector, Some(VariantType::Vector), |v| match *v {
371 V::Vector(value) => Some(value),
372 V::Vector2(value) => Some(value.into()),
373 _ => None,
374});
375variant_value!(Vector3, Vector3, Some(VariantType::Vector3), |v| match *v {
376 V::Vector3(value) => Some(value),
377 V::Vector3D(value) => Some(value.into()),
378 _ => None,
379});
380variant_value!(Vector3D, Vector3D, Some(VariantType::Vector3D), |v| match *v {
381 V::Vector3D(value) => Some(value),
382 V::Vector3(value) => Some(value.into()),
383 _ => None,
384});
385variant_value!(Vector4, Vector4, Some(VariantType::Vector4));
386variant_value!(Matrix3x2, Matrix3x2, Some(VariantType::Matrix3x2));
387variant_value!(Matrix, FerroMatrix, None);
390variant_value!(Matrix4x4, Matrix4x4, Some(VariantType::Matrix4x4));
391variant_value!(Quaternion, Quaternion, Some(VariantType::Quaternion));
392variant_value!(Color, Color, Some(VariantType::Color));
393variant_value!(RelativePoint, RelativePoint, Some(VariantType::RelativePoint));
394variant_value!(RelativeScalar, RelativeScalar, Some(VariantType::RelativeScalar));
395variant_value!(RelativeUnit, RelativeUnit, Some(VariantType::RelativeUnit));
396
397impl From<f32> for ExpressionVariant {
399 #[inline]
400 fn from(value: f32) -> ExpressionVariant {
401 V::Double(value as f64)
402 }
403}
404
405impl ExpressionVariantValue for f32 {
406 const FFI_VARIANT_TYPE: Option<VariantType> = Some(VariantType::Double);
407
408 #[inline]
409 fn try_from_variant(variant: &ExpressionVariant) -> Option<Self> {
410 match *variant {
411 V::Double(value) => Some(value as f32),
412 _ => None,
413 }
414 }
415
416 #[inline]
417 fn into_variant(self) -> ExpressionVariant {
418 self.into()
419 }
420}
421
422impl Add for ExpressionVariant {
423 type Output = ExpressionVariant;
424
425 fn add(self, right: ExpressionVariant) -> ExpressionVariant {
426 match unify(self, right) {
427 (V::Double(l), V::Double(r)) => (l + r).into(),
428 (V::Vector2(l), V::Vector2(r)) => (l + r).into(),
429 (V::Vector(l), V::Vector(r)) => (l + r).into(),
430 (V::Vector3(l), V::Vector3(r)) => (l + r).into(),
431 (V::Vector3D(l), V::Vector3D(r)) => Vector3D::add(l, r).into(),
432 (V::Vector4(l), V::Vector4(r)) => (l + r).into(),
433 (V::Matrix3x2(l), V::Matrix3x2(r)) => (l + r).into(),
434 (V::Matrix4x4(l), V::Matrix4x4(r)) => (l + r).into(),
435 (V::Quaternion(l), V::Quaternion(r)) => (l + r).into(),
436 (V::RelativePoint(l), V::RelativePoint(r)) if l.unit == r.unit => {
437 RelativePoint::new(l.point.x + r.point.x, l.point.y + r.point.y, l.unit).into()
438 }
439 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
440 RelativeScalar::new(l.scalar + r.scalar, l.unit).into()
441 }
442 _ => V::Invalid,
443 }
444 }
445}
446
447impl Sub for ExpressionVariant {
448 type Output = ExpressionVariant;
449
450 fn sub(self, right: ExpressionVariant) -> ExpressionVariant {
451 match unify(self, right) {
452 (V::Double(l), V::Double(r)) => (l - r).into(),
453 (V::Vector2(l), V::Vector2(r)) => (l - r).into(),
454 (V::Vector(l), V::Vector(r)) => (l - r).into(),
455 (V::Vector3(l), V::Vector3(r)) => (l - r).into(),
456 (V::Vector3D(l), V::Vector3D(r)) => Vector3D::add(l, -r).into(),
457 (V::Vector4(l), V::Vector4(r)) => (l - r).into(),
458 (V::Matrix3x2(l), V::Matrix3x2(r)) => (l - r).into(),
459 (V::Matrix4x4(l), V::Matrix4x4(r)) => (l - r).into(),
460 (V::Quaternion(l), V::Quaternion(r)) => (l - r).into(),
461 (V::RelativePoint(l), V::RelativePoint(r)) if l.unit == r.unit => {
462 RelativePoint::new(l.point.x - r.point.x, l.point.y - r.point.y, l.unit).into()
463 }
464 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
465 RelativeScalar::new(l.scalar - r.scalar, l.unit).into()
466 }
467 _ => V::Invalid,
468 }
469 }
470}
471
472impl Neg for ExpressionVariant {
473 type Output = ExpressionVariant;
474
475 fn neg(self) -> ExpressionVariant {
476 match self {
477 V::Double(l) => (-l).into(),
478 V::Vector2(l) => (-l).into(),
479 V::Vector(l) => (-l).into(),
480 V::Vector3(l) => (-l).into(),
481 V::Vector3D(l) => (-l).into(),
482 V::Vector4(l) => (-l).into(),
483 V::Matrix3x2(l) => (-l).into(),
484 V::FerroMatrix(l) => (-l).into(),
485 V::Matrix4x4(l) => (-l).into(),
486 V::Quaternion(l) => (-l).into(),
487 V::RelativePoint(l) => RelativePoint::new(-l.point.x, -l.point.y, l.unit).into(),
488 V::RelativeScalar(l) => RelativeScalar::new(-l.scalar, l.unit).into(),
489 _ => V::Invalid,
490 }
491 }
492}
493
494impl Mul for ExpressionVariant {
495 type Output = ExpressionVariant;
496
497 fn mul(self, right: ExpressionVariant) -> ExpressionVariant {
498 match unify(self, right) {
499 (V::Double(l), V::Double(r)) => (l * r).into(),
500 (V::Vector2(l), V::Vector2(r)) => (l * r).into(),
501 (V::Vector(l), V::Vector(r)) => Vector::multiply(l, r).into(),
502 (V::Vector2(l), V::Double(r)) => (l * (r as f32)).into(),
503 (V::Vector(l), V::Double(r)) => (l * r).into(),
504 (V::Vector3(l), V::Vector3(r)) => (l * r).into(),
505 (V::Vector3D(l), V::Vector3D(r)) => Vector3D::multiply(l, r).into(),
506 (V::Vector3(l), V::Double(r)) => (l * (r as f32)).into(),
507 (V::Vector3D(l), V::Double(r)) => Vector3D::multiply_scalar(l, r).into(),
508 (V::Vector4(l), V::Vector4(r)) => (l * r).into(),
509 (V::Vector4(l), V::Double(r)) => (l * (r as f32)).into(),
510 (V::Matrix3x2(l), V::Matrix3x2(r)) => (l * r).into(),
511 (V::Matrix3x2(l), V::Double(r)) => (l * (r as f32)).into(),
512 (V::FerroMatrix(l), V::FerroMatrix(r)) => (l * r).into(),
513 (V::Matrix4x4(l), V::Matrix4x4(r)) => (l * r).into(),
514 (V::Matrix4x4(l), V::Double(r)) => (l * (r as f32)).into(),
515 (V::Quaternion(l), V::Quaternion(r)) => (l * r).into(),
516 (V::Quaternion(l), V::Double(r)) => (l * (r as f32)).into(),
517 (V::RelativePoint(l), V::Double(r)) => RelativePoint::new(l.point.x * r, l.point.y * r, l.unit).into(),
518 (V::Double(l), V::RelativePoint(r)) => RelativePoint::new(l * r.point.x, l * r.point.y, r.unit).into(),
519 (V::RelativeScalar(l), V::Double(r)) => RelativeScalar::new(l.scalar * r, l.unit).into(),
520 (V::Double(l), V::RelativeScalar(r)) => RelativeScalar::new(l * r.scalar, r.unit).into(),
521 (V::RelativePoint(l), V::RelativePoint(r)) if l.unit == r.unit => {
522 RelativePoint::new(l.point.x * r.point.x, l.point.y * r.point.y, l.unit).into()
523 }
524 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
525 RelativeScalar::new(l.scalar * r.scalar, l.unit).into()
526 }
527 _ => V::Invalid,
528 }
529 }
530}
531
532impl Div for ExpressionVariant {
533 type Output = ExpressionVariant;
534
535 fn div(self, right: ExpressionVariant) -> ExpressionVariant {
536 match unify(self, right) {
537 (V::Double(l), V::Double(r)) => (l / r).into(),
538 (V::Vector2(l), V::Vector2(r)) => (l / r).into(),
539 (V::Vector(l), V::Vector(r)) => Vector::divide(l, r).into(),
540 (V::Vector2(l), V::Double(r)) => (l / (r as f32)).into(),
541 (V::Vector(l), V::Double(r)) => (l / r).into(),
542 (V::Vector3(l), V::Vector3(r)) => (l / r).into(),
543 (V::Vector3D(l), V::Vector3D(r)) => Vector3D::divide(l, r).into(),
544 (V::Vector3(l), V::Double(r)) => (l / (r as f32)).into(),
545 (V::Vector3D(l), V::Double(r)) => Vector3D::divide_scalar(l, r).into(),
546 (V::Vector4(l), V::Vector4(r)) => (l / r).into(),
547 (V::Vector4(l), V::Double(r)) => (l / (r as f32)).into(),
548 (V::Quaternion(l), V::Quaternion(r)) => (l / r).into(),
549 (V::RelativePoint(l), V::Double(r)) => RelativePoint::new(l.point.x / r, l.point.y / r, l.unit).into(),
550 (V::RelativeScalar(l), V::Double(r)) => RelativeScalar::new(l.scalar / r, l.unit).into(),
551 (V::RelativePoint(l), V::RelativePoint(r)) if l.unit == r.unit => {
552 RelativePoint::new(l.point.x / r.point.x, l.point.y / r.point.y, l.unit).into()
553 }
554 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
555 RelativeScalar::new(l.scalar / r.scalar, l.unit).into()
556 }
557 _ => V::Invalid,
558 }
559 }
560}
561
562impl Not for ExpressionVariant {
563 type Output = ExpressionVariant;
564
565 fn not(self) -> ExpressionVariant {
566 match self {
567 V::Boolean(v) => (!v).into(),
568 _ => V::Invalid,
569 }
570 }
571}
572
573impl Rem for ExpressionVariant {
574 type Output = ExpressionVariant;
575
576 fn rem(self, right: ExpressionVariant) -> ExpressionVariant {
577 match (self, right) {
578 (V::Double(l), V::Double(r)) => (l % r).into(),
579 (V::RelativeScalar(l), V::RelativeScalar(r)) if l.unit == r.unit => {
580 RelativeScalar::new(l.scalar % r.scalar, l.unit).into()
581 }
582 _ => V::Invalid,
583 }
584 }
585}
586
587impl fmt::Display for ExpressionVariant {
588 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
589 match self {
590 V::Boolean(v) => f.write_str(if *v { "True" } else { "False" }),
591 V::Double(v) => write!(f, "{}", InvariantF64(*v)),
592 V::Vector2(v) => v.fmt(f),
593 V::Vector(v) => v.fmt(f),
594 V::Vector3(v) => v.fmt(f),
595 V::Vector3D(v) => v.fmt(f),
596 V::Vector4(v) => v.fmt(f),
597 V::Quaternion(v) => v.fmt(f),
598 V::Matrix3x2(v) => v.fmt(f),
599 V::FerroMatrix(v) => v.fmt(f),
600 V::Matrix4x4(v) => v.fmt(f),
601 V::Color(v) => v.fmt(f),
602 V::RelativePoint(v) => v.fmt(f),
603 V::RelativeScalar(v) => v.fmt(f),
604 V::RelativeUnit(v) => fmt::Debug::fmt(v, f),
605 V::Invalid => f.write_str("Invalid"),
606 }
607 }
608}