unitforge/
impl_macros.rs

1#[macro_export]
2macro_rules! impl_quantity {
3    ($type:ident, $unit:ty, $display_unit:expr) => {
4        use $crate::small_linalg::{Matrix3, Vector3};
5
6        #[derive(Copy, Clone)]
7        pub struct $type {
8            pub(crate) multiplyer: f64,
9            pub(crate) power: i32,
10        }
11
12        impl PhysicsQuantity for $type {
13            type Unit = $unit;
14
15            fn new(value: f64, unit: Self::Unit) -> Self {
16                if value.is_infinite() {
17                    if value.is_sign_negative() {
18                        return Self::NEG_INFINITY;
19                    } else {
20                        return Self::INFINITY;
21                    }
22                }
23                let (unit_multiplyer, unit_power) = unit.base_per_x();
24                let (multiplyer, power) = Self::split_value(value);
25                Self {
26                    multiplyer: multiplyer * unit_multiplyer,
27                    power: power + unit_power,
28                }
29            }
30
31            fn split_value(v: f64) -> (f64, i32) {
32                if v.is_zero() {
33                    (0.0, 0)
34                } else {
35                    let power = v.abs().log10().floor() as i32;
36                    let multiplier = v / 10f64.powi(power);
37                    (multiplier, power)
38                }
39            }
40
41            fn zero() -> Self {
42                Self {
43                    multiplyer: 0.,
44                    power: 0,
45                }
46            }
47
48            fn get_value(&self) -> f64 {
49                self.multiplyer * 10_f64.powi(self.power)
50            }
51
52            fn get_power(&self) -> i32 {
53                self.power
54            }
55
56            fn get_multiplyer(&self) -> f64 {
57                self.multiplyer
58            }
59
60            fn get_tuple(&self) -> (f64, i32) {
61                (self.multiplyer, self.power)
62            }
63
64            fn to(&self, unit: Self::Unit) -> f64 {
65                let (unit_multiplyer, unit_power) = unit.base_per_x();
66                self.multiplyer / unit_multiplyer * 10_f64.powi(self.power - unit_power)
67            }
68
69            fn abs(self) -> Self {
70                Self {
71                    multiplyer: self.multiplyer.abs(),
72                    power: self.power,
73                }
74            }
75
76            fn to_raw(&self) -> f64 {
77                self.get_value()
78            }
79
80            fn from_raw(value: f64) -> Self {
81                if value.is_infinite() {
82                    if value.is_sign_negative() {
83                        return Self::NEG_INFINITY;
84                    } else {
85                        return Self::INFINITY;
86                    }
87                }
88                let (multiplyer, power) = Self::split_value(value);
89                Self { multiplyer, power }
90            }
91
92            fn from_exponential(multiplyer: f64, power: i32) -> Self {
93                Self { multiplyer, power }
94            }
95
96            fn min(self, other: Self) -> Self {
97                if self.get_value() < other.get_value() {
98                    self
99                } else {
100                    other
101                }
102            }
103
104            fn max(self, other: Self) -> Self {
105                if self.get_value() > other.get_value() {
106                    self
107                } else {
108                    other
109                }
110            }
111
112            const INFINITY: Self = Self {
113                multiplyer: f64::INFINITY,
114                power: 0,
115            };
116            const NEG_INFINITY: Self = Self {
117                multiplyer: f64::NEG_INFINITY,
118                power: 0,
119            };
120        }
121
122        impl fmt::Display for $type {
123            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124                let base_unit = $display_unit;
125                let unit_name = if base_unit.name() == "°" {
126                    "°".to_string()
127                } else {
128                    format!(" {}", base_unit.name())
129                };
130                let value = self.to(base_unit);
131                let rounded = if value.is_zero() {
132                    value
133                } else {
134                    let didgits = value.log10().ceil() as i32;
135                    let rounding_multiplyer = 10_f64.powi(3 - didgits);
136                    (value * rounding_multiplyer).round() as f64 / rounding_multiplyer as f64
137                };
138
139                write!(f, "{}{}", rounded, unit_name)
140            }
141        }
142
143        impl Neg for $type {
144            type Output = Self;
145
146            fn neg(self) -> Self::Output {
147                Self {
148                    multiplyer: -self.multiplyer,
149                    power: self.power,
150                }
151            }
152        }
153
154        impl PartialEq<Self> for $type {
155            fn eq(&self, other: &Self) -> bool {
156                self.power == other.power && self.multiplyer == other.multiplyer
157            }
158        }
159
160        impl PartialOrd for $type {
161            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
162                self.get_value().partial_cmp(&other.get_value())
163            }
164        }
165
166        impl FromPrimitive for $type {
167            fn from_i64(n: i64) -> Option<Self> {
168                Some(Self::from_raw(n as f64))
169            }
170
171            fn from_u64(n: u64) -> Option<Self> {
172                Some(Self::from_raw(n as f64))
173            }
174
175            fn from_f64(n: f64) -> Option<Self> {
176                Some(Self::from_raw(n))
177            }
178        }
179
180        impl Add for $type {
181            type Output = Self;
182
183            fn add(self, other: Self) -> Self {
184                let common_power = (self.power + other.power) / 2;
185                let multiplyer = self.multiplyer * 10_f64.powi(self.power - common_power)
186                    + other.multiplyer * 10_f64.powi(other.power - common_power);
187
188                Self {
189                    multiplyer,
190                    power: common_power,
191                }
192            }
193        }
194
195        impl Sub for $type {
196            type Output = Self;
197
198            fn sub(self, other: Self) -> Self {
199                let common_power = (self.power + other.power) / 2;
200                let multiplyer = self.multiplyer * 10_f64.powi(self.power - common_power)
201                    - other.multiplyer * 10_f64.powi(other.power - common_power);
202
203                Self {
204                    multiplyer,
205                    power: common_power,
206                }
207            }
208        }
209
210        impl Div<f64> for $type {
211            type Output = Self;
212
213            fn div(self, rhs: f64) -> Self::Output {
214                let (rhs_multiplyer, rhs_power) = Self::split_value(rhs);
215                Self {
216                    multiplyer: self.multiplyer / rhs_multiplyer,
217                    power: self.power - rhs_power,
218                }
219            }
220        }
221
222        impl Mul<f64> for $type {
223            type Output = Self;
224
225            fn mul(self, rhs: f64) -> Self::Output {
226                let (rhs_multiplyer, rhs_power) = Self::split_value(rhs);
227                Self {
228                    multiplyer: self.multiplyer * rhs_multiplyer,
229                    power: self.power + rhs_power,
230                }
231            }
232        }
233
234        impl Mul<$type> for f64 {
235            type Output = $type;
236
237            fn mul(self, rhs: $type) -> Self::Output {
238                rhs * self
239            }
240        }
241
242        impl AddAssign for $type {
243            fn add_assign(&mut self, other: Self) {
244                let common_power = (self.power + other.power) / 2;
245                self.multiplyer = self.multiplyer * 10_f64.powi(self.power - common_power)
246                    + other.multiplyer * 10_f64.powi(other.power - common_power);
247                self.power = common_power;
248            }
249        }
250
251        impl SubAssign for $type {
252            fn sub_assign(&mut self, other: Self) {
253                let common_power = (self.power + other.power) / 2;
254                self.multiplyer = self.multiplyer * 10_f64.powi(self.power - common_power)
255                    - other.multiplyer * 10_f64.powi(other.power - common_power);
256                self.power = common_power;
257            }
258        }
259
260        impl MulAssign<f64> for $type {
261            fn mul_assign(&mut self, rhs: f64) {
262                let (rhs_multiplyer, rhs_power) = Self::split_value(rhs);
263                self.multiplyer *= rhs_multiplyer;
264                self.power += rhs_power;
265            }
266        }
267
268        impl DivAssign<f64> for $type {
269            fn div_assign(&mut self, rhs: f64) {
270                let (rhs_multiplyer, rhs_power) = Self::split_value(rhs);
271                self.multiplyer /= rhs_multiplyer;
272                self.power -= rhs_power;
273            }
274        }
275
276        impl Mul<Vector3<f64>> for $type {
277            type Output = Vector3<$type>;
278
279            fn mul(self, rhs: Vector3<f64>) -> Self::Output {
280                Vector3::new([self * rhs[0], self * rhs[1], self * rhs[2]])
281            }
282        }
283
284        impl Mul<Matrix3<f64>> for $type {
285            type Output = Matrix3<$type>;
286
287            fn mul(self, rhs: Matrix3<f64>) -> Self::Output {
288                Matrix3::new([
289                    [self * rhs[(0, 0)], self * rhs[(0, 1)], self * rhs[(0, 2)]],
290                    [self * rhs[(1, 0)], self * rhs[(1, 1)], self * rhs[(1, 2)]],
291                    [self * rhs[(2, 0)], self * rhs[(2, 1)], self * rhs[(2, 2)]],
292                ])
293            }
294        }
295
296        impl Zero for $type {
297            fn zero() -> Self {
298                Self {
299                    multiplyer: 0.0,
300                    power: 0,
301                }
302            }
303
304            fn is_zero(&self) -> bool {
305                self.multiplyer == 0.0
306            }
307        }
308
309        impl fmt::Debug for $type {
310            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
311                fmt::Display::fmt(self, f)
312            }
313        }
314
315        impl QuantityArray2<$unit> for Array2<$type> {
316            fn from_raw(raw: ArrayView2<f64>, unit: $unit) -> Self {
317                let mut res = Array2::zeros(raw.dim());
318                for i in 0..raw.dim().0 {
319                    for j in 0..raw.dim().1 {
320                        res[[i, j]] = <$type>::new(raw[[i, j]], unit);
321                    }
322                }
323                res
324            }
325
326            fn to_raw(&self) -> Array2<f64> {
327                let mut res = Array2::zeros(self.dim());
328                for i in 0..self.dim().0 {
329                    for j in 0..self.dim().1 {
330                        res[[i, j]] = self[[i, j]].to_raw();
331                    }
332                }
333                res
334            }
335
336            fn to(&self, unit: $unit) -> Array2<f64> {
337                let mut res = Array2::zeros(self.dim());
338                for i in 0..self.dim().0 {
339                    for j in 0..self.dim().1 {
340                        res[[i, j]] = self[[i, j]].to(unit);
341                    }
342                }
343                res
344            }
345        }
346
347        impl QuantityArray1<$unit> for Array1<$type> {
348            fn from_raw(raw: ArrayView1<f64>, unit: $unit) -> Self {
349                let mut res = Array1::zeros(raw.dim());
350                for i in 0..raw.dim() {
351                    res[i] = <$type>::new(raw[i], unit);
352                }
353                res
354            }
355
356            fn to_raw(&self) -> Array1<f64> {
357                let mut res = Array1::zeros(self.dim());
358                for i in 0..self.dim() {
359                    res[i] = self[i].to_raw();
360                }
361                res
362            }
363
364            fn to(&self, unit: $unit) -> Array1<f64> {
365                let mut res = Array1::zeros(self.dim());
366                for i in 0..self.dim() {
367                    res[i] = self[i].to(unit);
368                }
369                res
370            }
371        }
372    };
373}
374
375#[macro_export]
376macro_rules! impl_const {
377    ($type:ident, $name:ident, $multiplier:expr, $power:expr) => {
378        impl $type {
379            pub fn $name() -> Self {
380                Self {
381                    multiplyer: $multiplier,
382                    power: $power,
383                }
384            }
385        }
386    };
387}
388
389#[macro_export]
390macro_rules! impl_sqrt {
391    ($lhs:ty, $res:ty) => {
392        impl Sqrt<$res> for $lhs {
393            fn sqrt(self) -> $res {
394                if self.power % 2 == 0 {
395                    <$res>::from_exponential(self.multiplyer.sqrt(), self.power / 2)
396                } else {
397                    <$res>::from_exponential(
398                        self.multiplyer.sqrt() * 10_f64.sqrt(),
399                        (self.power - 1) / 2,
400                    )
401                }
402            }
403        }
404    };
405}
406
407#[macro_export]
408macro_rules! impl_div_with_self_to_f64 {
409    ($lhs:ty) => {
410        impl Div<$lhs> for $lhs {
411            type Output = f64;
412
413            fn div(self, rhs: Self) -> Self::Output {
414                (self.multiplyer / rhs.multiplyer) * 10_f64.powi(self.power - rhs.power)
415            }
416        }
417    };
418}
419
420#[macro_export]
421macro_rules! impl_div_with_self {
422    ($lhs:ty, $res:ty, $res_type:ident) => {
423        impl Div<$lhs> for $lhs {
424            type Output = $res;
425
426            fn div(self, rhs: Self) -> Self::Output {
427                $res_type {
428                    multiplyer: self.multiplyer / rhs.multiplyer,
429                    power: self.power - rhs.power,
430                }
431            }
432        }
433    };
434}
435
436#[macro_export]
437macro_rules! impl_mul {
438    ($lhs:ty, $rhs:ty, $result:ty) => {
439        impl std::ops::Mul<$rhs> for $lhs {
440            type Output = $result;
441
442            fn mul(self, rhs: $rhs) -> Self::Output {
443                <$result>::from_exponential(
444                    self.multiplyer * rhs.multiplyer,
445                    self.power + rhs.power,
446                )
447            }
448        }
449
450        impl std::ops::Mul<$lhs> for $rhs {
451            type Output = $result;
452
453            fn mul(self, rhs: $lhs) -> Self::Output {
454                <$result>::from_exponential(
455                    self.multiplyer * rhs.multiplyer,
456                    self.power + rhs.power,
457                )
458            }
459        }
460
461        impl MulArray1<$rhs> for Array1<$lhs> {
462            type Output = Array1<$result>;
463
464            fn mul_array1(self, rhs: Array1<$rhs>) -> Array1<$result> {
465                self.into_iter()
466                    .zip(rhs.into_iter())
467                    .map(|(force, distance)| force * distance)
468                    .collect()
469            }
470        }
471
472        impl MulArray2<$rhs> for Array2<$lhs> {
473            type Output = Array2<$result>;
474
475            fn mul_array2(self, rhs: Array2<$rhs>) -> Result<Array2<$result>, String> {
476                let mut results = Vec::new();
477
478                for (lhs_row, rhs_row) in self.outer_iter().zip(rhs.outer_iter()) {
479                    let result_row: Array1<$result> = lhs_row
480                        .iter()
481                        .zip(rhs_row.iter())
482                        .map(|(&lhs, &rhs)| lhs * rhs)
483                        .collect();
484                    results.push(result_row);
485                }
486
487                let nrows = results.len();
488                let ncols = if nrows > 0 { results[0].len() } else { 0 };
489                let data: Vec<$result> = results
490                    .into_iter()
491                    .flat_map(|r| {
492                        let (raw_vec, _) = r.into_raw_vec_and_offset();
493                        raw_vec
494                    })
495                    .collect();
496
497                Array2::from_shape_vec((nrows, ncols), data)
498                    .map_err(|_| "Shape mismatch".to_string())
499            }
500        }
501
502        impl MulArray1<$lhs> for Array1<$rhs> {
503            type Output = Array1<$result>;
504
505            fn mul_array1(self, rhs: Array1<$lhs>) -> Array1<$result> {
506                self.into_iter()
507                    .zip(rhs.into_iter())
508                    .map(|(force, distance)| force * distance)
509                    .collect()
510            }
511        }
512
513        impl MulArray2<$lhs> for Array2<$rhs> {
514            type Output = Array2<$result>;
515
516            fn mul_array2(self, rhs: Array2<$lhs>) -> Result<Array2<$result>, String> {
517                let mut results = Vec::new();
518
519                for (force_row, distance_row) in self.outer_iter().zip(rhs.outer_iter()) {
520                    let result_row: Array1<$result> = force_row
521                        .iter()
522                        .zip(distance_row.iter())
523                        .map(|(&force, &distance)| force * distance)
524                        .collect();
525                    results.push(result_row);
526                }
527
528                let nrows = results.len();
529                let ncols = if nrows > 0 { results[0].len() } else { 0 };
530                let data: Vec<$result> = results
531                    .into_iter()
532                    .flat_map(|r| {
533                        let (raw_vec, _) = r.into_raw_vec_and_offset();
534                        raw_vec
535                    })
536                    .collect();
537
538                Array2::from_shape_vec((nrows, ncols), data)
539                    .map_err(|_| "Shape mismatch".to_string())
540            }
541        }
542    };
543}
544
545#[macro_export]
546macro_rules! impl_mul_with_self {
547    ($lhs:ty,$result:ty) => {
548        impl std::ops::Mul<$lhs> for $lhs {
549            type Output = $result;
550
551            fn mul(self, rhs: $lhs) -> Self::Output {
552                <$result>::from_exponential(
553                    self.multiplyer * rhs.multiplyer,
554                    self.power + rhs.power,
555                )
556            }
557        }
558
559        impl MulArray1<$lhs> for Array1<$lhs> {
560            type Output = Array1<$result>;
561
562            fn mul_array1(self, rhs: Array1<$lhs>) -> Array1<$result> {
563                self.into_iter()
564                    .zip(rhs.into_iter())
565                    .map(|(force, distance)| force * distance)
566                    .collect()
567            }
568        }
569
570        impl MulArray2<$lhs> for Array2<$lhs> {
571            type Output = Array2<$result>;
572
573            fn mul_array2(self, rhs: Array2<$lhs>) -> Result<Array2<$result>, String> {
574                let mut results = Vec::new();
575
576                for (force_row, distance_row) in self.outer_iter().zip(rhs.outer_iter()) {
577                    let result_row: Array1<$result> = force_row
578                        .iter()
579                        .zip(distance_row.iter())
580                        .map(|(&force, &distance)| force * distance)
581                        .collect();
582                    results.push(result_row);
583                }
584
585                let nrows = results.len();
586                let ncols = if nrows > 0 { results[0].len() } else { 0 };
587                let data: Vec<$result> = results
588                    .into_iter()
589                    .flat_map(|r| {
590                        let (raw_vec, _) = r.into_raw_vec_and_offset();
591                        raw_vec
592                    })
593                    .collect();
594
595                Array2::from_shape_vec((nrows, ncols), data)
596                    .map_err(|_| "Shape mismatch".to_string())
597            }
598        }
599    };
600}
601
602#[macro_export]
603macro_rules! impl_div {
604    ($lhs:ty, $rhs:ty, $result:ty) => {
605        impl std::ops::Div<$rhs> for $lhs {
606            type Output = $result;
607
608            fn div(self, rhs: $rhs) -> Self::Output {
609                <$result>::from_exponential(
610                    self.multiplyer / rhs.multiplyer,
611                    self.power - rhs.power,
612                )
613            }
614        }
615
616        impl DivArray1<$rhs> for Array1<$lhs> {
617            type Output = Array1<$result>;
618
619            fn div_array1(self, rhs: Array1<$rhs>) -> Array1<$result> {
620                self.into_iter()
621                    .zip(rhs.into_iter())
622                    .map(|(force, distance)| force / distance)
623                    .collect()
624            }
625        }
626
627        impl DivArray2<$rhs> for Array2<$lhs> {
628            type Output = Array2<$result>;
629
630            fn div_array2(self, rhs: Array2<$rhs>) -> Result<Array2<$result>, String> {
631                let mut results = Vec::new();
632
633                for (force_row, distance_row) in self.outer_iter().zip(rhs.outer_iter()) {
634                    let result_row: Array1<$result> = force_row
635                        .iter()
636                        .zip(distance_row.iter())
637                        .map(|(&force, &distance)| force / distance)
638                        .collect();
639                    results.push(result_row);
640                }
641
642                let nrows = results.len();
643                let ncols = if nrows > 0 { results[0].len() } else { 0 };
644                let data: Vec<$result> = results
645                    .into_iter()
646                    .flat_map(|r| {
647                        let (raw_vec, _) = r.into_raw_vec_and_offset();
648                        raw_vec
649                    })
650                    .collect();
651
652                Array2::from_shape_vec((nrows, ncols), data)
653                    .map_err(|_| "Shape mismatch".to_string())
654            }
655        }
656    };
657}
658
659pub mod macros {
660    pub use crate::impl_const;
661    pub use crate::impl_div;
662    pub use crate::impl_div_with_self;
663    pub use crate::impl_div_with_self_to_f64;
664    pub use crate::impl_mul;
665    pub use crate::impl_mul_with_self;
666    pub use crate::impl_quantity;
667    pub use crate::impl_sqrt;
668}