runtime_units/
mutivalue_macros.rs

1#[macro_export]
2macro_rules! impl_quantity_vec_ops {
3    ($quantity:ident) =>
4    {
5        paste::paste!
6        {
7        use core::ops::{Mul, Div, Add, Sub, AddAssign, SubAssign, MulAssign, DivAssign };
8        impl Div<f64> for [<$quantity Vec>]
9        {
10            type Output = [<$quantity Vec>];
11
12            fn div(self, rhs: f64) -> Self::Output {
13                let mut result = self.clone();
14                for val in result.values.as_mut_slice()
15                {
16                *val /= rhs;
17                }
18                result
19            }
20        }
21
22
23        impl Mul<f64> for [<$quantity Vec>]
24        {
25            type Output = [<$quantity Vec>];
26
27            fn mul(self, rhs: f64) -> Self::Output {
28                let mut result = self.clone();
29                for val in result.values.as_mut_slice()
30                {
31                *val *= rhs;
32                }
33                result
34            }
35        }
36        impl DivAssign<f64> for [<$quantity Vec>]
37        {
38
39            fn div_assign(&mut self, rhs: f64) {
40                for val in self.values.as_mut_slice()
41                {
42                *val /= rhs;
43                }
44            }
45        }
46        impl MulAssign<f64> for [<$quantity Vec>]
47        {
48
49            fn mul_assign(&mut self, rhs: f64) {
50                for val in self.values.as_mut_slice()
51                {
52                *val *= rhs;
53                }
54            }
55        }
56        use $crate::traits::Unit;
57        impl AddAssign<[<$quantity Vec>]> for [<$quantity Vec>]
58        {
59
60            fn add_assign(&mut self, rhs: [<$quantity Vec>]) {
61                if rhs.values.len() != self.values.len()
62                {
63                    panic!("Slice dimensions do not match: {} != {}", rhs.values.len(), self.values.len());
64                }
65                let factor = rhs.unit.definition().convert_unchecked(self.unit.definition());
66                for (val, &rhs) in self.values.as_mut_slice().iter_mut().zip(rhs.values.as_slice())
67                {
68                *val += rhs*factor;
69                }
70            }
71        }
72        impl SubAssign<[<$quantity Vec>]> for [<$quantity Vec>]
73        {
74
75            fn sub_assign(&mut self, rhs: [<$quantity Vec>]) {
76                if rhs.values.len() != self.values.len()
77                {
78                    panic!("Slice dimensions do not match: {} != {}", rhs.values.len(), self.values.len());
79                }
80                let factor = rhs.unit.convert_unchecked(self.unit);
81                for (val, &rhs) in self.values.as_mut_slice().iter_mut().zip(rhs.values.as_slice())
82                {
83                *val -= rhs*factor;
84                }
85            }
86        }
87        impl Add<[<$quantity Vec>]> for [<$quantity Vec>]
88        {
89            type Output=Self;
90
91            fn add(self, rhs: [<$quantity Vec>]) -> Self {
92                let mut result = self.clone();
93                result += rhs;
94                result
95            }
96        }
97        impl Sub<[<$quantity Vec>]> for [<$quantity Vec>]
98        {
99            type Output=Self;
100            fn sub(self, rhs: [<$quantity Vec>]) -> Self {
101                let mut result = self;
102                result -= rhs;
103                result
104            }
105        } 
106    }
107    }
108}
109
110#[macro_export]
111macro_rules! impl_quantity_array_ops {
112    ($quantity:ident) =>
113    {
114        paste::paste!
115        {
116        impl<const N: usize> Div<f64> for [<$quantity Array>]<N>
117        {
118            type Output = [<$quantity Array>]<N>;
119
120            fn div(self, rhs: f64) -> Self::Output {
121                let mut result = self.clone();
122                for val in result.values.as_mut_slice()
123                {
124                *val /= rhs;
125                }
126                result
127            }
128        }
129
130
131        impl<const N: usize> Mul<f64> for [<$quantity Array>]<N>
132        {
133            type Output = [<$quantity Array>]<N>;
134
135            fn mul(self, rhs: f64) -> Self::Output {
136                let mut result = self.clone();
137                for val in result.values.as_mut_slice()
138                {
139                *val *= rhs;
140                }
141                result
142            }
143        }
144        impl<const N: usize> DivAssign<f64> for [<$quantity Array>]<N>
145        {
146
147            fn div_assign(&mut self, rhs: f64) {
148                for val in self.values.as_mut_slice()
149                {
150                *val /= rhs;
151                }
152            }
153        }
154        impl<const N: usize> Add<[<$quantity Array>]<N>> for [<$quantity Array>]<N>
155        {
156            type Output=Self;
157
158            fn add(self, rhs: [<$quantity Array>]<N>) -> Self {
159                let mut result = self;
160                result += rhs;
161                result
162            }
163        }
164        impl<const N: usize> Sub<[<$quantity Array>]<N>> for [<$quantity Array>]<N>
165        {
166            type Output=Self;
167            fn sub(self, rhs: [<$quantity Array>]<N>) -> Self {
168                let mut result = self;
169                result -= rhs;
170                result
171            }
172        }     
173        impl<const N: usize> MulAssign<f64> for [<$quantity Array>]<N>
174        {
175
176            fn mul_assign(&mut self, rhs: f64) {
177                for val in self.values.as_mut_slice()
178                {
179                *val *= rhs;
180                }
181            }
182        }
183        impl<const N: usize> AddAssign<[<$quantity Array>]<N>> for [<$quantity Array>]<N>
184        {
185
186            fn add_assign(&mut self, rhs: [<$quantity Array>]<N>) {
187                if rhs.values.len() != self.values.len()
188                {
189                    panic!("Slice dimensions do not match: {} != {}", rhs.values.len(), self.values.len());
190                }
191                let factor = rhs.unit.definition().convert_unchecked(self.unit.definition());
192                for (val, &rhs) in self.values.as_mut_slice().iter_mut().zip(rhs.values.as_slice())
193                {
194                *val += rhs*factor;
195                }
196            }
197        }
198        impl<const N: usize> SubAssign<[<$quantity Array>]<N>> for [<$quantity Array>]<N>
199        {
200
201            fn sub_assign(&mut self, rhs: [<$quantity Array>]<N>) {
202                if rhs.values.len() != self.values.len()
203                {
204                    panic!("Slice dimensions do not match: {} != {}", rhs.values.len(), self.values.len());
205                }
206                let factor = rhs.unit.convert_unchecked(self.unit);
207                for (val, &rhs) in self.values.as_mut_slice().iter_mut().zip(rhs.values.as_slice())
208                {
209                *val -= rhs*factor;
210                }
211            }
212        }
213    }
214    }
215}
216
217#[macro_export]
218macro_rules! create_multivalue_quantities {
219    ($quantity:ident) =>
220    {       
221        #[cfg(feature="serde")]
222        use serde_with::serde_as;      
223        use std::ops::{Deref, DerefMut};  
224        paste::paste!
225        {
226        #[cfg_attr(feature="serde", cfg_eval::cfg_eval, serde_as)]
227        #[derive(Copy, Clone, Debug, PartialEq)]
228        #[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
229        #[cfg_attr(feature="utoipa", derive(ToSchema))]
230        #[doc = "Array storage for a series of values and [`" [<$quantity Unit>]"`]."]
231        pub struct [<$quantity Array>]<const N: usize>
232        {
233            pub(crate) unit: [<$quantity Unit>],
234            #[cfg_attr(feature="serde", serde_as(as = "[_; N]"))]
235            pub(crate) values: [f64; N],
236        }
237
238        impl<const N: usize> Default for [<$quantity Array>]<N>
239        {
240            fn default() -> Self {
241                [<$quantity Array>]{unit: [<$quantity Unit>]::default(), values: [0.0; N]}
242            }
243        }
244
245        impl<const N: usize> Deref for [<$quantity Array>]<N>
246        {
247            type Target = [f64; N];
248            fn deref(&self) -> &[f64; N] {
249                &self.values
250            }        
251        }
252
253        impl<const N: usize> DerefMut for  [<$quantity Array>]<N>
254        {
255            fn deref_mut(&mut self) -> &mut [f64; N] {
256                &mut self.values
257            }
258        } 
259
260        #[derive(Default, Clone, Debug, PartialEq)]
261        #[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
262        #[cfg_attr(feature="utoipa", derive(ToSchema))]
263        #[doc = "Vector storage for a series of values and [`" [<$quantity Unit>]"`]."]
264        pub struct [<$quantity Vec>]
265        {
266            pub(crate) unit: [<$quantity Unit>],
267            pub(crate) values: Vec<f64>
268        }
269
270        impl Deref for [<$quantity Vec>]
271        {
272            type Target = Vec<f64>;
273            fn deref(&self) -> &Vec<f64> {
274                &self.values
275            }        
276        }
277        impl DerefMut for [<$quantity Vec>]
278        {
279            fn deref_mut(&mut self) -> &mut Vec<f64> {
280                &mut self.values
281            }
282        }
283
284        impl $crate::traits::FixedSliceQuantity<[<$quantity Unit>], f64> for [<$quantity Vec>]
285        {
286            fn unit(&self) -> [<$quantity Unit>] {
287                self.unit
288            }
289
290            fn values(&self) -> &[f64] {
291                &self.values.as_slice()
292            }
293
294            fn values_mut(&mut self) -> &mut [f64] {
295                self.values.as_mut_slice()
296            }
297
298            fn len(&self) -> usize {
299                self.values.len()
300            }
301
302            fn convert(&self, unit: [<$quantity Unit>]) -> Self
303            {
304                let mut result = self.clone();
305                result.convert_mut(unit);
306                return result;
307            }
308
309            #[inline]
310            fn convert_mut(&mut self, unit: [<$quantity Unit>]) {
311                let factor = self.unit.definition().convert_unchecked(unit.definition());
312                for val in self.values.as_mut_slice().iter_mut()
313                {
314                    *val *= factor;
315                }
316                self.unit = unit;
317            }
318
319            #[inline]
320            fn try_convert(&self, unit: $crate::Units) -> Result<Self, RuntimeUnitError> where Self: Sized
321            {
322                let destination_unit: [<$quantity Unit>] = unit.try_into()?;
323                Ok(self.convert(destination_unit))
324            }
325        }
326        impl<const N: usize>  $crate::traits::FixedSliceQuantity<[<$quantity Unit>], f64> for [<$quantity Array>]<N>
327        {
328            fn unit(&self) -> [<$quantity Unit>] {
329                self.unit
330            }
331
332            fn values(&self) -> &[f64] {
333                &self.values.as_slice()
334            }
335
336            fn values_mut(&mut self) -> &mut [f64] {
337                self.values.as_mut_slice()
338            }
339
340            fn len(&self) -> usize {
341                self.values.len()
342            }
343
344            fn convert(&self, unit: [<$quantity Unit>]) -> Self 
345            {
346                let mut result = self.clone();
347                result.convert_mut(unit);
348                return result;
349            }
350
351            #[inline]
352            fn convert_mut(&mut self, unit: [<$quantity Unit>]) {
353                let factor = self.unit.definition().convert_unchecked(unit.definition());
354                for val in self.values.as_mut_slice().iter_mut()
355                {
356                    *val *= factor;
357                }            
358                self.unit = unit;
359            }
360
361            #[inline]
362            fn try_convert(&self, unit: $crate::Units) -> Result<Self, RuntimeUnitError> where Self: Sized
363            {
364                let destination_unit: [<$quantity Unit>] = unit.try_into()?;                   
365                Ok(self.convert(destination_unit))      
366            }
367        }
368
369        }
370    }
371}
372
373#[macro_export]
374macro_rules! create_multivalue_quantities_vec_enum {
375    ($($quantity:ident),+) =>
376    {
377        paste::paste!{
378            #[derive(Clone, Debug, PartialEq)]
379            #[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
380            #[cfg_attr(feature="utoipa", derive(ToSchema))]
381            ///
382            /// A wrapper to hold all QuantitiesVec supported by this library. It is analogous to `Units``, 
383            /// but when combined with the `serde` feature flag, can serve as a way to serialize a quantity, not just the unit. 
384            /// 
385            pub enum QuantitiesVec
386            {
387                $(
388                    #[cfg(any(feature = "" $quantity, feature="All"))]   
389                    #[cfg_attr(feature="utoipa", schema(title = "" $quantity))]
390                    $quantity([<$quantity Vec>]),
391                )+
392            }
393            impl QuantitiesVec
394            {                
395                /// Get the `Units` enumeration associated with a given `QuantitiesVec` enumeration.
396                pub fn unit(&self) -> Units
397                {
398                    use $crate::traits::FixedSliceQuantity;
399                    match self
400                    {
401                        $(
402                            #[cfg(any(feature = "" $quantity, feature="All"))]                               
403                            QuantitiesVec::$quantity(x)=> $crate::Units::from(x.unit()),
404                        )+
405                    }
406                }
407                /// Try to convert to the unit specified by a given `Units` enumeration.
408                pub fn try_convert(&self, unit: Units) -> Result<QuantitiesVec, RuntimeUnitError>
409                {   
410                    use $crate::traits::FixedSliceQuantity;
411                    match self
412                    {
413                        $(
414                            #[cfg(any(feature = "" $quantity, feature="All"))]   
415                            QuantitiesVec::$quantity(x)=> {
416                                Ok(QuantitiesVec::$quantity(x.try_convert(unit)?))
417                            },
418                        )+
419                    }
420                }
421
422                /// Create a new quantity from a given value and unit
423                pub fn new(value: Vec<f64>, unit: Units) -> QuantitiesVec
424                {
425                    match unit
426                    {
427                        $(
428                            #[cfg(any(feature = "" $quantity, feature="All"))]   
429                            Units::$quantity(x)=> {                                
430                                QuantitiesVec::$quantity([<$quantity Vec>]::new(value, x))
431                            },
432                        )+
433                    }
434                }
435                /// Get the value associated with quantity.
436                pub fn values(&self) -> Vec<f64>
437                {
438                    use $crate::vector_quantity::VecQuantity;
439                    VecQuantity::from(self.clone()).values
440                }
441            }
442            /// A means to create a default quantity with a given set of units.
443            impl From<Units> for QuantitiesVec
444            {
445                
446                fn from(value: Units) -> Self 
447                {    
448                    
449                    match value
450                    {
451                        $(
452                            
453                            #[cfg(any(feature = "" $quantity, feature="All"))]   
454                            Units::$quantity(x)=>
455                            {
456                                QuantitiesVec::new(vec![0.0], x.into())
457                            },
458                        )+
459                    }                
460                    
461                }
462            }
463            impl From<QuantitiesVec> for crate::vector_quantity::VecQuantity
464            {
465                fn from(value: QuantitiesVec) -> Self {
466                    match value
467                    {
468                        $(
469                            #[cfg(any(feature = "" $quantity, feature="All"))]   
470                            QuantitiesVec::$quantity(x)=>crate::vector_quantity::VecQuantity { values: x.values, unit: UnitDefinition{multiplier: x.unit.multiplier(), base: *[<$quantity:snake>]::[<$quantity:upper _UNIT_BASE>]} },
471                        )+
472                    }
473                }
474            }
475            impl ToString for QuantitiesVec
476            {
477                fn to_string(&self) -> String 
478                {
479                    match self
480                    {
481                        $(
482                            #[cfg(any(feature = "" $quantity, feature="All"))]   
483                            QuantitiesVec::$quantity(x) => format!("{:?} {}", x.values, x.unit.abbreviation()),
484                        )+
485                    }                        
486                }
487            }
488        }
489    }
490}
491
492#[macro_export]
493macro_rules! create_multivalue_quantities_array_enum {
494    ($($quantity:ident),+) =>
495    {
496        paste::paste!{
497            #[derive(Copy, Clone, Debug, PartialEq)]
498            #[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
499            ///
500            /// A wrapper to hold all QuantitiesArray supported by this library. It is analogous to `Units``, 
501            /// but when combined with the `serde` feature flag, can serve as a way to serialize a quantity, not just the unit. 
502            /// 
503            pub enum QuantitiesArray<const N: usize>
504            {
505                $(
506                    #[cfg(any(feature = "" $quantity, feature="All"))]   
507                    $quantity([<$quantity Array>]<N>),
508                )+
509            }
510            impl<const N: usize> QuantitiesArray<N>
511            {                
512                /// Get the `Units` enumeration associated with a given `QuantitiesArray` enumeration.
513                pub fn unit(&self) -> Units
514                {
515                    match self
516                    {
517                        $(
518                            #[cfg(any(feature = "" $quantity, feature="All"))]                               
519                            QuantitiesArray::$quantity(x)=> $crate::Units::from(x.unit),
520                        )+
521                    }
522                }
523                /// Try to convert to the unit specified by a given `Units` enumeration.
524                pub fn try_convert(&self, unit: Units) -> Result<QuantitiesArray<N>, RuntimeUnitError>
525                {   
526                    use $crate::traits::FixedSliceQuantity;
527                    match self
528                    {
529                        $(
530                            #[cfg(any(feature = "" $quantity, feature="All"))]   
531                            QuantitiesArray::$quantity(x)=> {
532                                Ok(QuantitiesArray::$quantity(x.try_convert(unit)?))
533                            },
534                        )+
535                    }
536                }
537
538                /// Create a new quantity from a given value and unit
539                pub fn new(value: [f64; N], unit: Units) -> QuantitiesArray<N>
540                {
541                    match unit
542                    {
543                        $(
544                            #[cfg(any(feature = "" $quantity, feature="All"))]   
545                            Units::$quantity(x)=> {                                
546                                QuantitiesArray::$quantity([<$quantity Array>]{values: value, unit:x})
547                            },
548                        )+
549                    }
550                }
551                /// Get the value associated with quantity.
552                pub fn values(&self) -> [f64; N]
553                {
554                    use $crate::array_quantity::ArrayQuantity;
555                    ArrayQuantity::from(*self).values
556                }
557            }
558            /// A means to create a default quantity with a given set of units.
559            impl<const N: usize> From<Units> for QuantitiesArray<N>
560            {
561                fn from(value: Units) -> Self 
562                {    
563                    match value
564                    {
565                        $(
566                            #[cfg(any(feature = "" $quantity, feature="All"))]   
567                            Units::$quantity(x)=> QuantitiesArray::new([0.0; N], x.into()),
568                        )+
569                    }                
570                    
571                }
572            }
573            impl<const N: usize> From<QuantitiesArray<N>> for $crate::array_quantity::ArrayQuantity<N>
574            {
575                fn from(value: QuantitiesArray<N>) -> Self {
576                    use crate::array_quantity::ArrayQuantity;
577                    match value
578                    {
579                        $(
580                            #[cfg(any(feature = "" $quantity, feature="All"))]   
581                            QuantitiesArray::$quantity(x)=>ArrayQuantity { values: x.values, unit: UnitDefinition{multiplier: x.unit.multiplier(), base: *[<$quantity:snake>]::[<$quantity:upper _UNIT_BASE>]} },
582                        )+
583                    }
584                }
585            }
586            impl<const N: usize> ToString for QuantitiesArray<N>
587            {
588                fn to_string(&self) -> String 
589                {
590                    match self
591                    {
592                        $(
593                            #[cfg(any(feature = "" $quantity, feature="All"))]   
594                            QuantitiesArray::$quantity(x) => format!("{:?} {}", x.values, x.unit.abbreviation()),
595                        )+
596                    }                        
597                }
598            }
599        }
600    }
601}