physical_units/
convert.rs1use 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}