runtime_units/
traits.rs

1use crate::{errors::RuntimeUnitError, units_base::{UnitBase, UnitDefinition}, Units};
2use core::ops::{Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign };
3
4
5pub(crate) trait IsScalarQuantity
6{
7    fn value(&self) -> f64;
8    fn unit(&self) -> UnitDefinition;
9}
10
11///
12/// Trait that implements conversion of an arbitrary quantity into another
13/// 
14pub trait ArbitraryQuantity where Self: Sized + Div<f64> + Mul<f64> + DivAssign<f64> + MulAssign<f64> + Div<Self> + Mul<Self> + AddAssign<Self> + SubAssign<Self> + DivAssign<Self>
15{
16    /// Return unit associated with this quantity
17    fn unit(&self) -> UnitDefinition;
18    /// Return unit associated with this quantity (mutable)
19    fn unit_mut(&mut self) -> &mut UnitDefinition;
20    /// Try to convert from this unit to another (creates a copy)
21    fn try_convert(&self, unit: UnitDefinition) -> Result<Self, RuntimeUnitError>;    
22    #[inline]
23    /// Try to convert from this unit to the given `unit` (creates a copy)
24    fn try_convert_unit(&self, unit: Units) -> Result<Self, RuntimeUnitError>
25    {
26        self.try_convert(unit.into())
27    }
28    /// Try to convert from this unit to another (modifies current quantity)
29    fn try_convert_mut(&mut self, unit: UnitDefinition) -> Result<(), RuntimeUnitError>;    
30    /// Convert from this unit to another (creates a copy). No validation of base unit is made.
31    fn convert(&self, unit: UnitDefinition) -> Self;
32    /// Convert from this unit to another (modifies current quantity). No validation of base unit is made.
33    fn convert_mut(&mut self, unit: UnitDefinition);
34}
35
36///
37/// Trait that implements conversion of a quantity within a given unit type (e.g. m->cm, kg->g)
38/// 
39pub trait FixedQuantity<UnitType: Unit> where Self: Sized + Div<f64> + Mul<f64> + DivAssign<f64> + MulAssign<f64> + AddAssign<Self> + SubAssign<Self> 
40{
41    /// Return unit associated with this quantity
42    fn unit(&self) -> UnitType;    
43    /// Return mutable unit associated with this quantity
44    fn unit_mut(&mut self) -> &mut UnitType;    
45    /// Convert from this unit to another (creates a copy). No validation of base unit is made.
46    fn convert(&self, unit: UnitType) -> Self;
47    /// Convert from this unit to another (modifies current quantity). No validation of base unit is made.
48    fn convert_mut(&mut self, unit: UnitType);
49    /// Try to convert from this unit to another (creates a copy)
50    fn try_convert(&self, unit: crate::Units) -> Result<Self, RuntimeUnitError> where Self: Sized;
51}
52
53///
54/// Trait that implements conversion of a slice quantity within a given unit type (e.g. m->cm, kg->g)
55/// 
56pub trait FixedSliceQuantity<UnitType: Unit, Element>
57{
58    /// Return unit associated with this quantity
59    fn unit(&self) -> UnitType;
60    /// Return values in quantity
61    fn values(&self) -> &[Element];
62    /// Return mutable values in quantity
63    fn values_mut(&mut self) -> &mut [Element];
64    /// Return number of values in quantity
65    fn len(&self) -> usize;
66    /// Convert a unit of one `UnitType` to another of the same type. No validation of base unit is made.
67    fn convert(&self, unit: UnitType) -> Self;
68    /// Mutate current quantity, convering  a unit of one `UnitType` to another of the same type. No validation of base unit is made.
69    fn convert_mut(&mut self, unit: UnitType);
70    /// Attempt to convert the unit given in `unit` to a `UnitType`. Base unit validation is made here.
71    fn try_convert(&self, unit: Units) -> Result<Self, RuntimeUnitError> where Self: Sized;
72}
73
74
75///
76/// Trait to define a type of unit (e.g. `LengthUnit`,`MassUnit`)
77/// 
78pub trait Unit where Self:Sized
79{
80    /// Return unit definition for this Unit Type
81    fn definition(&self) -> UnitDefinition;
82
83    /// Try to compute conversion factor from this unit to another.
84    #[inline]
85    fn try_convert(&self, unit: UnitDefinition) -> Result<f64, RuntimeUnitError>
86    {
87        let definition = self.definition();
88        if definition.is_convertible(unit)
89        {
90            Ok(unit.multiplier() / definition.multiplier())
91        }
92        else
93        {
94            Err(RuntimeUnitError::IncompatibleUnitConversion(format!("Could not convert from base units of {} to {}", definition.unit_string(), unit.unit_string())))
95        }
96    }
97    /// Compute conversion factor from this unit to another (no check of unit compatibility is made).
98    #[inline]
99    fn convert_unchecked(&self, unit: Self) -> f64
100    {
101        let definition = self.definition();
102        definition.multiplier() / unit.definition().multiplier()
103    }
104}