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