1#[derive(Debug, Clone)]
2pub enum Unit {
3 Mass(Mass),
4 Time(Time),
5 Length(Length),
6 Speed(Speed),
7 Angle(Angle),
8 Pressure(Pressure),
9 Area(Area),
10 Volume(Volume),
11 Temperature(Temperature),
12 Energy(Energy),
13 Power(Power),
14 Force(Force),
15 ElectricCharge(ElectricCharge),
16 Current(Current),
17 Frequency(Frequency),
18 Acceleration(Acceleration),
19}
20
21#[derive(Debug, Clone)]
22pub enum Mass {
23 Kg,
24 Gram,
25 Ton,
26 Grain,
27 Carat,
28 Pound,
29 Ounce,
30 Atomic,
31 Earth,
32 Sun,
33 Moon,
34 Jupiter,
35 Milligram,
36 Microgram,
37 Nanogram,
38 Custom(f64, Box<Mass>),
39}
40
41impl Mass {
42 pub fn convert_to(self, to: Self) -> Self {
43 let base_kg = match self {
44 Mass::Kg => 1.0,
45 Mass::Gram => 0.001,
46 Mass::Ton => 1000.0,
47 Mass::Grain => 0.0000647989,
48 Mass::Carat => 0.0002,
49 Mass::Pound => 0.45359237,
50 Mass::Ounce => 0.028349523125,
51 Mass::Atomic => 1.660539067e-27,
52 Mass::Earth => 5.972e24,
53 Mass::Sun => 1.989e30,
54 Mass::Moon => 7.34767309e22,
55 Mass::Jupiter => 1.8982e27,
56 Mass::Milligram => 0.000001,
57 Mass::Microgram => 0.000000001,
58 Mass::Nanogram => 0.000000000001,
59 Mass::Custom(value, base) => {
60 value
61 * match *base {
62 Mass::Kg => 1.0,
63 Mass::Gram => 0.001,
64 Mass::Ton => 1000.0,
65 Mass::Grain => 0.0000647989,
66 Mass::Carat => 0.0002,
67 Mass::Pound => 0.45359237,
68 Mass::Ounce => 0.028349523125,
69 Mass::Atomic => 1.660539067e-27,
70 Mass::Earth => 5.972e24,
71 Mass::Sun => 1.989e30,
72 Mass::Moon => 7.34767309e22,
73 Mass::Jupiter => 1.8982e27,
74 Mass::Milligram => 0.000001,
75 Mass::Microgram => 0.000000001,
76 Mass::Nanogram => 0.000000000001,
77 Mass::Custom(v, b) => v * b.convert_to(Mass::Kg).to_kg(),
78 }
79 }
80 };
81
82 match to {
83 Mass::Kg => Mass::Kg,
84 Mass::Gram => Mass::Custom(base_kg / 0.001, Box::new(Mass::Gram)),
85 Mass::Ton => Mass::Custom(base_kg / 1000.0, Box::new(Mass::Ton)),
86 Mass::Grain => Mass::Custom(base_kg / 0.0000647989, Box::new(Mass::Grain)),
87 Mass::Carat => Mass::Custom(base_kg / 0.0002, Box::new(Mass::Carat)),
88 Mass::Pound => Mass::Custom(base_kg / 0.45359237, Box::new(Mass::Pound)),
89 Mass::Ounce => Mass::Custom(base_kg / 0.028349523125, Box::new(Mass::Ounce)),
90 Mass::Atomic => Mass::Custom(base_kg / 1.660539067e-27, Box::new(Mass::Atomic)),
91 Mass::Earth => Mass::Custom(base_kg / 5.972e24, Box::new(Mass::Earth)),
92 Mass::Sun => Mass::Custom(base_kg / 1.989e30, Box::new(Mass::Sun)),
93 Mass::Moon => Mass::Custom(base_kg / 7.34767309e22, Box::new(Mass::Moon)),
94 Mass::Jupiter => Mass::Custom(base_kg / 1.8982e27, Box::new(Mass::Jupiter)),
95 Mass::Milligram => Mass::Custom(base_kg / 0.000001, Box::new(Mass::Milligram)),
96 Mass::Microgram => Mass::Custom(base_kg / 0.000000001, Box::new(Mass::Microgram)),
97 Mass::Nanogram => Mass::Custom(base_kg / 0.000000000001, Box::new(Mass::Nanogram)),
98 Mass::Custom(value, base) => {
99 let base_in_kg = base.clone().convert_to(Mass::Kg).to_kg();
100 Mass::Custom(base_kg / (value * base_in_kg), base)
101 }
102 }
103 }
104
105 pub fn to_kg(&self) -> f64 {
106 match self {
107 Mass::Kg => 1.0,
108 Mass::Gram => 0.001,
109 Mass::Ton => 1000.0,
110 Mass::Grain => 0.0000647989,
111 Mass::Carat => 0.0002,
112 Mass::Pound => 0.45359237,
113 Mass::Ounce => 0.028349523125,
114 Mass::Atomic => 1.660539067e-27,
115 Mass::Earth => 5.972e24,
116 Mass::Sun => 1.989e30,
117 Mass::Moon => 7.34767309e22,
118 Mass::Jupiter => 1.8982e27,
119 Mass::Milligram => 0.000001,
120 Mass::Microgram => 0.000000001,
121 Mass::Nanogram => 0.000000000001,
122 Mass::Custom(value, base) => value * base.to_kg(),
123 }
124 }
125}
126
127#[derive(Debug, Clone)]
128pub enum Time {
129 Second,
130 Millisecond,
131 Microsecond,
132 Nanosecond,
133 Minute,
134 Hour,
135 Day,
136 Week,
137 Year,
138 JulianYear,
139 Decade,
140 Century,
141 SiderealDay,
142 SiderealYear,
143 Custom(f64, Box<Time>),
144}
145
146impl Time {
147 pub fn convert_to(self, to: Self) -> Self {
148 let base_seconds = match self {
149 Time::Second => 1.0,
150 Time::Millisecond => 0.001,
151 Time::Microsecond => 0.000001,
152 Time::Nanosecond => 0.000000001,
153 Time::Minute => 60.0,
154 Time::Hour => 3600.0,
155 Time::Day => 86400.0,
156 Time::Week => 604800.0,
157 Time::Year => 31536000.0,
158 Time::JulianYear => 31557600.0,
159 Time::Decade => 315360000.0,
160 Time::Century => 3153600000.0,
161 Time::SiderealDay => 86164.0905,
162 Time::SiderealYear => 31558149.504,
163 Time::Custom(value, base) => {
164 value
165 * match *base {
166 Time::Second => 1.0,
167 Time::Millisecond => 0.001,
168 Time::Microsecond => 0.000001,
169 Time::Nanosecond => 0.000000001,
170 Time::Minute => 60.0,
171 Time::Hour => 3600.0,
172 Time::Day => 86400.0,
173 Time::Week => 604800.0,
174 Time::Year => 31536000.0,
175 Time::JulianYear => 31557600.0,
176 Time::Decade => 315360000.0,
177 Time::Century => 3153600000.0,
178 Time::SiderealDay => 86164.0905,
179 Time::SiderealYear => 31558149.504,
180 Time::Custom(v, b) => v * b.convert_to(Time::Second).to_seconds(),
181 }
182 }
183 };
184
185 match to {
186 Time::Second => Time::Second,
187 Time::Millisecond => Time::Custom(base_seconds / 0.001, Box::new(Time::Millisecond)),
188 Time::Microsecond => Time::Custom(base_seconds / 0.000001, Box::new(Time::Microsecond)),
189 Time::Nanosecond => {
190 Time::Custom(base_seconds / 0.000000001, Box::new(Time::Nanosecond))
191 }
192 Time::Minute => Time::Custom(base_seconds / 60.0, Box::new(Time::Minute)),
193 Time::Hour => Time::Custom(base_seconds / 3600.0, Box::new(Time::Hour)),
194 Time::Day => Time::Custom(base_seconds / 86400.0, Box::new(Time::Day)),
195 Time::Week => Time::Custom(base_seconds / 604800.0, Box::new(Time::Week)),
196 Time::Year => Time::Custom(base_seconds / 31536000.0, Box::new(Time::Year)),
197 Time::JulianYear => Time::Custom(base_seconds / 31557600.0, Box::new(Time::JulianYear)),
198 Time::Decade => Time::Custom(base_seconds / 315360000.0, Box::new(Time::Decade)),
199 Time::Century => Time::Custom(base_seconds / 3153600000.0, Box::new(Time::Century)),
200 Time::SiderealDay => {
201 Time::Custom(base_seconds / 86164.0905, Box::new(Time::SiderealDay))
202 }
203 Time::SiderealYear => {
204 Time::Custom(base_seconds / 31558149.504, Box::new(Time::SiderealYear))
205 }
206 Time::Custom(value, base) => {
207 let base_in_seconds = base.clone().convert_to(Time::Second).to_seconds();
208 Time::Custom(base_seconds / (value * base_in_seconds), base)
209 }
210 }
211 }
212
213 pub fn to_seconds(&self) -> f64 {
214 match self {
215 Time::Second => 1.0,
216 Time::Millisecond => 0.001,
217 Time::Microsecond => 0.000001,
218 Time::Nanosecond => 0.000000001,
219 Time::Minute => 60.0,
220 Time::Hour => 3600.0,
221 Time::Day => 86400.0,
222 Time::Week => 604800.0,
223 Time::Year => 31536000.0,
224 Time::JulianYear => 31557600.0,
225 Time::Decade => 315360000.0,
226 Time::Century => 3153600000.0,
227 Time::SiderealDay => 86164.0905,
228 Time::SiderealYear => 31558149.504,
229 Time::Custom(value, base) => value * base.to_seconds(),
230 }
231 }
232}
233
234#[derive(Debug, Clone)]
235pub enum Length {
236 Meter,
237 Centimeter,
238 Kilometer,
239 Inch,
240 Foot,
241 Yard,
242 Mile,
243 Mil,
244 Point,
245 NauticalMile,
246 Fermi,
247 Micron,
248 AstroUnit,
249 LightYear,
250 LightMinute,
251 LightSecond,
252 LightDay,
253 Parsec,
254 Millimeter,
255 Micrometer,
256 Nanometer,
257 Angstrom,
258 Megaparsec,
259 Gigaparsec,
260 Custom(f64, Box<Length>),
261}
262
263impl Length {
264 pub fn convert_to(self, to: Self) -> Self {
265 let base_meters = self.to_meters();
266
267 match to {
268 Length::Meter => Length::Meter,
269 Length::Centimeter => Length::Custom(base_meters * 100.0, Box::new(Length::Centimeter)),
270 Length::Kilometer => Length::Custom(base_meters / 1000.0, Box::new(Length::Kilometer)),
271 Length::Inch => Length::Custom(base_meters / 0.0254, Box::new(Length::Inch)),
272 Length::Foot => Length::Custom(base_meters / 0.3048, Box::new(Length::Foot)),
273 Length::Yard => Length::Custom(base_meters / 0.9144, Box::new(Length::Yard)),
274 Length::Mile => Length::Custom(base_meters / 1609.344, Box::new(Length::Mile)),
275 Length::Mil => Length::Custom(base_meters / 0.0000254, Box::new(Length::Mil)),
276 Length::Point => Length::Custom(base_meters / 0.0003527777778, Box::new(Length::Point)),
277 Length::NauticalMile => {
278 Length::Custom(base_meters / 1852.0, Box::new(Length::NauticalMile))
279 }
280 Length::Fermi => Length::Custom(base_meters / 1e-15, Box::new(Length::Fermi)),
281 Length::Micron => Length::Custom(base_meters / 0.000001, Box::new(Length::Micron)),
282 Length::AstroUnit => {
283 Length::Custom(base_meters / 149597870700.0, Box::new(Length::AstroUnit))
284 }
285 Length::LightYear => {
286 Length::Custom(base_meters / 9.461e15, Box::new(Length::LightYear))
287 }
288 Length::LightMinute => {
289 Length::Custom(base_meters / 17987547480.0, Box::new(Length::LightMinute))
290 }
291 Length::LightSecond => {
292 Length::Custom(base_meters / 299792458.0, Box::new(Length::LightSecond))
293 }
294 Length::LightDay => {
295 Length::Custom(base_meters / 25902068371200.0, Box::new(Length::LightDay))
296 }
297 Length::Parsec => Length::Custom(base_meters / 3.086e16, Box::new(Length::Parsec)),
298 Length::Millimeter => Length::Custom(base_meters / 0.001, Box::new(Length::Millimeter)),
299 Length::Micrometer => {
300 Length::Custom(base_meters / 0.000001, Box::new(Length::Micrometer))
301 }
302 Length::Nanometer => {
303 Length::Custom(base_meters / 0.000000001, Box::new(Length::Nanometer))
304 }
305 Length::Angstrom => Length::Custom(base_meters / 1e-10, Box::new(Length::Angstrom)),
306 Length::Megaparsec => {
307 Length::Custom(base_meters / 3.086e22, Box::new(Length::Megaparsec))
308 }
309 Length::Gigaparsec => {
310 Length::Custom(base_meters / 3.086e25, Box::new(Length::Gigaparsec))
311 }
312 Length::Custom(value, base) => {
313 let base_in_meters = base.clone().convert_to(Length::Meter).to_meters();
314 Length::Custom(base_meters / (value * base_in_meters), base)
315 }
316 }
317 }
318
319 pub fn to_meters(&self) -> f64 {
320 match self {
321 Length::Meter => 1.0,
322 Length::Centimeter => 0.01,
323 Length::Kilometer => 1000.0,
324 Length::Inch => 0.0254,
325 Length::Foot => 0.3048,
326 Length::Yard => 0.9144,
327 Length::Mile => 1609.344,
328 Length::Mil => 0.0000254,
329 Length::Point => 0.0003527777778,
330 Length::NauticalMile => 1852.0,
331 Length::Fermi => 1e-15,
332 Length::Micron => 0.000001,
333 Length::AstroUnit => 149597870700.0,
334 Length::LightYear => 9.461e15,
335 Length::LightMinute => 17987547480.0,
336 Length::LightSecond => 299792458.0,
337 Length::LightDay => 25902068371200.0,
338 Length::Parsec => 3.086e16,
339 Length::Millimeter => 0.001,
340 Length::Micrometer => 0.000001,
341 Length::Nanometer => 0.000000001,
342 Length::Angstrom => 1e-10,
343 Length::Megaparsec => 3.086e22,
344 Length::Gigaparsec => 3.086e25,
345 Length::Custom(value, base) => value * base.to_meters(),
346 }
347 }
348}
349
350#[derive(Debug, Clone)]
351pub enum Speed {
352 KmH,
353 MpH,
354 Mach,
355 Knot,
356 MetersPerSecond,
357 C,
358 Custom(Length, Time),
359}
360
361impl Speed {
362 pub fn convert_to(self, to: Self) -> Self {
363 let base_mps = self.to_mps();
364
365 match to {
366 Speed::MetersPerSecond => Speed::MetersPerSecond,
367 Speed::KmH => {
368 let km_per_hour = base_mps * 3.6; Speed::Custom(
370 Length::Custom(km_per_hour, Box::new(Length::Kilometer)),
371 Time::Hour,
372 )
373 }
374 Speed::MpH => {
375 let miles_per_hour = base_mps * 2.23694; Speed::Custom(
377 Length::Custom(miles_per_hour, Box::new(Length::Mile)),
378 Time::Hour,
379 )
380 }
381 Speed::Mach => {
382 let mach = base_mps / 343.0; Speed::Custom(
384 Length::Custom(mach * 343.0, Box::new(Length::Meter)),
385 Time::Second,
386 )
387 }
388 Speed::Knot => {
389 let knots = base_mps * 1.94384; Speed::Custom(
391 Length::Custom(knots * 1852.0, Box::new(Length::NauticalMile)),
392 Time::Hour,
393 )
394 }
395 Speed::C => {
396 let c = base_mps / 299792458.0;
397 Speed::Custom(
398 Length::Custom(c * 299792458.0, Box::new(Length::Meter)),
399 Time::Second,
400 )
401 }
402 Speed::Custom(length, time) => {
403 let target_length = Length::Meter.convert_to(length);
404 let target_time = Time::Second.convert_to(time);
405 Speed::Custom(target_length, target_time)
406 }
407 }
408 }
409
410 pub fn to_mps(&self) -> f64 {
411 match self {
412 Speed::MetersPerSecond => 1.0,
413 Speed::KmH => 0.277778,
414 Speed::MpH => 0.44704,
415 Speed::Mach => 343.0,
416 Speed::Knot => 0.514444,
417 Speed::C => 299792458.0,
418 Speed::Custom(length, time) => {
419 let meters = match length {
420 Length::Custom(value, base) => value * base.to_meters(),
421 _ => length.clone().convert_to(Length::Meter).to_meters(),
422 };
423 let seconds = match time {
424 Time::Custom(value, base) => value * base.to_seconds(),
425 _ => time.clone().convert_to(Time::Second).to_seconds(),
426 };
427 meters / seconds
428 }
429 }
430 }
431
432 pub fn to_kmh(&self) -> f64 {
433 self.to_mps() * 3.6
434 }
435
436 pub fn to_mph(&self) -> f64 {
437 self.to_mps() * 2.23694
438 }
439
440 pub fn to_knots(&self) -> f64 {
441 self.to_mps() * 1.94384
442 }
443
444 pub fn to_mach(&self) -> f64 {
445 self.to_mps() / 343.0
446 }
447
448 pub fn to_c(&self) -> f64 {
449 self.to_mps() / 299792458.0
450 }
451}
452
453#[derive(Debug, Clone)]
454pub enum Angle {
455 Degree,
456 Radian,
457 Gradian,
458 ArcMinute,
459 ArcSecond,
460 Custom(f64, Box<Angle>),
461}
462
463impl Angle {
464 pub fn convert_to(self, to: Self) -> Self {
465 let base_radians = self.to_radians();
467
468 match to {
469 Angle::Radian => Angle::Radian,
470 Angle::Degree => {
471 Angle::Custom(base_radians * 57.29577951308232, Box::new(Angle::Degree))
472 } Angle::Gradian => {
474 Angle::Custom(base_radians * 63.66197723675813, Box::new(Angle::Gradian))
475 } Angle::ArcMinute => Angle::Custom(
477 base_radians * 3437.7467707849396,
478 Box::new(Angle::ArcMinute),
479 ), Angle::ArcSecond => Angle::Custom(
481 base_radians * 206264.80624709636,
482 Box::new(Angle::ArcSecond),
483 ), Angle::Custom(value, base) => {
485 let base_in_radians = base.clone().convert_to(Angle::Radian).to_radians();
486 Angle::Custom(base_radians / (value * base_in_radians), base)
487 }
488 }
489 }
490
491 pub fn to_radians(&self) -> f64 {
492 match self {
493 Angle::Radian => 1.0,
494 Angle::Degree => 0.017453292519943295,
495 Angle::Gradian => 0.015707963267948967,
496 Angle::ArcMinute => 0.0002908882086657216,
497 Angle::ArcSecond => 0.000004848136811095278,
498 Angle::Custom(value, base) => value * base.to_radians(),
499 }
500 }
501
502 pub fn to_degrees(&self) -> f64 {
503 self.to_radians() * 57.29577951308232
504 }
505}
506
507#[derive(Debug, Clone)]
508pub enum Pressure {
509 Atmospheric,
510 Bar,
511 Millibar,
512 Pascal,
513 Kilopascal,
514 Megapascal,
515 Torr,
516 MmHg,
517 Psi,
518 Custom(Force, Area),
519}
520
521impl Pressure {
522 pub fn convert_to(self, to: Self) -> Self {
523 let base_pascal = self.to_pascal();
524
525 match to {
526 Pressure::Pascal => Pressure::Pascal,
527 Pressure::Atmospheric => Pressure::Custom(
528 Force::Custom(
529 Mass::Custom(base_pascal / 101325.0, Box::new(Mass::Kg)),
530 Length::Meter,
531 Time::Second,
532 ),
533 Area::SquareMeter,
534 ),
535 Pressure::Bar => Pressure::Custom(
536 Force::Custom(
537 Mass::Custom(base_pascal / 100000.0, Box::new(Mass::Kg)),
538 Length::Meter,
539 Time::Second,
540 ),
541 Area::SquareMeter,
542 ),
543 Pressure::Millibar => Pressure::Custom(
544 Force::Custom(
545 Mass::Custom(base_pascal / 100.0, Box::new(Mass::Kg)),
546 Length::Meter,
547 Time::Second,
548 ),
549 Area::SquareMeter,
550 ),
551 Pressure::Kilopascal => Pressure::Custom(
552 Force::Custom(
553 Mass::Custom(base_pascal / 1000.0, Box::new(Mass::Kg)),
554 Length::Meter,
555 Time::Second,
556 ),
557 Area::SquareMeter,
558 ),
559 Pressure::Megapascal => Pressure::Custom(
560 Force::Custom(
561 Mass::Custom(base_pascal / 1000000.0, Box::new(Mass::Kg)),
562 Length::Meter,
563 Time::Second,
564 ),
565 Area::SquareMeter,
566 ),
567 Pressure::Torr => Pressure::Custom(
568 Force::Custom(
569 Mass::Custom(base_pascal / 133.322, Box::new(Mass::Kg)),
570 Length::Meter,
571 Time::Second,
572 ),
573 Area::SquareMeter,
574 ),
575 Pressure::MmHg => Pressure::Custom(
576 Force::Custom(
577 Mass::Custom(base_pascal / 133.322, Box::new(Mass::Kg)),
578 Length::Meter,
579 Time::Second,
580 ),
581 Area::SquareMeter,
582 ),
583 Pressure::Psi => Pressure::Custom(
584 Force::Custom(
585 Mass::Custom(base_pascal / 6894.757293168361, Box::new(Mass::Kg)),
586 Length::Meter,
587 Time::Second,
588 ),
589 Area::SquareMeter,
590 ),
591 Pressure::Custom(force, area) => {
592 let target_force = Force::Newton.convert_to(force);
593 let target_area = Area::SquareMeter.convert_to(area);
594 Pressure::Custom(target_force, target_area)
595 }
596 }
597 }
598
599 pub fn to_pascal(&self) -> f64 {
600 match self {
601 Pressure::Pascal => 1.0,
602 Pressure::Atmospheric => 101325.0,
603 Pressure::Bar => 100000.0,
604 Pressure::Millibar => 100.0,
605 Pressure::Kilopascal => 1000.0,
606 Pressure::Megapascal => 1000000.0,
607 Pressure::Torr => 133.322,
608 Pressure::MmHg => 133.322,
609 Pressure::Psi => 6894.757293168361,
610 Pressure::Custom(force, area) => {
611 let newtons = match force {
612 Force::Newton => 1.0,
613 Force::Dyne => 0.00001,
614 Force::Pound => 4.448222,
615 Force::Kg => 9.80665,
616 Force::Custom(mass, length, time) => {
617 let kg = mass.clone().convert_to(Mass::Kg).to_kg();
618 let meters = length.clone().convert_to(Length::Meter).to_meters();
619 let seconds = time.clone().convert_to(Time::Second).to_seconds();
620 kg * (meters / (seconds * seconds))
621 }
622 };
623
624 let square_meters = match area {
625 Area::SquareMeter => 1.0,
626 Area::Acre => 4046.8564224,
627 Area::Hectare => 10000.0,
628 Area::SquareKilometer => 1000000.0,
629 Area::SquareMile => 2589988.110336,
630 Area::SquareFoot => 0.09290304,
631 Area::Custom(length) => {
632 let meters = length.clone().convert_to(Length::Meter).to_meters();
633 meters * meters
634 }
635 };
636
637 newtons / square_meters
638 }
639 }
640 }
641
642 pub fn to_bar(&self) -> f64 {
643 self.to_pascal() / 100000.0
644 }
645
646 pub fn to_atm(&self) -> f64 {
647 self.to_pascal() / 101325.0
648 }
649
650 pub fn to_psi(&self) -> f64 {
651 self.to_pascal() / 6894.757293168361
652 }
653}
654
655#[derive(Debug, Clone)]
656pub enum Area {
657 Acre,
658 Hectare,
659 SquareMeter,
660 SquareKilometer,
661 SquareMile,
662 SquareFoot,
663 Custom(Length),
664}
665
666impl Area {
667 pub fn convert_to(self, to: Self) -> Self {
668 let base_square_meters = self.to_square_meters();
669
670 match to {
671 Area::SquareMeter => Area::Custom(Length::Meter),
672 Area::Acre => Area::Custom(Length::Custom(
673 (base_square_meters / 4046.8564224).sqrt(),
674 Box::new(Length::Custom(2.0, Box::new(Length::Meter))),
675 )),
676 Area::Hectare => Area::Custom(Length::Custom(
677 (base_square_meters / 10000.0).sqrt(),
678 Box::new(Length::Custom(100.0, Box::new(Length::Meter))),
679 )),
680 Area::SquareKilometer => Area::Custom(Length::Custom(
681 (base_square_meters / 1_000_000.0).sqrt(),
682 Box::new(Length::Kilometer),
683 )),
684 Area::SquareMile => Area::Custom(Length::Custom(
685 (base_square_meters / 2_589_988.110336).sqrt(),
686 Box::new(Length::Mile),
687 )),
688 Area::SquareFoot => Area::Custom(Length::Custom(
689 (base_square_meters / 0.09290304).sqrt(),
690 Box::new(Length::Foot),
691 )),
692 Area::Custom(length) => {
693 let target_length = Length::Meter.convert_to(length);
694 Area::Custom(target_length)
695 }
696 }
697 }
698
699 pub fn to_square_meters(&self) -> f64 {
700 match self {
701 Area::SquareMeter => 1.0,
702 Area::Acre => 4046.8564224,
703 Area::Hectare => 10000.0,
704 Area::SquareKilometer => 1_000_000.0,
705 Area::SquareMile => 2_589_988.110336,
706 Area::SquareFoot => 0.09290304,
707 Area::Custom(length) => {
708 let meters = length.clone().convert_to(Length::Meter).to_meters();
709 meters * meters
710 }
711 }
712 }
713
714 pub fn to_acres(&self) -> f64 {
715 self.to_square_meters() / 4046.8564224
716 }
717
718 pub fn to_hectares(&self) -> f64 {
719 self.to_square_meters() / 10000.0
720 }
721
722 pub fn to_square_kilometers(&self) -> f64 {
723 self.to_square_meters() / 1_000_000.0
724 }
725
726 pub fn to_square_miles(&self) -> f64 {
727 self.to_square_meters() / 2_589_988.110336
728 }
729
730 pub fn to_square_feet(&self) -> f64 {
731 self.to_square_meters() / 0.09290304
732 }
733}
734
735impl Length {
736 pub fn squared(&self) -> Area {
737 Area::Custom(self.clone())
738 }
739}
740
741#[derive(Debug, Clone)]
742pub enum Volume {
743 Custom(Length),
744 CubicMeter,
745 CubicFoot,
746 Liter,
747 Milliliter,
748 Gallon,
749 Barell,
750 FluidOunce,
751 Pint,
752 Quart,
753}
754
755impl Volume {
756 pub fn convert_to(self, to: Self) -> Self {
757 let base_cubic_meters = self.to_cubic_meters();
758
759 match to {
760 Volume::CubicMeter => Volume::Custom(Length::Meter),
761 Volume::CubicFoot => Volume::Custom(Length::Custom(
762 (base_cubic_meters / 0.028316846592).cbrt(),
763 Box::new(Length::Foot),
764 )),
765 Volume::Liter => Volume::Custom(Length::Custom(
766 (base_cubic_meters / 0.001).cbrt(),
767 Box::new(Length::Custom(0.1, Box::new(Length::Meter))),
768 )),
769 Volume::Milliliter => Volume::Custom(Length::Custom(
770 (base_cubic_meters / 0.000001).cbrt(),
771 Box::new(Length::Custom(0.01, Box::new(Length::Meter))),
772 )),
773 Volume::Gallon => Volume::Custom(Length::Custom(
774 (base_cubic_meters / 0.003785411784).cbrt(),
775 Box::new(Length::Custom(0.1546, Box::new(Length::Meter))),
776 )),
777 Volume::Barell => Volume::Custom(Length::Custom(
778 (base_cubic_meters / 0.158987294928).cbrt(),
779 Box::new(Length::Custom(0.5408, Box::new(Length::Meter))),
780 )),
781 Volume::FluidOunce => Volume::Custom(Length::Custom(
782 (base_cubic_meters / 0.0000295735295625).cbrt(),
783 Box::new(Length::Custom(0.0312, Box::new(Length::Meter))),
784 )),
785 Volume::Pint => Volume::Custom(Length::Custom(
786 (base_cubic_meters / 0.000473176473).cbrt(),
787 Box::new(Length::Custom(0.0781, Box::new(Length::Meter))),
788 )),
789 Volume::Quart => Volume::Custom(Length::Custom(
790 (base_cubic_meters / 0.000946352946).cbrt(),
791 Box::new(Length::Custom(0.0984, Box::new(Length::Meter))),
792 )),
793 Volume::Custom(length) => {
794 let target_length = Length::Meter.convert_to(length);
795 Volume::Custom(target_length)
796 }
797 }
798 }
799
800 pub fn to_cubic_meters(&self) -> f64 {
801 match self {
802 Volume::CubicMeter => 1.0,
803 Volume::CubicFoot => 0.028316846592,
804 Volume::Liter => 0.001,
805 Volume::Milliliter => 0.000001,
806 Volume::Gallon => 0.003785411784,
807 Volume::Barell => 0.158987294928,
808 Volume::FluidOunce => 0.0000295735295625,
809 Volume::Pint => 0.000473176473,
810 Volume::Quart => 0.000946352946,
811 Volume::Custom(length) => {
812 let meters = length.clone().convert_to(Length::Meter).to_meters();
813 meters * meters * meters
814 }
815 }
816 }
817
818 pub fn to_liters(&self) -> f64 {
819 self.to_cubic_meters() * 1000.0
820 }
821
822 pub fn to_gallons(&self) -> f64 {
823 self.to_cubic_meters() / 0.003785411784
824 }
825
826 pub fn to_cubic_feet(&self) -> f64 {
827 self.to_cubic_meters() / 0.028316846592
828 }
829
830 pub fn to_milliliters(&self) -> f64 {
831 self.to_cubic_meters() * 1_000_000.0
832 }
833
834 pub fn to_fluid_ounces(&self) -> f64 {
835 self.to_cubic_meters() / 0.0000295735295625
836 }
837
838 pub fn to_pints(&self) -> f64 {
839 self.to_cubic_meters() / 0.000473176473
840 }
841
842 pub fn to_quarts(&self) -> f64 {
843 self.to_cubic_meters() / 0.000946352946
844 }
845
846 pub fn to_barrels(&self) -> f64 {
847 self.to_cubic_meters() / 0.158987294928
848 }
849}
850
851impl Length {
852 pub fn cubed(&self) -> Volume {
853 Volume::Custom(self.clone())
854 }
855}
856
857#[derive(Debug, Clone)]
858pub enum Temperature {
859 Celsius,
860 Fahrenheit,
861 Kelvin,
862 Rankine,
863}
864
865impl Temperature {
866 pub fn convert_to(self, to: Self) -> Self {
867 match to {
868 Temperature::Kelvin => Temperature::Kelvin,
869 Temperature::Celsius => Temperature::Celsius,
870 Temperature::Fahrenheit => Temperature::Fahrenheit,
871 Temperature::Rankine => Temperature::Rankine,
872 }
873 }
874
875 pub fn to_kelvin(&self, value: f64) -> f64 {
876 match self {
877 Temperature::Kelvin => value,
878 Temperature::Celsius => value + 273.15,
879 Temperature::Fahrenheit => (value - 32.0) * 5.0 / 9.0 + 273.15,
880 Temperature::Rankine => value * 5.0 / 9.0,
881 }
882 }
883
884 pub fn from_kelvin(&self, kelvin: f64) -> f64 {
885 match self {
886 Temperature::Kelvin => kelvin,
887 Temperature::Celsius => kelvin - 273.15,
888 Temperature::Fahrenheit => (kelvin - 273.15) * 9.0 / 5.0 + 32.0,
889 Temperature::Rankine => kelvin * 9.0 / 5.0,
890 }
891 }
892
893 pub fn to_celsius(&self, value: f64) -> f64 {
894 let kelvin = self.to_kelvin(value);
895 Temperature::Celsius.from_kelvin(kelvin)
896 }
897
898 pub fn to_fahrenheit(&self, value: f64) -> f64 {
899 let kelvin = self.to_kelvin(value);
900 Temperature::Fahrenheit.from_kelvin(kelvin)
901 }
902
903 pub fn to_rankine(&self, value: f64) -> f64 {
904 let kelvin = self.to_kelvin(value);
905 Temperature::Rankine.from_kelvin(kelvin)
906 }
907}
908
909#[derive(Debug, Clone)]
910pub enum Energy {
911 Joule,
912 Kilojoule,
913 Megajoule,
914 Ev,
915 KiloEv,
916 MegaEv,
917 Calorie,
918 Kilocalorie,
919 Erg,
920 TNT,
921 Custom(Force, Length),
923}
924
925impl Energy {
926 pub fn convert_to(self, to: Self) -> Self {
927 let base_joules = self.to_joules();
928
929 match to {
930 Energy::Joule => Energy::Joule,
931 Energy::Kilojoule => Energy::Custom(
932 Force::Custom(
933 Mass::Custom(base_joules / 1000.0, Box::new(Mass::Kg)),
934 Length::Meter,
935 Time::Second,
936 ),
937 Length::Meter,
938 ),
939 Energy::Megajoule => Energy::Custom(
940 Force::Custom(
941 Mass::Custom(base_joules / 1_000_000.0, Box::new(Mass::Kg)),
942 Length::Meter,
943 Time::Second,
944 ),
945 Length::Meter,
946 ),
947 Energy::Ev => Energy::Custom(
948 Force::Custom(
949 Mass::Custom(base_joules / 1.602176634e-19, Box::new(Mass::Kg)),
950 Length::Meter,
951 Time::Second,
952 ),
953 Length::Meter,
954 ),
955 Energy::KiloEv => Energy::Custom(
956 Force::Custom(
957 Mass::Custom(base_joules / 1.602176634e-16, Box::new(Mass::Kg)),
958 Length::Meter,
959 Time::Second,
960 ),
961 Length::Meter,
962 ),
963 Energy::MegaEv => Energy::Custom(
964 Force::Custom(
965 Mass::Custom(base_joules / 1.602176634e-13, Box::new(Mass::Kg)),
966 Length::Meter,
967 Time::Second,
968 ),
969 Length::Meter,
970 ),
971 Energy::Calorie => Energy::Custom(
972 Force::Custom(
973 Mass::Custom(base_joules / 4.184, Box::new(Mass::Kg)),
974 Length::Meter,
975 Time::Second,
976 ),
977 Length::Meter,
978 ),
979 Energy::Kilocalorie => Energy::Custom(
980 Force::Custom(
981 Mass::Custom(base_joules / 4184.0, Box::new(Mass::Kg)),
982 Length::Meter,
983 Time::Second,
984 ),
985 Length::Meter,
986 ),
987 Energy::Erg => Energy::Custom(
988 Force::Custom(
989 Mass::Custom(base_joules / 1e-7, Box::new(Mass::Kg)),
990 Length::Meter,
991 Time::Second,
992 ),
993 Length::Meter,
994 ),
995 Energy::TNT => Energy::Custom(
996 Force::Custom(
997 Mass::Custom(base_joules / 4.184e9, Box::new(Mass::Kg)),
998 Length::Meter,
999 Time::Second,
1000 ),
1001 Length::Meter,
1002 ),
1003 Energy::Custom(force, length) => {
1004 let target_force = Force::Newton.convert_to(force);
1005 let target_length = Length::Meter.convert_to(length);
1006 Energy::Custom(target_force, target_length)
1007 }
1008 }
1009 }
1010
1011 pub fn to_joules(&self) -> f64 {
1012 match self {
1013 Energy::Joule => 1.0,
1014 Energy::Kilojoule => 1000.0,
1015 Energy::Megajoule => 1_000_000.0,
1016 Energy::Ev => 1.602176634e-19,
1017 Energy::KiloEv => 1.602176634e-16,
1018 Energy::MegaEv => 1.602176634e-13,
1019 Energy::Calorie => 4.184,
1020 Energy::Kilocalorie => 4184.0,
1021 Energy::Erg => 1e-7,
1022 Energy::TNT => 4.184e9,
1023 Energy::Custom(force, length) => {
1024 let newtons = match force {
1025 Force::Newton => 1.0,
1026 Force::Dyne => 1e-5,
1027 Force::Pound => 4.448222,
1028 Force::Kg => 9.80665,
1029 Force::Custom(mass, len, time) => {
1030 let kg = mass.clone().convert_to(Mass::Kg).to_kg();
1031 let m = len.clone().convert_to(Length::Meter).to_meters();
1032 let s = time.clone().convert_to(Time::Second).to_seconds();
1033 kg * (m / (s * s))
1034 }
1035 };
1036 let meters = length.clone().convert_to(Length::Meter).to_meters();
1037 newtons * meters
1038 }
1039 }
1040 }
1041
1042 pub fn to_calories(&self) -> f64 {
1043 self.to_joules() / 4.184
1044 }
1045
1046 pub fn to_kilocalories(&self) -> f64 {
1047 self.to_joules() / 4184.0
1048 }
1049
1050 pub fn to_electron_volts(&self) -> f64 {
1051 self.to_joules() / 1.602176634e-19
1052 }
1053
1054 pub fn to_tnt_equivalent(&self) -> f64 {
1055 self.to_joules() / 4.184e9
1056 }
1057}
1058
1059#[derive(Debug, Clone)]
1060pub enum Power {
1061 Watt,
1062 Kilowatt,
1063 Megawatt,
1064 Hp,
1065 Custom(Energy, Time),
1067}
1068
1069impl Power {
1070 pub fn convert_to(self, to: Self) -> Self {
1071 let base_watts = self.to_watts();
1072
1073 match to {
1074 Power::Watt => Power::Watt,
1075 Power::Kilowatt => Power::Custom(
1076 Energy::Joule,
1077 Time::Custom(base_watts / 1000.0, Box::new(Time::Second)),
1078 ),
1079 Power::Megawatt => Power::Custom(
1080 Energy::Joule,
1081 Time::Custom(base_watts / 1_000_000.0, Box::new(Time::Second)),
1082 ),
1083 Power::Hp => Power::Custom(
1084 Energy::Joule,
1085 Time::Custom(base_watts / 745.7, Box::new(Time::Second)),
1086 ),
1087 Power::Custom(energy, time) => {
1088 let target_energy = Energy::Joule.convert_to(energy);
1089 let target_time = Time::Second.convert_to(time);
1090 Power::Custom(target_energy, target_time)
1091 }
1092 }
1093 }
1094
1095 pub fn to_watts(&self) -> f64 {
1096 match self {
1097 Power::Watt => 1.0,
1098 Power::Kilowatt => 1000.0,
1099 Power::Megawatt => 1_000_000.0,
1100 Power::Hp => 745.7,
1101 Power::Custom(energy, time) => {
1102 let joules = energy.to_joules();
1103 let seconds = time.to_seconds();
1104 joules / seconds
1105 }
1106 }
1107 }
1108
1109 pub fn to_kilowatts(&self) -> f64 {
1110 self.to_watts() / 1000.0
1111 }
1112
1113 pub fn to_megawatts(&self) -> f64 {
1114 self.to_watts() / 1_000_000.0
1115 }
1116
1117 pub fn to_horsepower(&self) -> f64 {
1118 self.to_watts() / 745.7
1119 }
1120}
1121
1122#[derive(Debug, Clone)]
1123pub enum Force {
1124 Newton,
1125 Dyne,
1126 Pound,
1127 Kg,
1128 Custom(Mass, Length, Time),
1130}
1131
1132impl Force {
1133 pub fn convert_to(self, to: Self) -> Self {
1134 let base_newtons = self.to_newtons();
1135
1136 match to {
1137 Force::Newton => Force::Newton,
1138 Force::Dyne => Force::Custom(
1139 Mass::Custom(base_newtons / 1e-5, Box::new(Mass::Gram)),
1140 Length::Centimeter,
1141 Time::Second,
1142 ),
1143 Force::Pound => Force::Custom(
1144 Mass::Custom(base_newtons / 4.448222, Box::new(Mass::Pound)),
1145 Length::Meter,
1146 Time::Second,
1147 ),
1148 Force::Kg => Force::Custom(
1149 Mass::Custom(base_newtons / 9.80665, Box::new(Mass::Kg)),
1150 Length::Meter,
1151 Time::Second,
1152 ),
1153 Force::Custom(mass, length, time) => {
1154 let target_mass = Mass::Kg.convert_to(mass);
1155 let target_length = Length::Meter.convert_to(length);
1156 let target_time = Time::Second.convert_to(time);
1157 Force::Custom(target_mass, target_length, target_time)
1158 }
1159 }
1160 }
1161
1162 pub fn to_newtons(&self) -> f64 {
1163 match self {
1164 Force::Newton => 1.0,
1165 Force::Dyne => 1e-5,
1166 Force::Pound => 4.448222,
1167 Force::Kg => 9.80665,
1168 Force::Custom(mass, length, time) => {
1169 let kg = mass.clone().convert_to(Mass::Kg).to_kg();
1170 let meters = length.clone().convert_to(Length::Meter).to_meters();
1171 let seconds = time.clone().convert_to(Time::Second).to_seconds();
1172 kg * (meters / (seconds * seconds))
1173 }
1174 }
1175 }
1176
1177 pub fn to_pounds(&self) -> f64 {
1178 self.to_newtons() / 4.448222
1179 }
1180
1181 pub fn to_dynes(&self) -> f64 {
1182 self.to_newtons() * 100000.0
1183 }
1184
1185 pub fn to_kilograms_force(&self) -> f64 {
1186 self.to_newtons() / 9.80665
1187 }
1188}
1189
1190impl Mass {
1191 pub fn times_acceleration(&self, length: Length, time: Time) -> Force {
1192 Force::Custom(self.clone(), length, time)
1193 }
1194}
1195
1196impl Energy {
1197 pub fn per_time(&self, time: Time) -> Power {
1198 Power::Custom(self.clone(), time)
1199 }
1200}
1201
1202#[derive(Debug, Clone)]
1203pub enum ElectricCharge {
1204 Coulomb,
1205 ElementaryCharge,
1206 Custom(Box<Current>, Time),
1208}
1209
1210impl ElectricCharge {
1211 pub fn convert_to(self, to: Self) -> Self {
1212 let base_coulombs = self.to_coulombs();
1213
1214 match to {
1215 ElectricCharge::Coulomb => ElectricCharge::Coulomb,
1216 ElectricCharge::ElementaryCharge => ElectricCharge::Custom(
1217 Box::new(Current::Custom(
1218 ElectricCharge::Coulomb,
1219 Time::Custom(base_coulombs / 1.602176634e-19, Box::new(Time::Second)),
1220 )),
1221 Time::Second,
1222 ),
1223 ElectricCharge::Custom(current, time) => {
1224 let target_current = Current::Ampere.convert_to(*current);
1225 let target_time = Time::Second.convert_to(time);
1226 ElectricCharge::Custom(Box::new(target_current), target_time)
1227 }
1228 }
1229 }
1230
1231 pub fn to_coulombs(&self) -> f64 {
1232 match self {
1233 ElectricCharge::Coulomb => 1.0,
1234 ElectricCharge::ElementaryCharge => 1.602176634e-19,
1235 ElectricCharge::Custom(current, time) => {
1236 let amperes = match **current {
1237 Current::Ampere => 1.0,
1238 Current::Milliampere => 0.001,
1239 Current::Custom(ref charge, ref t) => {
1240 charge
1241 .clone()
1242 .convert_to(ElectricCharge::Coulomb)
1243 .to_coulombs()
1244 / t.clone().convert_to(Time::Second).to_seconds()
1245 }
1246 };
1247 let seconds = time.to_seconds();
1248 amperes * seconds
1249 }
1250 }
1251 }
1252
1253 pub fn to_elementary_charges(&self) -> f64 {
1254 self.to_coulombs() / 1.602176634e-19
1255 }
1256}
1257
1258#[derive(Debug, Clone)]
1259pub enum Current {
1260 Ampere,
1261 Milliampere,
1262 Custom(ElectricCharge, Time),
1263}
1264
1265impl Current {
1266 pub fn convert_to(self, to: Self) -> Self {
1267 let base_amperes = self.to_amperes();
1268
1269 match to {
1270 Current::Ampere => Current::Ampere,
1271 Current::Milliampere => Current::Custom(
1272 ElectricCharge::Coulomb,
1273 Time::Custom(base_amperes / 0.001, Box::new(Time::Second)),
1274 ),
1275 Current::Custom(charge, time) => {
1276 let target_charge = ElectricCharge::Coulomb.convert_to(charge);
1277 let target_time = Time::Second.convert_to(time);
1278 Current::Custom(target_charge, target_time)
1279 }
1280 }
1281 }
1282
1283 pub fn to_amperes(&self) -> f64 {
1284 match self {
1285 Current::Ampere => 1.0,
1286 Current::Milliampere => 0.001,
1287 Current::Custom(charge, time) => {
1288 let coulombs = charge.to_coulombs();
1289 let seconds = time.to_seconds();
1290 coulombs / seconds
1291 }
1292 }
1293 }
1294
1295 pub fn to_milliamperes(&self) -> f64 {
1296 self.to_amperes() * 1000.0
1297 }
1298}
1299
1300#[derive(Debug, Clone)]
1301pub enum Frequency {
1302 Hertz,
1303 Kilohertz,
1304 Megahertz,
1305 Gigahertz,
1306 Custom(Time),
1308}
1309
1310impl Frequency {
1311 pub fn convert_to(self, to: Self) -> Self {
1312 let base_hertz = self.to_hertz();
1313
1314 match to {
1315 Frequency::Hertz => Frequency::Hertz,
1316 Frequency::Kilohertz => {
1317 Frequency::Custom(Time::Custom(base_hertz / 1000.0, Box::new(Time::Second)))
1318 }
1319 Frequency::Megahertz => Frequency::Custom(Time::Custom(
1320 base_hertz / 1_000_000.0,
1321 Box::new(Time::Second),
1322 )),
1323 Frequency::Gigahertz => Frequency::Custom(Time::Custom(
1324 base_hertz / 1_000_000_000.0,
1325 Box::new(Time::Second),
1326 )),
1327 Frequency::Custom(time) => {
1328 let target_time = Time::Second.convert_to(time);
1329 Frequency::Custom(target_time)
1330 }
1331 }
1332 }
1333
1334 pub fn to_hertz(&self) -> f64 {
1335 match self {
1336 Frequency::Hertz => 1.0,
1337 Frequency::Kilohertz => 1000.0,
1338 Frequency::Megahertz => 1_000_000.0,
1339 Frequency::Gigahertz => 1_000_000_000.0,
1340 Frequency::Custom(time) => 1.0 / time.to_seconds(),
1341 }
1342 }
1343
1344 pub fn to_kilohertz(&self) -> f64 {
1345 self.to_hertz() / 1000.0
1346 }
1347
1348 pub fn to_megahertz(&self) -> f64 {
1349 self.to_hertz() / 1_000_000.0
1350 }
1351
1352 pub fn to_gigahertz(&self) -> f64 {
1353 self.to_hertz() / 1_000_000_000.0
1354 }
1355}
1356
1357#[derive(Debug, Clone)]
1358pub enum Acceleration {
1359 MetersPerSecondSquared,
1360 G, Custom(Length, Time, Time),
1363}
1364
1365impl Acceleration {
1366 pub fn convert_to(self, to: Self) -> Self {
1367 let base_mps2 = self.to_mps2();
1369
1370 match to {
1371 Acceleration::MetersPerSecondSquared => Acceleration::MetersPerSecondSquared,
1372 Acceleration::G => Acceleration::Custom(
1373 Length::Custom(base_mps2 / 9.80665, Box::new(Length::Meter)),
1374 Time::Second,
1375 Time::Second,
1376 ),
1377 Acceleration::Custom(length, time1, time2) => {
1378 let target_length = Length::Meter.convert_to(length);
1379 let target_time1 = Time::Second.convert_to(time1);
1380 let target_time2 = Time::Second.convert_to(time2);
1381 Acceleration::Custom(target_length, target_time1, target_time2)
1382 }
1383 }
1384 }
1385
1386 pub fn to_mps2(&self) -> f64 {
1387 match self {
1388 Acceleration::MetersPerSecondSquared => 1.0,
1389 Acceleration::G => 9.80665,
1390 Acceleration::Custom(length, time1, time2) => {
1391 let meters = length.clone().convert_to(Length::Meter).to_meters();
1392 let seconds1 = time1.clone().convert_to(Time::Second).to_seconds();
1393 let seconds2 = time2.clone().convert_to(Time::Second).to_seconds();
1394 meters / (seconds1 * seconds2)
1395 }
1396 }
1397 }
1398
1399 pub fn to_g(&self) -> f64 {
1400 self.to_mps2() / 9.80665
1401 }
1402}
1403
1404impl Time {
1405 pub fn frequency(&self) -> Frequency {
1406 Frequency::Custom(self.clone())
1407 }
1408}
1409
1410impl Length {
1411 pub fn per_time_squared(&self, time1: Time, time2: Time) -> Acceleration {
1412 Acceleration::Custom(self.clone(), time1, time2)
1413 }
1414}