Skip to main content

physical_units/
convert.rs

1use crate::{base, derived, identities::BASIC_IDENTITIES};
2
3impl From<base::BaseUnit> for derived::DerivedUnit {
4    fn from(value: base::BaseUnit) -> Self {
5        value.to_derived()
6    }
7}
8
9impl base::BaseUnit {
10    pub const fn to_derived(self) -> derived::DerivedUnit {
11        derived::DerivedUnit {
12            base: self,
13            ..derived::UNITLESS
14        }
15    }
16}
17
18impl From<derived::DerivedUnit> for base::BaseUnit {
19    fn from(value: derived::DerivedUnit) -> Self {
20        value.to_base()
21    }
22}
23
24impl derived::DerivedUnit {
25    pub fn to_base(self) -> base::BaseUnit {
26        let mut output = self.base;
27        let derived_units = [
28            (self.hertz, base::HERTZ),
29            (self.newton, base::NEWTON),
30            (self.pascal, base::PASCAL),
31            (self.joule, base::JOULE),
32            (self.watt, base::WATT),
33            (self.coulomb, base::COULOMB),
34            (self.volt, base::VOLT),
35            (self.farad, base::FARAD),
36            (self.ohm, base::OHM),
37            (self.siemens, base::SIEMENS),
38            (self.weber, base::WEBER),
39            (self.tesla, base::TESLA),
40            (self.henry, base::HENRY),
41            (self.lux, base::LUX),
42            (self.becquerel, base::BECQUEREL),
43            (self.gray, base::GRAY),
44            (self.sievert, base::SIEVERT),
45            (self.katal, base::KATAL),
46        ];
47        for (n, base) in derived_units {
48            if n > 0 {
49                for _ in 0..n {
50                    output = output.multiply(base);
51                }
52            } else {
53                for _ in 0..-n {
54                    output = output.divide(base);
55                }
56            }
57        }
58        output
59    }
60}
61
62impl<Number> From<base::BaseValue<Number>> for derived::DerivedValue<Number> {
63    fn from(value: base::BaseValue<Number>) -> Self {
64        value.to_derived()
65    }
66}
67
68impl<Number> base::BaseValue<Number> {
69    pub fn to_derived(self) -> derived::DerivedValue<Number> {
70        derived::DerivedValue {
71            unit: self.unit.to_derived(),
72            number: self.number,
73        }
74    }
75}
76
77impl<Number> From<derived::DerivedValue<Number>> for base::BaseValue<Number> {
78    fn from(value: derived::DerivedValue<Number>) -> Self {
79        value.to_base()
80    }
81}
82
83impl<Number> derived::DerivedValue<Number> {
84    pub fn to_base(self) -> base::BaseValue<Number> {
85        base::BaseValue {
86            unit: self.unit.to_base(),
87            number: self.number,
88        }
89    }
90}
91
92impl derived::DerivedUnit {
93    pub fn simplify(self) -> Self {
94        let mut output = self;
95
96        for identity in BASIC_IDENTITIES {
97            let after_mul = output.multiply(identity);
98            let after_div = output.divide(identity);
99            if after_mul.magnitude() < output.magnitude() {
100                let mut after_mul = after_mul;
101                let mut after_mul_mag = after_mul.magnitude();
102                loop {
103                    let next = after_mul.multiply(identity);
104                    let next_mag = next.magnitude();
105                    if next_mag >= after_mul_mag {
106                        break;
107                    }
108                    after_mul = next;
109                    after_mul_mag = next_mag;
110                }
111                output = after_mul;
112            } else if after_div.magnitude() < output.magnitude() {
113                let mut after_div = after_div;
114                let mut after_div_mag = after_div.magnitude();
115                loop {
116                    let next = after_div.divide(identity);
117                    let next_mag = next.magnitude();
118                    if next_mag >= after_div_mag {
119                        break;
120                    }
121                    after_div = next;
122                    after_div_mag = next_mag;
123                }
124                output = after_div;
125            }
126        }
127
128        output
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use crate::{base, derived};
135
136    #[test]
137    fn test_base_derived_conversions() {
138        assert_eq!(base::HERTZ, derived::HERTZ.into());
139        assert_eq!(base::NEWTON, derived::NEWTON.into());
140        assert_eq!(base::PASCAL, derived::PASCAL.into());
141        assert_eq!(base::JOULE, derived::JOULE.into());
142        assert_eq!(base::WATT, derived::WATT.into());
143        assert_eq!(base::COULOMB, derived::COULOMB.into());
144        assert_eq!(base::VOLT, derived::VOLT.into());
145        assert_eq!(base::FARAD, derived::FARAD.into());
146        assert_eq!(base::OHM, derived::OHM.into());
147        assert_eq!(base::SIEMENS, derived::SIEMENS.into());
148        assert_eq!(base::WEBER, derived::WEBER.into());
149        assert_eq!(base::TESLA, derived::TESLA.into());
150        assert_eq!(base::HENRY, derived::HENRY.into());
151        assert_eq!(base::LUX, derived::LUX.into());
152        assert_eq!(base::BECQUEREL, derived::BECQUEREL.into());
153        assert_eq!(base::GRAY, derived::GRAY.into());
154        assert_eq!(base::SIEVERT, derived::SIEVERT.into());
155        assert_eq!(base::KATAL, derived::KATAL.into());
156    }
157
158    #[test]
159    fn test_derive() {
160        let base_joule =
161            base::KILOGRAM * (base::METER * base::METER) / (base::SECOND * base::SECOND);
162        let derived_joule = base_joule.to_derived().simplify();
163        assert_eq!(
164            derived::JOULE,
165            derived_joule,
166            "{} != {}",
167            derived::JOULE,
168            derived_joule
169        );
170
171        let base_joule =
172            base::KILOGRAM * (base::METER * base::METER * base::METER) / (base::SECOND * base::SECOND);
173        let actual = base_joule.to_derived().simplify();
174        let expected = derived::JOULE * derived::METER;
175        assert_eq!(
176            expected,
177            actual,
178            "{} != {}",
179            expected,
180            actual
181        );
182    }
183}