Skip to main content

space_units/quantities/
mod.rs

1use core::fmt;
2
3/// A display helper returned by `Quantity::display_as(Unit)`.
4///
5/// Respects all `fmt::Formatter` flags (precision, width, alignment, etc.):
6/// ```
7/// # use space_units::prelude::*;
8/// let d = 384_400.km();
9/// assert_eq!(format!("{:.2}", d.display_as(LengthUnit::Kilometer)), "384400.00 km");
10/// ```
11#[derive(Debug, Clone, Copy)]
12pub struct DisplayWithUnit {
13    pub(crate) value: f64,
14    pub(crate) symbol: &'static str,
15}
16
17impl fmt::Display for DisplayWithUnit {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        fmt::Display::fmt(&self.value, f)?;
20        write!(f, " {}", self.symbol)
21    }
22}
23
24macro_rules! impl_common_ops {
25    ($t:ty) => {
26        impl core::ops::Add for $t {
27            type Output = Self;
28            fn add(self, rhs: Self) -> Self {
29                Self(self.0 + rhs.0)
30            }
31        }
32
33        impl core::ops::Sub for $t {
34            type Output = Self;
35            fn sub(self, rhs: Self) -> Self {
36                Self(self.0 - rhs.0)
37            }
38        }
39
40        impl core::ops::Neg for $t {
41            type Output = Self;
42            fn neg(self) -> Self {
43                Self(-self.0)
44            }
45        }
46
47        impl core::ops::Mul<f64> for $t {
48            type Output = Self;
49            fn mul(self, rhs: f64) -> Self {
50                Self(self.0 * rhs)
51            }
52        }
53
54        impl core::ops::Mul<$t> for f64 {
55            type Output = $t;
56            #[allow(clippy::suspicious_arithmetic_impl)]
57            fn mul(self, rhs: $t) -> $t {
58                // Reverse multiplication: scalar * quantity = quantity * scalar
59                rhs * self
60            }
61        }
62
63        impl core::ops::Div<f64> for $t {
64            type Output = Self;
65            fn div(self, rhs: f64) -> Self {
66                Self(self.0 / rhs)
67            }
68        }
69
70        impl core::ops::Div for $t {
71            type Output = f64;
72            fn div(self, rhs: Self) -> f64 {
73                self.0 / rhs.0
74            }
75        }
76
77        impl core::ops::AddAssign for $t {
78            fn add_assign(&mut self, rhs: Self) {
79                self.0 += rhs.0;
80            }
81        }
82
83        impl core::ops::SubAssign for $t {
84            fn sub_assign(&mut self, rhs: Self) {
85                self.0 -= rhs.0;
86            }
87        }
88
89        impl core::ops::MulAssign<f64> for $t {
90            fn mul_assign(&mut self, rhs: f64) {
91                self.0 *= rhs;
92            }
93        }
94
95        impl core::ops::DivAssign<f64> for $t {
96            fn div_assign(&mut self, rhs: f64) {
97                self.0 /= rhs;
98            }
99        }
100
101        impl core::iter::Sum for $t {
102            fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
103                Self(iter.map(|v| v.0).sum::<f64>())
104            }
105        }
106    };
107}
108
109macro_rules! impl_quantity_display {
110    ($t:ty, $symbol:expr) => {
111        impl core::fmt::Display for $t {
112            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113                core::fmt::Display::fmt(&self.0, f)?;
114                f.write_str(concat!(" ", $symbol))
115            }
116        }
117    };
118}
119
120// Domain modules — macro must be defined before these declarations.
121mod angular;
122mod electromagnetic;
123mod energy;
124mod geometry;
125mod mechanics;
126mod orbital;
127mod propulsion;
128mod radiation;
129mod thermal;
130mod waves;
131
132// Re-export everything so `use space_units::quantities::*` still works.
133pub use angular::*;
134pub use electromagnetic::*;
135pub use energy::*;
136pub use geometry::*;
137pub use mechanics::*;
138pub use orbital::*;
139pub use propulsion::*;
140pub use radiation::*;
141pub use thermal::*;
142pub use waves::*;
143
144// =========================================================================
145// Typed arithmetic graph
146// =========================================================================
147
148use core::ops::{Div, Mul};
149
150// --- Mechanics ---
151
152// Length / Time -> Velocity
153impl Div<Time> for Length {
154    type Output = Velocity;
155    fn div(self, rhs: Time) -> Velocity {
156        Velocity(self.0 / rhs.0)
157    }
158}
159
160// Length / Velocity -> Time
161impl Div<Velocity> for Length {
162    type Output = Time;
163    fn div(self, rhs: Velocity) -> Time {
164        Time(self.0 / rhs.0)
165    }
166}
167
168// Velocity * Time -> Length
169impl Mul<Time> for Velocity {
170    type Output = Length;
171    fn mul(self, rhs: Time) -> Length {
172        Length(self.0 * rhs.0)
173    }
174}
175
176impl Mul<Velocity> for Time {
177    type Output = Length;
178    fn mul(self, rhs: Velocity) -> Length {
179        Length(self.0 * rhs.0)
180    }
181}
182
183// Acceleration * Time -> Velocity
184impl Mul<Time> for Acceleration {
185    type Output = Velocity;
186    fn mul(self, rhs: Time) -> Velocity {
187        Velocity(self.0 * rhs.0)
188    }
189}
190
191impl Mul<Acceleration> for Time {
192    type Output = Velocity;
193    fn mul(self, rhs: Acceleration) -> Velocity {
194        Velocity(self.0 * rhs.0)
195    }
196}
197
198// Velocity / Time -> Acceleration
199impl Div<Time> for Velocity {
200    type Output = Acceleration;
201    fn div(self, rhs: Time) -> Acceleration {
202        Acceleration(self.0 / rhs.0)
203    }
204}
205
206// Mass * Acceleration -> Force
207impl Mul<Acceleration> for Mass {
208    type Output = Force;
209    fn mul(self, rhs: Acceleration) -> Force {
210        Force(self.0 * rhs.0)
211    }
212}
213
214impl Mul<Mass> for Acceleration {
215    type Output = Force;
216    fn mul(self, rhs: Mass) -> Force {
217        Force(self.0 * rhs.0)
218    }
219}
220
221// Force / Mass -> Acceleration
222impl Div<Mass> for Force {
223    type Output = Acceleration;
224    fn div(self, rhs: Mass) -> Acceleration {
225        Acceleration(self.0 / rhs.0)
226    }
227}
228
229// Force / Acceleration -> Mass
230impl Div<Acceleration> for Force {
231    type Output = Mass;
232    fn div(self, rhs: Acceleration) -> Mass {
233        Mass(self.0 / rhs.0)
234    }
235}
236
237// Force * Time -> Impulse
238impl Mul<Time> for Force {
239    type Output = Impulse;
240    fn mul(self, rhs: Time) -> Impulse {
241        Impulse(self.0 * rhs.0)
242    }
243}
244
245impl Mul<Force> for Time {
246    type Output = Impulse;
247    fn mul(self, rhs: Force) -> Impulse {
248        Impulse(self.0 * rhs.0)
249    }
250}
251
252// Mass * Velocity -> Momentum
253impl Mul<Velocity> for Mass {
254    type Output = Momentum;
255    fn mul(self, rhs: Velocity) -> Momentum {
256        Momentum(self.0 * rhs.0)
257    }
258}
259
260impl Mul<Mass> for Velocity {
261    type Output = Momentum;
262    fn mul(self, rhs: Mass) -> Momentum {
263        Momentum(self.0 * rhs.0)
264    }
265}
266
267// Impulse / Mass -> Velocity
268impl Div<Mass> for Impulse {
269    type Output = Velocity;
270    fn div(self, rhs: Mass) -> Velocity {
271        Velocity(self.0 / rhs.0)
272    }
273}
274
275// Momentum / Mass -> Velocity
276impl Div<Mass> for Momentum {
277    type Output = Velocity;
278    fn div(self, rhs: Mass) -> Velocity {
279        Velocity(self.0 / rhs.0)
280    }
281}
282
283// Momentum / Velocity -> Mass
284impl Div<Velocity> for Momentum {
285    type Output = Mass;
286    fn div(self, rhs: Velocity) -> Mass {
287        Mass(self.0 / rhs.0)
288    }
289}
290
291// --- Geometry ---
292
293impl Mul<Self> for Length {
294    type Output = Area;
295    fn mul(self, rhs: Self) -> Area {
296        Area(self.0 * rhs.0)
297    }
298}
299
300impl Div<Length> for Area {
301    type Output = Length;
302    fn div(self, rhs: Length) -> Length {
303        Length(self.0 / rhs.0)
304    }
305}
306
307impl Mul<Length> for Area {
308    type Output = Volume;
309    fn mul(self, rhs: Length) -> Volume {
310        Volume(self.0 * rhs.0)
311    }
312}
313
314impl Mul<Area> for Length {
315    type Output = Volume;
316    fn mul(self, rhs: Area) -> Volume {
317        Volume(self.0 * rhs.0)
318    }
319}
320
321impl Div<Length> for Volume {
322    type Output = Area;
323    fn div(self, rhs: Length) -> Area {
324        Area(self.0 / rhs.0)
325    }
326}
327
328impl Div<Area> for Volume {
329    type Output = Length;
330    fn div(self, rhs: Area) -> Length {
331        Length(self.0 / rhs.0)
332    }
333}
334
335// --- Density and pressure ---
336
337impl Div<Volume> for Mass {
338    type Output = Density;
339    fn div(self, rhs: Volume) -> Density {
340        Density(self.0 / rhs.0)
341    }
342}
343
344impl Mul<Volume> for Density {
345    type Output = Mass;
346    fn mul(self, rhs: Volume) -> Mass {
347        Mass(self.0 * rhs.0)
348    }
349}
350
351impl Mul<Density> for Volume {
352    type Output = Mass;
353    fn mul(self, rhs: Density) -> Mass {
354        Mass(self.0 * rhs.0)
355    }
356}
357
358impl Div<Area> for Force {
359    type Output = Pressure;
360    fn div(self, rhs: Area) -> Pressure {
361        Pressure(self.0 / rhs.0)
362    }
363}
364
365impl Mul<Area> for Pressure {
366    type Output = Force;
367    fn mul(self, rhs: Area) -> Force {
368        Force(self.0 * rhs.0)
369    }
370}
371
372impl Mul<Pressure> for Area {
373    type Output = Force;
374    fn mul(self, rhs: Pressure) -> Force {
375        Force(self.0 * rhs.0)
376    }
377}
378
379// --- Energy and power ---
380
381impl Mul<Length> for Force {
382    type Output = Energy;
383    fn mul(self, rhs: Length) -> Energy {
384        Energy(self.0 * rhs.0)
385    }
386}
387
388impl Mul<Force> for Length {
389    type Output = Energy;
390    fn mul(self, rhs: Force) -> Energy {
391        Energy(self.0 * rhs.0)
392    }
393}
394
395impl Div<Time> for Energy {
396    type Output = Power;
397    fn div(self, rhs: Time) -> Power {
398        Power(self.0 / rhs.0)
399    }
400}
401
402impl Mul<Time> for Power {
403    type Output = Energy;
404    fn mul(self, rhs: Time) -> Energy {
405        Energy(self.0 * rhs.0)
406    }
407}
408
409impl Div<Length> for Energy {
410    type Output = Force;
411    fn div(self, rhs: Length) -> Force {
412        Force(self.0 / rhs.0)
413    }
414}
415
416impl Div<Mass> for Energy {
417    type Output = SpecificEnergy;
418    fn div(self, rhs: Mass) -> SpecificEnergy {
419        SpecificEnergy(self.0 / rhs.0)
420    }
421}
422
423// --- Orbital mechanics ---
424
425impl Div<Length> for GravitationalParameter {
426    type Output = SpecificEnergy;
427    fn div(self, rhs: Length) -> SpecificEnergy {
428        SpecificEnergy(self.0 / rhs.0)
429    }
430}
431
432impl Div<Area> for GravitationalParameter {
433    type Output = Acceleration;
434    fn div(self, rhs: Area) -> Acceleration {
435        Acceleration(self.0 / rhs.0)
436    }
437}
438
439impl Mul<Self> for Velocity {
440    type Output = SpecificEnergy;
441    fn mul(self, rhs: Self) -> SpecificEnergy {
442        SpecificEnergy(self.0 * rhs.0)
443    }
444}
445
446impl Mul<Velocity> for Length {
447    type Output = SpecificAngularMomentum;
448    fn mul(self, rhs: Velocity) -> SpecificAngularMomentum {
449        SpecificAngularMomentum(self.0 * rhs.0)
450    }
451}
452
453impl Mul<Length> for Velocity {
454    type Output = SpecificAngularMomentum;
455    fn mul(self, rhs: Length) -> SpecificAngularMomentum {
456        SpecificAngularMomentum(self.0 * rhs.0)
457    }
458}
459
460impl Div<Time> for Area {
461    type Output = SpecificAngularMomentum;
462    fn div(self, rhs: Time) -> SpecificAngularMomentum {
463        SpecificAngularMomentum(self.0 / rhs.0)
464    }
465}
466
467// --- Angular motion ---
468
469impl Div<Time> for Angle {
470    type Output = AngularVelocity;
471    fn div(self, rhs: Time) -> AngularVelocity {
472        AngularVelocity(self.0 / rhs.0)
473    }
474}
475
476impl Mul<Time> for AngularVelocity {
477    type Output = Angle;
478    fn mul(self, rhs: Time) -> Angle {
479        Angle(self.0 * rhs.0)
480    }
481}
482
483impl Mul<AngularVelocity> for Time {
484    type Output = Angle;
485    fn mul(self, rhs: AngularVelocity) -> Angle {
486        Angle(self.0 * rhs.0)
487    }
488}
489
490impl Div<Time> for AngularVelocity {
491    type Output = AngularAcceleration;
492    fn div(self, rhs: Time) -> AngularAcceleration {
493        AngularAcceleration(self.0 / rhs.0)
494    }
495}
496
497impl Mul<AngularAcceleration> for MomentOfInertia {
498    type Output = Torque;
499    fn mul(self, rhs: AngularAcceleration) -> Torque {
500        Torque(self.0 * rhs.0)
501    }
502}
503
504impl Mul<MomentOfInertia> for AngularAcceleration {
505    type Output = Torque;
506    fn mul(self, rhs: MomentOfInertia) -> Torque {
507        Torque(self.0 * rhs.0)
508    }
509}
510
511impl Div<AngularAcceleration> for Torque {
512    type Output = MomentOfInertia;
513    fn div(self, rhs: AngularAcceleration) -> MomentOfInertia {
514        MomentOfInertia(self.0 / rhs.0)
515    }
516}
517
518impl Mul<Time> for Torque {
519    type Output = AngularMomentum;
520    fn mul(self, rhs: Time) -> AngularMomentum {
521        AngularMomentum(self.0 * rhs.0)
522    }
523}
524
525impl Div<Time> for AngularMomentum {
526    type Output = Torque;
527    fn div(self, rhs: Time) -> Torque {
528        Torque(self.0 / rhs.0)
529    }
530}
531
532// --- Propulsion ---
533
534// Mass / Time -> MassFlowRate
535impl Div<Time> for Mass {
536    type Output = MassFlowRate;
537    fn div(self, rhs: Time) -> MassFlowRate {
538        MassFlowRate(self.0 / rhs.0)
539    }
540}
541
542// MassFlowRate * Time -> Mass
543impl Mul<Time> for MassFlowRate {
544    type Output = Mass;
545    fn mul(self, rhs: Time) -> Mass {
546        Mass(self.0 * rhs.0)
547    }
548}
549
550impl Mul<MassFlowRate> for Time {
551    type Output = Mass;
552    fn mul(self, rhs: MassFlowRate) -> Mass {
553        Mass(self.0 * rhs.0)
554    }
555}
556
557// MassFlowRate * Velocity -> Force (thrust: F = ṁVe)
558impl Mul<Velocity> for MassFlowRate {
559    type Output = Force;
560    fn mul(self, rhs: Velocity) -> Force {
561        Force(self.0 * rhs.0)
562    }
563}
564
565impl Mul<MassFlowRate> for Velocity {
566    type Output = Force;
567    fn mul(self, rhs: MassFlowRate) -> Force {
568        Force(self.0 * rhs.0)
569    }
570}
571
572// Force / MassFlowRate -> Velocity
573impl Div<MassFlowRate> for Force {
574    type Output = Velocity;
575    fn div(self, rhs: MassFlowRate) -> Velocity {
576        Velocity(self.0 / rhs.0)
577    }
578}
579
580// Force / Velocity -> MassFlowRate
581impl Div<Velocity> for Force {
582    type Output = MassFlowRate;
583    fn div(self, rhs: Velocity) -> MassFlowRate {
584        MassFlowRate(self.0 / rhs.0)
585    }
586}
587
588// --- Electromagnetic ---
589
590// ElectricCharge / Time -> ElectricCurrent
591impl Div<Time> for ElectricCharge {
592    type Output = ElectricCurrent;
593    fn div(self, rhs: Time) -> ElectricCurrent {
594        ElectricCurrent(self.0 / rhs.0)
595    }
596}
597
598// ElectricCurrent * Time -> ElectricCharge
599impl Mul<Time> for ElectricCurrent {
600    type Output = ElectricCharge;
601    fn mul(self, rhs: Time) -> ElectricCharge {
602        ElectricCharge(self.0 * rhs.0)
603    }
604}
605
606impl Mul<ElectricCurrent> for Time {
607    type Output = ElectricCharge;
608    fn mul(self, rhs: ElectricCurrent) -> ElectricCharge {
609        ElectricCharge(self.0 * rhs.0)
610    }
611}
612
613// Power / ElectricCurrent -> Voltage
614impl Div<ElectricCurrent> for Power {
615    type Output = Voltage;
616    fn div(self, rhs: ElectricCurrent) -> Voltage {
617        Voltage(self.0 / rhs.0)
618    }
619}
620
621// Voltage * ElectricCurrent -> Power
622impl Mul<ElectricCurrent> for Voltage {
623    type Output = Power;
624    fn mul(self, rhs: ElectricCurrent) -> Power {
625        Power(self.0 * rhs.0)
626    }
627}
628
629impl Mul<Voltage> for ElectricCurrent {
630    type Output = Power;
631    fn mul(self, rhs: Voltage) -> Power {
632        Power(self.0 * rhs.0)
633    }
634}
635
636// Energy / ElectricCharge -> Voltage
637impl Div<ElectricCharge> for Energy {
638    type Output = Voltage;
639    fn div(self, rhs: ElectricCharge) -> Voltage {
640        Voltage(self.0 / rhs.0)
641    }
642}
643
644// Voltage * ElectricCharge -> Energy
645impl Mul<ElectricCharge> for Voltage {
646    type Output = Energy;
647    fn mul(self, rhs: ElectricCharge) -> Energy {
648        Energy(self.0 * rhs.0)
649    }
650}
651
652impl Mul<Voltage> for ElectricCharge {
653    type Output = Energy;
654    fn mul(self, rhs: Voltage) -> Energy {
655        Energy(self.0 * rhs.0)
656    }
657}
658
659// Voltage / ElectricCurrent -> Resistance
660impl Div<ElectricCurrent> for Voltage {
661    type Output = Resistance;
662    fn div(self, rhs: ElectricCurrent) -> Resistance {
663        Resistance(self.0 / rhs.0)
664    }
665}
666
667// ElectricCurrent * Resistance -> Voltage
668impl Mul<Resistance> for ElectricCurrent {
669    type Output = Voltage;
670    fn mul(self, rhs: Resistance) -> Voltage {
671        Voltage(self.0 * rhs.0)
672    }
673}
674
675impl Mul<ElectricCurrent> for Resistance {
676    type Output = Voltage;
677    fn mul(self, rhs: ElectricCurrent) -> Voltage {
678        Voltage(self.0 * rhs.0)
679    }
680}
681
682// ElectricCharge / Voltage -> Capacitance
683impl Div<Voltage> for ElectricCharge {
684    type Output = Capacitance;
685    fn div(self, rhs: Voltage) -> Capacitance {
686        Capacitance(self.0 / rhs.0)
687    }
688}
689
690// Capacitance * Voltage -> ElectricCharge
691impl Mul<Voltage> for Capacitance {
692    type Output = ElectricCharge;
693    fn mul(self, rhs: Voltage) -> ElectricCharge {
694        ElectricCharge(self.0 * rhs.0)
695    }
696}
697
698impl Mul<Capacitance> for Voltage {
699    type Output = ElectricCharge;
700    fn mul(self, rhs: Capacitance) -> ElectricCharge {
701        ElectricCharge(self.0 * rhs.0)
702    }
703}
704
705// MagneticFluxDensity * Area -> MagneticFlux
706impl Mul<Area> for MagneticFluxDensity {
707    type Output = MagneticFlux;
708    fn mul(self, rhs: Area) -> MagneticFlux {
709        MagneticFlux(self.0 * rhs.0)
710    }
711}
712
713impl Mul<MagneticFluxDensity> for Area {
714    type Output = MagneticFlux;
715    fn mul(self, rhs: MagneticFluxDensity) -> MagneticFlux {
716        MagneticFlux(self.0 * rhs.0)
717    }
718}
719
720// MagneticFlux / Area -> MagneticFluxDensity
721impl Div<Area> for MagneticFlux {
722    type Output = MagneticFluxDensity;
723    fn div(self, rhs: Area) -> MagneticFluxDensity {
724        MagneticFluxDensity(self.0 / rhs.0)
725    }
726}
727
728// MagneticFlux / ElectricCurrent -> Inductance
729impl Div<ElectricCurrent> for MagneticFlux {
730    type Output = Inductance;
731    fn div(self, rhs: ElectricCurrent) -> Inductance {
732        Inductance(self.0 / rhs.0)
733    }
734}
735
736// Inductance * ElectricCurrent -> MagneticFlux
737impl Mul<ElectricCurrent> for Inductance {
738    type Output = MagneticFlux;
739    fn mul(self, rhs: ElectricCurrent) -> MagneticFlux {
740        MagneticFlux(self.0 * rhs.0)
741    }
742}
743
744impl Mul<Inductance> for ElectricCurrent {
745    type Output = MagneticFlux;
746    fn mul(self, rhs: Inductance) -> MagneticFlux {
747        MagneticFlux(self.0 * rhs.0)
748    }
749}
750
751// --- Thermal ---
752
753// Power / Area -> HeatFlux
754impl Div<Area> for Power {
755    type Output = HeatFlux;
756    fn div(self, rhs: Area) -> HeatFlux {
757        HeatFlux(self.0 / rhs.0)
758    }
759}
760
761// HeatFlux * Area -> Power
762impl Mul<Area> for HeatFlux {
763    type Output = Power;
764    fn mul(self, rhs: Area) -> Power {
765        Power(self.0 * rhs.0)
766    }
767}
768
769impl Mul<HeatFlux> for Area {
770    type Output = Power;
771    fn mul(self, rhs: HeatFlux) -> Power {
772        Power(self.0 * rhs.0)
773    }
774}