Skip to main content

space_units/
numeric_ext.rs

1use crate::quantities::{
2    Acceleration, Angle, Area, Capacitance, ElectricCharge, ElectricCurrent, Energy, Force,
3    Frequency, Inductance, Length, MagneticFlux, MagneticFluxDensity, Mass, MassFlowRate, Power,
4    Pressure, Resistance, SolidAngle, Temperature, Time, Velocity, Voltage, Volume,
5};
6
7/// Extension methods on numeric literals for constructing typed quantities.
8///
9/// This is the primary construction UX — it turns bare numbers into typed
10/// quantities so code reads like English:
11///
12/// ```
13/// use space_units::prelude::*;
14///
15/// let distance = 384_400.km();   // Length
16/// let time     = 3.5.hours();    // Time
17/// let angle    = 51.6.deg();     // Angle
18/// ```
19///
20/// Implemented for `f64`, `f32`, `i32`, `i64`, `u32`, and `u64`.
21/// Integer types convert to `f64` internally.
22pub trait NumericExt {
23    /// Create a [`Length`] in meters.
24    fn m(self) -> Length;
25    /// Create a [`Length`] in kilometers.
26    fn km(self) -> Length;
27    /// Create a [`Length`] in astronomical units.
28    fn au(self) -> Length;
29    /// Create a [`Length`] in feet.
30    fn ft(self) -> Length;
31
32    /// Create a [`Time`] in seconds.
33    fn seconds(self) -> Time;
34    /// Create a [`Time`] in minutes.
35    fn minutes(self) -> Time;
36    /// Create a [`Time`] in hours.
37    fn hours(self) -> Time;
38    /// Create a [`Time`] in days (86 400 s).
39    fn days(self) -> Time;
40
41    /// Create a [`Mass`] in kilograms.
42    fn kg(self) -> Mass;
43    /// Create a [`Mass`] in grams.
44    fn g(self) -> Mass;
45    /// Create a [`Mass`] in pounds (avoirdupois).
46    fn lb(self) -> Mass;
47
48    /// Create an [`Angle`] in radians.
49    fn rad(self) -> Angle;
50    /// Create an [`Angle`] in degrees.
51    fn deg(self) -> Angle;
52    /// Create an [`Angle`] in revolutions (1 rev = 2π rad).
53    fn rev(self) -> Angle;
54
55    /// Create a [`Velocity`] in meters per second.
56    fn mps(self) -> Velocity;
57    /// Create a [`Velocity`] in kilometers per second.
58    fn kmps(self) -> Velocity;
59
60    /// Create an [`Acceleration`] in meters per second squared.
61    fn mps2(self) -> Acceleration;
62    /// Create an [`Acceleration`] in standard gravities (1 g₀ = 9.80665 m/s²).
63    fn g0(self) -> Acceleration;
64
65    /// Create a [`Force`] in Newtons.
66    fn n(self) -> Force;
67    /// Create a [`Force`] in kilonewtons.
68    fn kn(self) -> Force;
69    /// Create a [`Force`] in pounds-force.
70    fn lbf(self) -> Force;
71
72    /// Create an [`Area`] in square meters.
73    fn m2(self) -> Area;
74    /// Create a [`Volume`] in cubic meters.
75    fn m3(self) -> Volume;
76
77    /// Create an [`Energy`] in Joules.
78    fn j(self) -> Energy;
79    /// Create a [`Power`] in Watts.
80    fn w(self) -> Power;
81
82    /// Create a [`Pressure`] in Pascals.
83    fn pa(self) -> Pressure;
84    /// Create a [`Pressure`] in bar (1 bar = 100 000 Pa).
85    fn bar(self) -> Pressure;
86
87    /// Create a [`Frequency`] in Hertz.
88    fn hz(self) -> Frequency;
89    /// Create a [`Frequency`] in kilohertz.
90    fn khz(self) -> Frequency;
91    /// Create a [`Frequency`] in megahertz.
92    fn mhz(self) -> Frequency;
93    /// Create a [`Frequency`] in gigahertz.
94    fn ghz(self) -> Frequency;
95
96    /// Create an [`ElectricCurrent`] in Amperes.
97    fn amperes(self) -> ElectricCurrent;
98    /// Create a [`Voltage`] in Volts.
99    fn volts(self) -> Voltage;
100    /// Create a [`Resistance`] in Ohms.
101    fn ohms(self) -> Resistance;
102    /// Create a [`MagneticFluxDensity`] in Tesla.
103    fn tesla(self) -> MagneticFluxDensity;
104    /// Create an [`ElectricCharge`] in Coulombs.
105    fn coulombs(self) -> ElectricCharge;
106    /// Create a [`Capacitance`] in Farads.
107    fn farads(self) -> Capacitance;
108    /// Create an [`Inductance`] in Henrys.
109    fn henrys(self) -> Inductance;
110    /// Create a [`MagneticFlux`] in Webers.
111    fn webers(self) -> MagneticFlux;
112
113    /// Create a [`Temperature`] in Kelvin.
114    fn kelvin(self) -> Temperature;
115
116    /// Create a [`MassFlowRate`] in kilograms per second.
117    fn kgps(self) -> MassFlowRate;
118
119    /// Create a [`SolidAngle`] in steradians.
120    fn sr(self) -> SolidAngle;
121}
122
123impl NumericExt for f64 {
124    fn m(self) -> Length {
125        Length::from_m(self)
126    }
127
128    fn km(self) -> Length {
129        Length::from_km(self)
130    }
131
132    fn au(self) -> Length {
133        Length::from_au(self)
134    }
135
136    fn ft(self) -> Length {
137        Length::from_ft(self)
138    }
139
140    fn seconds(self) -> Time {
141        Time::from_s(self)
142    }
143
144    fn minutes(self) -> Time {
145        Time::from_min(self)
146    }
147
148    fn hours(self) -> Time {
149        Time::from_hours(self)
150    }
151
152    fn days(self) -> Time {
153        Time::from_days(self)
154    }
155
156    fn kg(self) -> Mass {
157        Mass::from_kg(self)
158    }
159
160    fn g(self) -> Mass {
161        Mass::from_g(self)
162    }
163
164    fn lb(self) -> Mass {
165        Mass::from_lb(self)
166    }
167
168    fn rad(self) -> Angle {
169        Angle::from_rad(self)
170    }
171
172    fn deg(self) -> Angle {
173        Angle::from_deg(self)
174    }
175
176    fn rev(self) -> Angle {
177        Angle::from_rev(self)
178    }
179
180    fn mps(self) -> Velocity {
181        Velocity::from_mps(self)
182    }
183
184    fn kmps(self) -> Velocity {
185        Velocity::from_kmps(self)
186    }
187
188    fn mps2(self) -> Acceleration {
189        Acceleration::from_mps2(self)
190    }
191
192    fn g0(self) -> Acceleration {
193        Acceleration::from_g(self)
194    }
195
196    fn n(self) -> Force {
197        Force::from_n(self)
198    }
199
200    fn kn(self) -> Force {
201        Force::from_kn(self)
202    }
203
204    fn lbf(self) -> Force {
205        Force::from_lbf(self)
206    }
207
208    fn m2(self) -> Area {
209        Area::from_m2(self)
210    }
211
212    fn m3(self) -> Volume {
213        Volume::from_m3(self)
214    }
215
216    fn j(self) -> Energy {
217        Energy::from_j(self)
218    }
219
220    fn w(self) -> Power {
221        Power::from_w(self)
222    }
223
224    fn pa(self) -> Pressure {
225        Pressure::from_pa(self)
226    }
227
228    fn bar(self) -> Pressure {
229        Pressure::from_bar(self)
230    }
231
232    fn hz(self) -> Frequency {
233        Frequency::from_hz(self)
234    }
235
236    fn khz(self) -> Frequency {
237        Frequency::from_khz(self)
238    }
239
240    fn mhz(self) -> Frequency {
241        Frequency::from_mhz(self)
242    }
243
244    fn ghz(self) -> Frequency {
245        Frequency::from_ghz(self)
246    }
247
248    fn amperes(self) -> ElectricCurrent {
249        ElectricCurrent::from_a(self)
250    }
251
252    fn volts(self) -> Voltage {
253        Voltage::from_v(self)
254    }
255
256    fn ohms(self) -> Resistance {
257        Resistance::from_ohm(self)
258    }
259
260    fn tesla(self) -> MagneticFluxDensity {
261        MagneticFluxDensity::from_t(self)
262    }
263
264    fn coulombs(self) -> ElectricCharge {
265        ElectricCharge::from_c(self)
266    }
267
268    fn farads(self) -> Capacitance {
269        Capacitance::from_f(self)
270    }
271
272    fn henrys(self) -> Inductance {
273        Inductance::from_h(self)
274    }
275
276    fn webers(self) -> MagneticFlux {
277        MagneticFlux::from_wb(self)
278    }
279
280    fn kelvin(self) -> Temperature {
281        Temperature::from_k(self)
282    }
283
284    fn kgps(self) -> MassFlowRate {
285        MassFlowRate::from_kgps(self)
286    }
287
288    fn sr(self) -> SolidAngle {
289        SolidAngle::from_sr(self)
290    }
291}
292
293// Blanket macro for all non-f64 numeric types. Delegates every method to the
294// canonical f64 impl via `self as f64`. The `#[allow]` covers:
295//   - cast_lossless  : f32/i32/u32 → f64 (lossless but clippy prefers From)
296//   - cast_precision_loss : i64/u64 → f64 (intentionally lossy — documented on NumericExt)
297macro_rules! impl_numeric_ext_for {
298    ($t:ty) => {
299        #[allow(clippy::cast_lossless, clippy::cast_precision_loss)]
300        impl NumericExt for $t {
301            fn m(self) -> Length {
302                <f64 as NumericExt>::m(self as f64)
303            }
304
305            fn km(self) -> Length {
306                <f64 as NumericExt>::km(self as f64)
307            }
308
309            fn au(self) -> Length {
310                <f64 as NumericExt>::au(self as f64)
311            }
312
313            fn ft(self) -> Length {
314                <f64 as NumericExt>::ft(self as f64)
315            }
316
317            fn seconds(self) -> Time {
318                <f64 as NumericExt>::seconds(self as f64)
319            }
320
321            fn minutes(self) -> Time {
322                <f64 as NumericExt>::minutes(self as f64)
323            }
324
325            fn hours(self) -> Time {
326                <f64 as NumericExt>::hours(self as f64)
327            }
328
329            fn days(self) -> Time {
330                <f64 as NumericExt>::days(self as f64)
331            }
332
333            fn kg(self) -> Mass {
334                <f64 as NumericExt>::kg(self as f64)
335            }
336
337            fn g(self) -> Mass {
338                <f64 as NumericExt>::g(self as f64)
339            }
340
341            fn lb(self) -> Mass {
342                <f64 as NumericExt>::lb(self as f64)
343            }
344
345            fn rad(self) -> Angle {
346                <f64 as NumericExt>::rad(self as f64)
347            }
348
349            fn deg(self) -> Angle {
350                <f64 as NumericExt>::deg(self as f64)
351            }
352
353            fn rev(self) -> Angle {
354                <f64 as NumericExt>::rev(self as f64)
355            }
356
357            fn mps(self) -> Velocity {
358                <f64 as NumericExt>::mps(self as f64)
359            }
360
361            fn kmps(self) -> Velocity {
362                <f64 as NumericExt>::kmps(self as f64)
363            }
364
365            fn mps2(self) -> Acceleration {
366                <f64 as NumericExt>::mps2(self as f64)
367            }
368
369            fn g0(self) -> Acceleration {
370                <f64 as NumericExt>::g0(self as f64)
371            }
372
373            fn n(self) -> Force {
374                <f64 as NumericExt>::n(self as f64)
375            }
376
377            fn kn(self) -> Force {
378                <f64 as NumericExt>::kn(self as f64)
379            }
380
381            fn lbf(self) -> Force {
382                <f64 as NumericExt>::lbf(self as f64)
383            }
384
385            fn m2(self) -> Area {
386                <f64 as NumericExt>::m2(self as f64)
387            }
388
389            fn m3(self) -> Volume {
390                <f64 as NumericExt>::m3(self as f64)
391            }
392
393            fn j(self) -> Energy {
394                <f64 as NumericExt>::j(self as f64)
395            }
396
397            fn w(self) -> Power {
398                <f64 as NumericExt>::w(self as f64)
399            }
400
401            fn pa(self) -> Pressure {
402                <f64 as NumericExt>::pa(self as f64)
403            }
404
405            fn bar(self) -> Pressure {
406                <f64 as NumericExt>::bar(self as f64)
407            }
408
409            fn hz(self) -> Frequency {
410                <f64 as NumericExt>::hz(self as f64)
411            }
412
413            fn khz(self) -> Frequency {
414                <f64 as NumericExt>::khz(self as f64)
415            }
416
417            fn mhz(self) -> Frequency {
418                <f64 as NumericExt>::mhz(self as f64)
419            }
420
421            fn ghz(self) -> Frequency {
422                <f64 as NumericExt>::ghz(self as f64)
423            }
424
425            fn amperes(self) -> ElectricCurrent {
426                <f64 as NumericExt>::amperes(self as f64)
427            }
428
429            fn volts(self) -> Voltage {
430                <f64 as NumericExt>::volts(self as f64)
431            }
432
433            fn ohms(self) -> Resistance {
434                <f64 as NumericExt>::ohms(self as f64)
435            }
436
437            fn tesla(self) -> MagneticFluxDensity {
438                <f64 as NumericExt>::tesla(self as f64)
439            }
440
441            fn coulombs(self) -> ElectricCharge {
442                <f64 as NumericExt>::coulombs(self as f64)
443            }
444
445            fn farads(self) -> Capacitance {
446                <f64 as NumericExt>::farads(self as f64)
447            }
448
449            fn henrys(self) -> Inductance {
450                <f64 as NumericExt>::henrys(self as f64)
451            }
452
453            fn webers(self) -> MagneticFlux {
454                <f64 as NumericExt>::webers(self as f64)
455            }
456
457            fn kelvin(self) -> Temperature {
458                <f64 as NumericExt>::kelvin(self as f64)
459            }
460
461            fn kgps(self) -> MassFlowRate {
462                <f64 as NumericExt>::kgps(self as f64)
463            }
464
465            fn sr(self) -> SolidAngle {
466                <f64 as NumericExt>::sr(self as f64)
467            }
468        }
469    };
470}
471
472impl_numeric_ext_for!(f32);
473impl_numeric_ext_for!(i32);
474impl_numeric_ext_for!(i64);
475impl_numeric_ext_for!(u32);
476impl_numeric_ext_for!(u64);