syunit/
macros.rs

1// ##########################
2// #    Operation macros    #
3// ##########################
4    /// Automatically implements multiplication between three units
5    /// 
6    /// ### Macro buildup
7    /// 
8    /// ```rust, ignore
9    /// ( $input:ident, $by:ident, $output:ident ) 
10    /// ```
11    /// 
12    /// Takes three unit types and implements
13    /// 
14    /// ```rust, ignore
15    /// input * by = output
16    /// ```
17    /// 
18    /// Optionally a conversion (a [f32] literal) can be added: 
19    /// 
20    /// ```rust, ignore
21    /// ( $input:ident, $by:ident, $output:ident, $conv:literal ) 
22    /// ```
23    /// 
24    /// resulting in:
25    /// 
26    /// ```rust, ignore
27    /// input * by * conv = output
28    /// ```
29    #[macro_export]
30    macro_rules! impl_mul {
31        ( $input:ident, $by:ident, $output:ident ) => {
32            impl core::ops::Mul<$by> for $input {
33                type Output = $output;
34
35                #[inline]
36                fn mul(self, rhs : $by) -> $output {
37                    $output(self.0 * rhs.0)
38                }
39            }
40        };
41        ( $input:ident, $by:ident, $output:ident, $conv:literal ) => {
42            impl core::ops::Mul<$by> for $input {
43                type Output = $output;
44
45                #[inline]
46                fn mul(self, rhs : $by) -> $output {
47                    $output(self.0 * rhs.0 * $conv)
48                }
49            }
50        };
51    }
52
53    /// Identical to [impl_mul!], however it implements the division in both directions, so
54    /// 
55    /// ```rust, ignore
56    /// input * by = output
57    /// ```
58    /// 
59    /// and 
60    /// 
61    /// ```rust, ignore
62    /// by * input = output
63    /// ```
64    #[macro_export]
65    macro_rules! impl_mul_bidir {
66        ( $input:ident, $by:ident, $output:ident ) => {
67            syunit::impl_mul!( $input, $by, $output );
68            syunit::impl_mul!( $by, $input, $output );
69        }; 
70        ( $input:ident, $by:ident, $output:ident, $conv:literal ) => {
71            syunit::impl_mul!( $input, $by, $output, $conv );
72            syunit::impl_mul!( $by, $input, $output, $conv );
73        };
74    }
75
76    /// Automatically implements division between three units
77    /// 
78    /// ### Macro buildup
79    /// 
80    /// ```rust, ignore
81    /// ( $input:ident, $by:ident, $output:ident ) 
82    /// ```
83    /// 
84    /// Takes three unit types and implements
85    /// 
86    /// ```rust, ignore
87    /// input / by = output
88    /// ```
89    /// 
90    /// Optionally a conversion (a [f32] literal) can be added: 
91    /// 
92    /// ```rust, ignore
93    /// ( $input:ident, $by:ident, $output:ident, $conv:literal ) 
94    /// ```
95    /// 
96    /// resulting in:
97    /// 
98    /// ```rust, ignore
99    /// input / by / conv = output
100    /// ```
101    #[macro_export]
102    macro_rules! impl_div {
103        ( $input:ident, $by:ident, $output:ident ) => {
104            impl core::ops::Div<$by> for $input {
105                type Output = $output;
106
107                #[inline]
108                fn div(self, rhs : $by) -> $output {
109                    $output(self.0 / rhs.0)
110                }
111            }
112        };
113        ( $input:ident, $by:ident, $output:ident, $conv:literal ) => {
114            impl core::ops::Div<$by> for $input {
115                type Output = $output;
116
117                #[inline]
118                fn div(self, rhs : $by) -> $output {
119                    $output(self.0 / rhs.0 / $conv)
120                }
121            }
122        };
123    }
124
125    /// Identical to [impl_div!], however it implements the division in both directions, so
126    /// 
127    /// ```rust, ignore
128    /// input / by = output
129    /// ```
130    /// 
131    /// and 
132    /// 
133    /// ```rust, ignore
134    /// input / output = by
135    /// ```
136    #[macro_export]
137    macro_rules! impl_div_bidir {
138        ( $input:ident, $by:ident, $output:ident ) => {
139            syunit::impl_div!( $input, $by, $output );
140            syunit::impl_div!( $input, $output, $by );
141        }; 
142        ( $input:ident, $by:ident, $output:ident, $conv:literal ) => {
143            syunit::impl_div!( $input, $by, $output, $conv );
144            syunit::impl_div!( $input, $output, $by, $conv );
145        };
146    }
147//
148
149// ####################
150// #    Conversion    #
151// ####################
152    // TODO: Improve documentation
153    /// Implements conversion between two units
154    /// 
155    /// ### Syntax
156    /// 
157    /// `( input, output, conv )`
158    /// 
159    /// - `input`: The input unit
160    /// - `output`: The output unit
161    /// - `conv`: The conversion factor, can be an expression (=> `output = input * conv`)
162    #[macro_export]
163    macro_rules! impl_conversion {
164        ( $input:ident, $output:ident ) => {
165            impl From<$input> for $output {
166                #[inline(always)]
167                fn from(value : $input) -> Self {
168                    Self(value.0)
169                }
170            }
171
172            impl From<$output> for $input {
173                #[inline(always)]
174                fn from(value : $output) -> Self {
175                    Self(value.0)
176                }
177            }
178        };
179        ( $input:ident, $output:ident, $conv:literal ) => {
180            impl From<$input> for $output {
181                #[inline(always)]
182                fn from(value : $input) -> Self {
183                    Self(value.0 * ($conv))
184                }
185            }
186
187            impl From<$output> for $input {
188                #[inline(always)]
189                fn from(value : $output) -> Self {
190                    Self(value.0 / ($conv))
191                }
192            }
193        };
194    }
195
196    /// Implements everything required to form a "derive over time like"-connection between the given units
197    #[macro_export]
198    macro_rules! impl_full_conversion {
199        ( $input:ident, $by:ident, $output:ident ) => {
200            syunit::impl_mul_bidir!( $input, $by, $output );
201            syunit::impl_div_bidir!( $output, $by, $input );
202        };
203        ( $input:ident, $by:ident, $output:ident, $conv:literal ) => {
204            syunit::impl_mul_bidir!( $input, $by, $output, $conv );
205            syunit::impl_div_bidir!( $output, $by, $input, $conv );
206        };
207    }
208//
209
210// ####################
211// #    Basic unit    #
212// ####################
213    /// Implements the basics for a unit
214    #[macro_export]
215    macro_rules! basic_unit_helper {
216        ( $a:ident ) => {      
217            // Display traits
218                impl core::str::FromStr for $a {
219                    type Err = <f32 as core::str::FromStr>::Err;
220                
221                    fn from_str(s: &str) -> Result<Self, Self::Err> {
222                        Ok(Self(s.parse::<f32>()?))
223                    }
224                }
225
226                impl core::fmt::Debug for $a {
227                    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
228                        f.write_fmt(format_args!("{}({})", stringify!($a), self.0))
229                    }
230                }
231
232                impl core::convert::From<f32> for $a {
233                    #[inline(always)]
234                    fn from(value : f32) -> Self {
235                        Self(value)
236                    }
237                }
238
239                impl core::convert::Into<f32> for $a {
240                    #[inline(always)]
241                    fn into(self) -> f32 {
242                        self.0
243                    }
244                }
245            //
246
247            // Negation
248                impl core::ops::Neg for $a {
249                    type Output = Self;
250                    
251                    #[inline(always)]
252                    fn neg(self) -> Self::Output {
253                        Self(-self.0)
254                    }
255                }
256            //
257
258            // Multiplication
259                impl core::ops::Mul<f32> for $a {
260                    type Output = $a;
261                    
262                    #[inline(always)]
263                    fn mul(self, rhs: f32) -> Self::Output {
264                        $a(self.0 * rhs)
265                    }
266                }
267
268                impl core::ops::Mul<$a> for f32 {
269                    type Output = $a;
270
271                    #[inline(always)]
272                    fn mul(self, rhs : $a) -> Self::Output {
273                        $a(self * rhs.0)
274                    }
275                }
276            // 
277            
278            // Division
279                impl core::ops::Div<f32> for $a {
280                    type Output = $a;
281                
282                    #[inline(always)]
283                    fn div(self, rhs: f32) -> Self::Output {
284                        $a(self.0 / rhs)
285                    }
286                }
287
288                impl core::ops::Div<$a> for $a {
289                    type Output = f32;
290
291                    #[inline(always)]
292                    fn div(self, rhs : $a) -> Self::Output {
293                        self.0 / rhs.0
294                    }
295                }
296            // 
297
298            // Factor
299                impl core::ops::Mul<syunit::Factor> for $a {
300                    type Output = $a;
301
302                    #[inline]
303                    fn mul(self, rhs : syunit::Factor) -> Self::Output {
304                        Self(self.0 * rhs.as_f32())
305                    }
306                }
307            //  
308
309            impl syunit::Unit for $a { 
310                /// Zero value of this unit (0.0)
311                const ZERO : Self = Self(0.0);
312                /// Positive Infinity value of this unit (f32::INFINITY)
313                const INFINITY : Self = Self(f32::INFINITY);
314                /// Negative Infinity value of this unit (f32::INFINITY)
315                const NEG_INFINITY : Self = Self(f32::NEG_INFINITY);
316                /// NaN value of this unit (f32::NAN)
317                const NAN : Self = Self(f32::NAN);
318            }
319        };
320    }
321
322    /// Implements the basics for a unit
323    #[macro_export]
324    macro_rules! basic_unit {
325        ( $name:ident ) => {
326            syunit::basic_unit_helper!( $name );
327
328            impl core::fmt::Display for $name {
329                fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
330                    <f32 as core::fmt::Display>::fmt(&self.0, f)
331                }
332            }
333        };
334        ( $name:ident, $sym:literal ) => {
335            syunit::basic_unit_helper!( $name );
336
337            impl core::fmt::Display for $name {
338                fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
339                    f.write_fmt(format_args!("{}{}", self.0, $sym))
340                }
341            }
342        }
343    }
344//
345
346/// Helper macro that implements everything needed to do +,-,+=,-= operations with the unit itself
347#[macro_export]
348macro_rules! additive_unit {
349    ( $unit:ident ) => {
350        impl core::ops::Add<$unit> for $unit {
351            type Output = $unit;
352        
353            #[inline(always)]
354            fn add(self, rhs: $unit) -> Self::Output {
355                $unit(self.0 + rhs.0)
356            }
357        }
358
359        impl core::ops::AddAssign<$unit> for $unit {
360            #[inline(always)]
361            fn add_assign(&mut self, rhs: $unit) {
362                self.0 += rhs.0;
363            }
364        }        
365        
366        impl core::ops::Sub<$unit> for $unit {
367            type Output = $unit;
368        
369            #[inline(always)]
370            fn sub(self, rhs: $unit) -> Self::Output {
371                $unit(self.0 - rhs.0) 
372            }
373        }
374
375        impl core::ops::SubAssign<$unit> for $unit {
376            #[inline]
377            fn sub_assign(&mut self, rhs : $unit) {
378                self.0 -= rhs.0
379            }
380        }
381
382        impl syunit::AdditiveUnit for $unit { }
383    };
384}
385
386/// Helper macro for position units
387#[macro_export]
388macro_rules! position_unit {
389    ( $pos:ident, $unit:ident ) => {
390        impl core::ops::Add<$unit> for $pos {
391            type Output = $pos;
392
393            fn add(self, rhs: $unit) -> Self::Output {
394                Self(self.0 + rhs.0)
395            }
396        }
397
398        impl core::ops::AddAssign<$unit> for $pos {
399            fn add_assign(&mut self, other : $unit) {
400                self.0.add_assign(other.0);
401            }
402        }
403
404        impl core::ops::Sub<$unit> for $pos {
405            type Output = $pos;
406
407            fn sub(self, rhs: $unit) -> Self::Output {
408                Self(self.0 - rhs.0)
409            }
410        }
411
412        impl core::ops::SubAssign<$unit> for $pos {
413            fn sub_assign(&mut self, other : $unit) {
414                self.0.sub_assign(other.0);
415            }
416        }
417
418        impl core::ops::Sub<$pos> for $pos {
419            type Output = $unit; 
420
421            fn sub(self, rhs: $pos) -> Self::Output {
422                $unit(self.0 - rhs.0)
423            }
424        }
425
426        syunit::impl_conversion!($pos, $unit);
427    };
428}
429
430// TODO: Improve documentation to cover matching arms
431/// Implements everything required to form a "derive over time like"-connection between the given units
432#[macro_export]
433macro_rules! derive_units {
434    ( $dist:ident, $vel:ident, $time:ident ) => {
435
436        syunit::impl_full_conversion!( $vel, $time, $dist );
437
438        impl syunit::DerivableUnit<$time> for $dist { 
439            type Result = $vel;
440        }
441
442        impl syunit::IntegrableUnit<$time> for $vel { 
443            type Result = $dist;
444        }
445    };
446}
447
448/// Automatically implement [InertiaUnit](crate::InertiaUnit) for the given unit
449/// 
450#[macro_export]
451macro_rules! inertia_unit {
452    ( $name:ident, $length:ident, $reduced:ident ) => {
453        impl syunit::InertiaUnit<$length> for $name {
454            type Reduced = $reduced;
455        }
456    };
457    ( $name:ident, $length:ident, $reduced:ident, $conv:literal ) => {
458        impl syunit::InertiaUnit<$length> for $name {
459            type Reduced = $reduced;
460
461            fn reduce(self, ratio : $length) -> Self::Reduced {
462                Self::Reduced::from(<Self as Into<f32>>::into(self) * <$length as Into<f32>>::into(ratio) * <$length as Into<f32>>::into(ratio) * $conv)
463            }
464
465            fn extend(reduced : Self::Reduced, ratio : $length) -> Self {
466                Self::from(<$reduced as Into<f32>>::into(reduced) / <$length as Into<f32>>::into(ratio) / <$length as Into<f32>>::into(ratio) / $conv)
467            }
468        }
469    };
470}