1use std::any::Any;
2use std::ops::{Add, Div, Mul, Neg, Sub};
3use crate::physics::basic::{Coef, Mass, MassType, Momentum, PhysicalQuantity, Velocity};
4
5impl Default for Mass {
6 fn default() -> Self {
7 Self::from_kg(0.0)
8 }
9}
10
11
12impl PhysicalQuantity for Mass {
13 fn as_any(&self) -> &dyn Any {
14 self
15 }
16
17 fn is_zero(&self) -> bool {
18 self.v == 0.0
19 }
20
21 fn default_unit_value(&self) -> f64 {
22 self.as_kg()
23 }
24
25 fn set_value(&mut self, value: f64) {
26 self.v = value;
27 }
28 fn unit_display_name(&self) -> String {
29 "Mass (kg)".to_string()
30 }
31}
32
33impl Mass {
34 pub fn from_kg(kg: f64) -> Self {
35 Self {
36 default_type: MassType::Kg,
37 v: kg,
38 }
39 }
40
41 pub fn from_g(g: f64) -> Self {
42 Self {
43 default_type: MassType::g,
44 v: g,
45 }
46 }
47
48 pub fn as_kg(&self) -> f64 {
49 match self.default_type {
50 MassType::Kg => self.v,
51 MassType::g => self.v / 1000.0,
52 }
53 }
54
55 pub fn as_g(&self) -> f64 {
56 match self.default_type {
57 MassType::Kg => self.v * 1000.0,
58 MassType::g => self.v,
59 }
60 }
61}
62
63
64impl Add for Mass {
65 type Output = Self;
66 fn add(self, rhs: Self) -> Self::Output {
67 let v = self.as_kg() + rhs.as_kg();
68 Self::from_kg(v)
69 }
70}
71
72impl<'a, 'b> Add<&'b Mass> for &'a Mass {
74 type Output = Mass;
75 fn add(self, rhs: &'b Mass) -> Self::Output { Mass::from_kg(self.as_kg() + rhs.as_kg()) }
76}
77impl<'a> Add<&'a Mass> for Mass {
78 type Output = Mass;
79 fn add(self, rhs: &'a Mass) -> Self::Output { Mass::from_kg(self.as_kg() + rhs.as_kg()) }
80}
81impl<'a> Add<Mass> for &'a Mass {
82 type Output = Mass;
83 fn add(self, rhs: Mass) -> Self::Output { Mass::from_kg(self.as_kg() + rhs.as_kg()) }
84}
85
86impl Add<f64> for Mass {
91 type Output = Self;
92 fn add(self, rhs: f64) -> Self::Output {
93 let v = self.v + rhs;
94 Mass {
95 v,
96 default_type: self.default_type,
97 }
98 }
99}
100
101impl Sub for Mass {
102 type Output = Self;
103 fn sub(self, rhs: Self) -> Self::Output {
104 let v = self.as_kg() - rhs.as_kg();
105 Self::from_kg(v)
106 }
107}
108
109impl<'a, 'b> Sub<&'b Mass> for &'a Mass {
111 type Output = Mass;
112 fn sub(self, rhs: &'b Mass) -> Self::Output { Mass::from_kg(self.as_kg() - rhs.as_kg()) }
113}
114impl<'a> Sub<&'a Mass> for Mass {
115 type Output = Mass;
116 fn sub(self, rhs: &'a Mass) -> Self::Output { Mass::from_kg(self.as_kg() - rhs.as_kg()) }
117}
118impl<'a> Sub<Mass> for &'a Mass {
119 type Output = Mass;
120 fn sub(self, rhs: Mass) -> Self::Output { Mass::from_kg(self.as_kg() - rhs.as_kg()) }
121}
122
123impl Sub<f64> for Mass {
124 type Output = Self;
125 fn sub(self, rhs: f64) -> Self::Output {
126 let v = self.v - rhs;
127 Mass {
128 v,
129 default_type: self.default_type,
130 }
131 }
132}
133
134impl Mul<f64> for Mass {
135 type Output = Self;
136 fn mul(self, rhs: f64) -> Self::Output {
137 let v = self.as_kg() * rhs;
138 Self::from_kg(v)
139 }
140}
141
142impl Div<f64> for Mass {
143 type Output = Self;
144 fn div(self, rhs: f64) -> Self::Output {
145 let v = self.as_kg() / rhs;
146 Self::from_kg(v)
147 }
148}
149
150impl Mul<Mass> for f64 {
151 type Output = Mass;
152 fn mul(self, rhs: Mass) -> Self::Output {
153 rhs * self
154 }
155}
156
157impl Div<Mass> for f64 {
158 type Output = Mass;
159 fn div(self, rhs: Mass) -> Self::Output {
160 let v = self / rhs.v;
161 Mass {
162 default_type: rhs.default_type,
163 v: v,
164 }
165 }
166}
167
168impl Mul<Coef> for Mass {
169 type Output = Self;
170 fn mul(self, rhs: Coef) -> Self::Output {
171 let v = self.as_kg() * rhs.get_value();
172 Self::from_kg(v)
173 }
174}
175
176impl Div<Coef> for Mass {
177 type Output = Self;
178 fn div(self, rhs: Coef) -> Self::Output {
179 let v = self.as_kg() / rhs.get_value();
180 Self::from_kg(v)
181 }
182}
183
184impl Neg for Mass {
185 type Output = Self;
186 fn neg(self) -> Self::Output {
187 let v = -self.as_kg();
188 Self::from_kg(v)
189 }
190}
191
192
193impl Mul<Velocity> for Mass {
194 type Output = Momentum;
195 fn mul(self, rhs: Velocity) -> Self::Output {
196 rhs * self
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203 use approx::assert_relative_eq;
204 #[test]
205 fn test_mass() {
206 let m1 = Mass::from_kg(1000.0);
207 assert_eq!(m1.v, 1000.0);
208 assert_eq!(m1.default_type, MassType::Kg);
209
210 let m2 = Mass::from_g(1000.0);
211 assert_eq!(m2.v, 1000.0);
212 assert_eq!(m2.default_type, MassType::g);
213
214 let m2 = Mass::default();
215 assert_eq!(m2.v, 0.0);
216 assert_eq!(m2.default_type, MassType::Kg);
217 }
218
219 #[test]
220 fn test_mass_as() {
221 let m1 = Mass::from_kg(1000.0);
222 let _m2 = m1.as_g();
223 assert_eq!(m1.as_g(), 1000.0 * 1000.0);
224 assert_eq!(m1.as_kg(), 1000.0);
225
226
227 let m2 = Mass::from_g(1000.0);
228 assert_eq!(m2.as_g(), 1000.0);
229 assert_eq!(m2.as_kg(), 1000.0 / 1000.0);
230 }
231
232 #[test]
233 fn test_mass_add() {
234 let m1 = Mass::from_kg(1000.0);
235 let m2 = Mass::from_kg(1000.0);
236 let m3 = m1 + m2;
237 assert_eq!(m3.as_kg(), 2000.0);
238
239 let m1 = Mass::from_g(1000.0);
240 let m2 = Mass::from_g(1000.0);
241 let m3 = m1 + m2;
242 assert_eq!(m3.as_g(), 2.0 * 1000.0);
243
244 let m1 = Mass::from_kg(1000.0);
245 let m2 = Mass::from_g(1000.0);
246 let m3 = m1 + m2;
247 assert_eq!(m3.as_kg(), 1001.0);
248
249 let m1 = Mass::from_g(1000.0);
250 let m2 = Mass::from_kg(1.0);
251 let m3 = m1 + m2;
252 assert_eq!(m3.as_kg(), 2.0);
253
254 let m1 = Mass::from_g(1000.0);
255 let m2 = m1 + 100.0;
256 assert_eq!(m2.as_kg(), 1.1);
257
258 let m1 = Mass::from_kg(1200.0);
259 let m2 = m1 + 10.2;
260 assert_eq!(m2.as_kg(), 1210.2);
261 }
262
263 #[test]
264 fn test_mass_sub() {
265 let m1 = Mass::from_kg(2000.0);
266 let m2 = Mass::from_kg(1000.0);
267 let m3 = m1 - m2;
268 assert_eq!(m3.as_kg(), 1000.0);
269
270 let m1 = Mass::from_g(3000.0);
271 let m2 = Mass::from_g(1000.0);
272 let m3 = m1 - m2;
273 assert_eq!(m3.as_g(), 2.0 * 1000.0);
274
275 let m1 = Mass::from_kg(1000.0);
276 let m2 = Mass::from_g(1000.0);
277 let m3 = m1 - m2;
278 assert_eq!(m3.as_kg(), 999.0);
279
280 let m1 = Mass::from_g(1000.0);
281 let m2 = Mass::from_kg(1.0);
282 let m3 = m1 - m2;
283 assert_eq!(m3.as_kg(), 0.0);
284
285 let m1 = Mass::from_g(1000.0);
286 let m2 = m1 - 100.0;
287 assert_eq!(m2.as_kg(), 0.9);
288
289 let m1 = Mass::from_kg(1200.0);
290 let m2 = m1 - 10.0;
291 assert_eq!(m2.as_kg(), 1190.0);
292 }
293
294 #[test]
295 fn test_mass_mul() {
296 let m1 = Mass::from_kg(2000.0);
297 let m2 = m1 * 2.0;
298 assert_eq!(m2.as_kg(), 4000.0);
299 let m1 = Mass::from_g(3000.0);
300 let m2 = m1 * 2.0;
301 assert_eq!(m2.as_g(), 6000.0);
302
303 let m1 = Mass::from_g(1000.0);
304 let m2 = m1 * Coef::new(2.0);
305 assert_eq!(m2.as_kg(), 2.0);
306
307 let m1 = Mass::from_g(1000.0);
308 let m2 = m1 * Coef::new(2.0);
309 assert_eq!(m2.as_kg(), 2.0);
310 }
311
312 #[test]
313 fn test_mass_div() {
314 let m1 = Mass::from_kg(2000.0);
315 let m2 = m1 / 2.0;
316 assert_eq!(m2.as_kg(), 1000.0);
317 let m1 = Mass::from_g(3000.0);
318 let m2 = m1 / 2.0;
319 assert_eq!(m2.as_g(), 1500.0);
320 let m1 = Mass::from_g(1000.0);
321 let m2 = m1 / Coef::new(2.0);
322 assert_eq!(m2.as_kg(), 0.5);
323 }
324
325 #[test]
326 fn test_is_zero() {
327 let m1 = Mass::from_kg(0.0);
328 assert!(m1.is_zero());
329 let m1 = Mass::from_kg(1.0);
330 assert!(!m1.is_zero());
331 }
332
333 #[test]
334 fn test_default_unit_value() {
335 let m1 = Mass::from_kg(1.0);
336 assert_eq!(m1.default_unit_value(), 1.0);
337 let m1 = Mass::from_g(1000.0);
338 assert_eq!(m1.default_unit_value(), 1.0);
339 }
340
341 #[test]
342 fn test_set_value() {
343 let mut m1 = Mass::from_kg(1.0);
344 m1.set_value(1000.0);
345 assert_eq!(m1.as_kg(), 1000.0);
346 }
347
348 #[test]
349 fn test_mass_mul_velocity() {
350 let m1 = Mass::from_kg(1000.0);
351 let v1 = Velocity::from_m_per_sec(1000.0);
352 let m2 = m1 * v1;
353 assert_eq!(m2.as_kg_m_s(), 1000.0 * 1000.0);
354 }
355
356 #[test]
357 fn test_f64_mul_mass() {
358 let m = Mass::from_kg(2.0);
360 let result = 3.0 * m;
361 assert_relative_eq!(result.as_kg(), 6.0);
362
363 let m = Mass::from_g(1000.0);
364 let result = 2.0 * m;
365 assert_relative_eq!(result.as_g(), 2000.0);
366 }
367
368 #[test]
369 fn test_f64_div_mass() {
370 let m = Mass::from_kg(2.0);
372 let result = 6.0 / m;
373 assert_relative_eq!(result.as_kg(), 3.0);
374
375 let m = Mass::from_g(1000.0);
376 let result = 2000.0 / m;
377 assert_relative_eq!(result.as_g(), 2.0);
378 }
379
380 #[test]
381 fn test_mass_ref_ops() {
382 let m1 = Mass::from_kg(2.0);
383 let m2 = Mass::from_g(1000.0); let s = &m1 + &m2;
385 assert_relative_eq!(s.as_kg(), 3.0);
386
387 let d = &m1 - &m2;
388 assert_relative_eq!(d.as_kg(), 1.0);
389
390 let s2 = m1 + &m2;
392 assert_relative_eq!(s2.as_kg(), 3.0);
393 let m1b = Mass::from_kg(2.0);
394 let s3 = &m1b + m2;
395 assert_relative_eq!(s3.as_kg(), 3.0);
396
397 let m1c = Mass::from_kg(2.0);
398 let m2c = Mass::from_g(1000.0);
399 let d2 = m1c - &m2c;
400 assert_relative_eq!(d2.as_kg(), 1.0);
401 let m1d = Mass::from_kg(2.0);
402 let m2d = Mass::from_g(1000.0);
403 let d3 = &m1d - m2d;
404 assert_relative_eq!(d3.as_kg(), 1.0);
405 }
406
407 #[test]
408 fn test_mass_neg() {
409 let m1 = Mass::from_kg(5.0);
411 let neg_m1 = -m1;
412 assert_relative_eq!(neg_m1.as_kg(), -5.0);
413
414 let m2 = Mass::from_g(-1000.0);
416 let neg_m2 = -m2;
417 assert_relative_eq!(neg_m2.as_g(), 1000.0);
418
419 let m3 = Mass::from_kg(0.0);
421 let neg_m3 = -m3;
422 assert_relative_eq!(neg_m3.as_kg(), 0.0);
423
424 let m4 = Mass::from_g(1000.0);
426 let neg_m4 = -m4;
427 assert_relative_eq!(neg_m4.as_kg(), -1.0);
428
429 let m5 = Mass::from_kg(2.0);
431 let neg_m5 = -m5;
432 assert_relative_eq!(neg_m5.as_g(), -2000.0);
433 }
434}