eng_units/
complex_units.rs1pub mod energy_unit;
18
19use crate::units::amount_of_substance_unit::AmountOfSubstanceUnit;
20use crate::units::electric_current_unit::ElectricCurrentUnit;
21use crate::units::length_unit::LengthUnit;
22use crate::units::luminous_intensity_unit::LuminousIntensityUnit;
23use crate::units::mass_unit::MassUnit;
24use crate::units::temperature_unit::TemperatureDeltaUnit;
25use crate::units::time_unit::TimeUnit;
26use crate::EngUnit;
27
28#[derive(Debug, Clone, Copy)]
29pub struct ComplexUnit {
30 pub prefix_multiplier: f64,
31 pub amount_of_substance_count: i32,
32 pub amount_of_substance_unit: AmountOfSubstanceUnit,
33 pub electric_current_count: i32,
34 pub electric_current_unit: ElectricCurrentUnit,
35 pub length_count: i32,
36 pub length_unit: LengthUnit,
37 pub luminous_intensity_count: i32,
38 pub luminous_intensity_unit: LuminousIntensityUnit,
39 pub mass_count: i32,
40 pub mass_unit: MassUnit,
41 pub temperature_count: i32,
42 pub temperature_unit: TemperatureDeltaUnit,
43 pub time_count: i32,
44 pub time_unit: TimeUnit,
45 pub unit_string: &'static str,
46}
47
48impl ComplexUnit {
49 pub fn unit_to_string(&self) -> String {
50 self.unit_string.to_string()
51 }
52}
53
54pub const JOULE: ComplexUnit = ComplexUnit {
55 prefix_multiplier: 1.0,
56 amount_of_substance_count: 0,
57 amount_of_substance_unit: AmountOfSubstanceUnit::None,
58 electric_current_count: 0,
59 electric_current_unit: ElectricCurrentUnit::None,
60 length_count: 2,
61 length_unit: LengthUnit::Meter,
62 luminous_intensity_count: 0,
63 luminous_intensity_unit: LuminousIntensityUnit::None,
64 mass_count: 1,
65 mass_unit: MassUnit::Kilogram,
66 temperature_count: 0,
67 temperature_unit: TemperatureDeltaUnit::None,
68 time_count: -2,
69 time_unit: TimeUnit::Second,
70 unit_string: "J",
71};
72
73pub const KILOJOULE: ComplexUnit = ComplexUnit {
74 prefix_multiplier: 1.0 / 1000.0,
75 amount_of_substance_count: 0,
76 amount_of_substance_unit: AmountOfSubstanceUnit::None,
77 electric_current_count: 0,
78 electric_current_unit: ElectricCurrentUnit::None,
79 length_count: 2,
80 length_unit: LengthUnit::Meter,
81 luminous_intensity_count: 0,
82 luminous_intensity_unit: LuminousIntensityUnit::None,
83 mass_count: 1,
84 mass_unit: MassUnit::Kilogram,
85 temperature_count: 0,
86 temperature_unit: TemperatureDeltaUnit::None,
87 time_count: -2,
88 time_unit: TimeUnit::Second,
89 unit_string: "kJ",
90};
91
92pub fn can_extract_normal(unit: &EngUnit, complex: &ComplexUnit) -> bool {
93 if complex.amount_of_substance_count > 0 {
94 if unit.amount_of_substance_count < complex.amount_of_substance_count {
95 return false;
96 }
97 } else if complex.amount_of_substance_count < 0 {
98 if unit.amount_of_substance_count > complex.amount_of_substance_count {
99 return false;
100 }
101 }
102
103 if complex.electric_current_count > 0 {
104 if unit.electric_current_count < complex.electric_current_count {
105 return false;
106 }
107 } else if complex.electric_current_count < 0 {
108 if unit.electric_current_count > complex.electric_current_count {
109 return false;
110 }
111 }
112
113 if complex.length_count > 0 {
114 if unit.length_count < complex.length_count {
115 return false;
116 }
117 } else if complex.length_count < 0 {
118 if unit.length_count > complex.length_count {
119 return false;
120 }
121 }
122
123 if complex.luminous_intensity_count > 0 {
124 if unit.luminous_intensity_count < complex.luminous_intensity_count {
125 return false;
126 }
127 } else if complex.luminous_intensity_count < 0 {
128 if unit.luminous_intensity_count > complex.luminous_intensity_count {
129 return false;
130 }
131 }
132
133 if complex.mass_count > 0 {
134 if unit.mass_count < complex.mass_count {
135 return false;
136 }
137 } else if complex.mass_count < 0 {
138 if unit.mass_count > complex.mass_count {
139 return false;
140 }
141 }
142
143 if complex.temperature_count > 0 {
144 if unit.temperature_count < complex.temperature_count {
145 return false;
146 }
147 } else if complex.temperature_count < 0 {
148 if unit.temperature_count > complex.temperature_count {
149 return false;
150 }
151 }
152
153 if complex.time_count > 0 {
154 if unit.time_count < complex.time_count {
155 return false;
156 }
157 } else if complex.time_count < 0 {
158 if unit.time_count > complex.time_count {
159 return false;
160 }
161 }
162 true
163}
164
165pub fn extract_numerator(unit: &EngUnit, complex: ComplexUnit) -> Option<EngUnit> {
166 if !can_extract_normal(&unit, &complex) {
167 return None;
168 }
169 let new_unit = unit.convert(complex.amount_of_substance_unit);
170 let new_unit = new_unit.convert(complex.electric_current_unit);
171 let new_unit = new_unit.convert(complex.length_unit);
172 let new_unit = new_unit.convert(complex.luminous_intensity_unit);
173 let new_unit = new_unit.convert(complex.mass_unit);
174 let new_unit = new_unit.convert(complex.temperature_unit);
175 let new_unit = new_unit.convert(complex.time_unit);
176
177 let mut new_unit = new_unit;
178 new_unit.value *= complex.prefix_multiplier;
179 new_unit.amount_of_substance_count -= complex.amount_of_substance_count;
180 new_unit.electric_current_count -= complex.electric_current_count;
181 new_unit.length_count -= complex.length_count;
182 new_unit.luminous_intensity_count -= complex.luminous_intensity_count;
183 new_unit.mass_count -= complex.mass_count;
184 new_unit.temperature_count -= complex.temperature_count;
185 new_unit.time_count -= complex.time_count;
186
187 new_unit.unit_numerator.push(complex.clone());
188 Some(new_unit)
189}
190
191#[cfg(test)]
192
193mod tests {
194 use super::*;
195 use crate::*;
196
197 #[test]
198 fn test_1() {
199 let u1 = kJ!(1.0);
200 let u2 = extract_numerator(&u1, JOULE);
201 assert!(u2.is_some());
202 let u2 = u2.unwrap();
203 assert_eq!(1000.0, u2.value);
204 assert_eq!("1000.00 J", u2.to_string());
205 }
206
207 #[test]
208 fn test_2() {
209 let u1 = kJ!(1.0);
210 let u2 = extract_numerator(&u1, KILOJOULE);
211 assert!(u2.is_some());
212 let u2 = u2.unwrap();
213 assert_eq!(1.0, u2.value);
214 assert_eq!("1.00 kJ", u2.to_string());
215 }
216}