qtty_core/dimension.rs
1// SPDX-License-Identifier: BSD-3-Clause
2// Copyright (C) 2026 Vallés Puig, Ramon
3
4//! Dimension types and traits.
5//!
6//! Dimensions are modelled as a single generic struct [`Dim`] parameterised by eight
7//! [`typenum`] signed integers representing the exponents of the fundamental physical
8//! dimensions. Multiplying two dimensions adds exponents; dividing subtracts them.
9//! Because typenum arithmetic resolves at compile time, compound types like `Length * Length`
10//! automatically become `Area` (exponent 2), and `Area / Length` collapses back to `Length`
11//! (exponent 1) — all verified by the type checker.
12//!
13//! # Layout
14//!
15//! The eight exponent slots are:
16//!
17//! | Position | Base quantity | SI symbol |
18//! |----------|--------------------------|-----------|
19//! | `L` | Length | m |
20//! | `T` | Time | s |
21//! | `M` | Mass | kg |
22//! | `Th` | Thermodynamic temperature| K |
23//! | `I` | Electric current | A |
24//! | `N` | Amount of substance | mol |
25//! | `J` | Luminous intensity | cd |
26//! | `A` | Plane angle (auxiliary) | rad/deg |
27
28use core::marker::PhantomData;
29use core::ops::{Add, Sub};
30use typenum::Integer;
31
32/// Marker trait for **dimensions**.
33///
34/// Implemented automatically for every [`Dim<L,T,M,Th,I,N,J,A>`] whose type
35/// parameters satisfy the required bounds.
36pub trait Dimension: 'static {}
37
38// ─────────────────────────────────────────────────────────────────────────────
39// Core dimension struct
40// ─────────────────────────────────────────────────────────────────────────────
41
42/// A physical dimension encoded as eight typenum integer exponents.
43///
44/// This is a zero-sized type: no runtime cost.
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub struct Dim<L, T, M, Th, I, N, J, A>(
47 PhantomData<L>,
48 PhantomData<T>,
49 PhantomData<M>,
50 PhantomData<Th>,
51 PhantomData<I>,
52 PhantomData<N>,
53 PhantomData<J>,
54 PhantomData<A>,
55)
56where
57 L: Integer,
58 T: Integer,
59 M: Integer,
60 Th: Integer,
61 I: Integer,
62 N: Integer,
63 J: Integer,
64 A: Integer;
65
66impl<L, T, M, Th, I, N, J, A> Dimension for Dim<L, T, M, Th, I, N, J, A>
67where
68 L: Integer + 'static,
69 T: Integer + 'static,
70 M: Integer + 'static,
71 Th: Integer + 'static,
72 I: Integer + 'static,
73 N: Integer + 'static,
74 J: Integer + 'static,
75 A: Integer + 'static,
76{
77}
78
79// ─────────────────────────────────────────────────────────────────────────────
80// Dimension multiplication (adds exponents)
81// ─────────────────────────────────────────────────────────────────────────────
82
83/// Trait for multiplying two dimensions (adds exponents).
84pub trait DimMul<Rhs: Dimension>: Dimension {
85 /// The resulting dimension.
86 type Output: Dimension;
87}
88
89impl<L1, T1, M1, Th1, I1, N1, J1, A1, L2, T2, M2, Th2, I2, N2, J2, A2>
90 DimMul<Dim<L2, T2, M2, Th2, I2, N2, J2, A2>> for Dim<L1, T1, M1, Th1, I1, N1, J1, A1>
91where
92 L1: Integer + Add<L2> + 'static,
93 T1: Integer + Add<T2> + 'static,
94 M1: Integer + Add<M2> + 'static,
95 Th1: Integer + Add<Th2> + 'static,
96 I1: Integer + Add<I2> + 'static,
97 N1: Integer + Add<N2> + 'static,
98 J1: Integer + Add<J2> + 'static,
99 A1: Integer + Add<A2> + 'static,
100 L2: Integer + 'static,
101 T2: Integer + 'static,
102 M2: Integer + 'static,
103 Th2: Integer + 'static,
104 I2: Integer + 'static,
105 N2: Integer + 'static,
106 J2: Integer + 'static,
107 A2: Integer + 'static,
108 <L1 as Add<L2>>::Output: Integer + 'static,
109 <T1 as Add<T2>>::Output: Integer + 'static,
110 <M1 as Add<M2>>::Output: Integer + 'static,
111 <Th1 as Add<Th2>>::Output: Integer + 'static,
112 <I1 as Add<I2>>::Output: Integer + 'static,
113 <N1 as Add<N2>>::Output: Integer + 'static,
114 <J1 as Add<J2>>::Output: Integer + 'static,
115 <A1 as Add<A2>>::Output: Integer + 'static,
116{
117 type Output = Dim<
118 <L1 as Add<L2>>::Output,
119 <T1 as Add<T2>>::Output,
120 <M1 as Add<M2>>::Output,
121 <Th1 as Add<Th2>>::Output,
122 <I1 as Add<I2>>::Output,
123 <N1 as Add<N2>>::Output,
124 <J1 as Add<J2>>::Output,
125 <A1 as Add<A2>>::Output,
126 >;
127}
128
129// ─────────────────────────────────────────────────────────────────────────────
130// Dimension division (subtracts exponents)
131// ─────────────────────────────────────────────────────────────────────────────
132
133/// Trait for dividing two dimensions (subtracts exponents).
134pub trait DimDiv<Rhs: Dimension>: Dimension {
135 /// The resulting dimension.
136 type Output: Dimension;
137}
138
139impl<L1, T1, M1, Th1, I1, N1, J1, A1, L2, T2, M2, Th2, I2, N2, J2, A2>
140 DimDiv<Dim<L2, T2, M2, Th2, I2, N2, J2, A2>> for Dim<L1, T1, M1, Th1, I1, N1, J1, A1>
141where
142 L1: Integer + Sub<L2> + 'static,
143 T1: Integer + Sub<T2> + 'static,
144 M1: Integer + Sub<M2> + 'static,
145 Th1: Integer + Sub<Th2> + 'static,
146 I1: Integer + Sub<I2> + 'static,
147 N1: Integer + Sub<N2> + 'static,
148 J1: Integer + Sub<J2> + 'static,
149 A1: Integer + Sub<A2> + 'static,
150 L2: Integer + 'static,
151 T2: Integer + 'static,
152 M2: Integer + 'static,
153 Th2: Integer + 'static,
154 I2: Integer + 'static,
155 N2: Integer + 'static,
156 J2: Integer + 'static,
157 A2: Integer + 'static,
158 <L1 as Sub<L2>>::Output: Integer + 'static,
159 <T1 as Sub<T2>>::Output: Integer + 'static,
160 <M1 as Sub<M2>>::Output: Integer + 'static,
161 <Th1 as Sub<Th2>>::Output: Integer + 'static,
162 <I1 as Sub<I2>>::Output: Integer + 'static,
163 <N1 as Sub<N2>>::Output: Integer + 'static,
164 <J1 as Sub<J2>>::Output: Integer + 'static,
165 <A1 as Sub<A2>>::Output: Integer + 'static,
166{
167 type Output = Dim<
168 <L1 as Sub<L2>>::Output,
169 <T1 as Sub<T2>>::Output,
170 <M1 as Sub<M2>>::Output,
171 <Th1 as Sub<Th2>>::Output,
172 <I1 as Sub<I2>>::Output,
173 <N1 as Sub<N2>>::Output,
174 <J1 as Sub<J2>>::Output,
175 <A1 as Sub<A2>>::Output,
176 >;
177}
178
179// ─────────────────────────────────────────────────────────────────────────────
180// Base dimension aliases
181// ─────────────────────────────────────────────────────────────────────────────
182
183use typenum::{N1, N2, N3, P1, P2, P3, P4, Z0};
184
185/// Dimensionless (all exponents zero).
186pub type Dimensionless = Dim<Z0, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
187
188/// Length (L¹).
189pub type Length = Dim<P1, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
190
191/// Time (T¹).
192pub type Time = Dim<Z0, P1, Z0, Z0, Z0, Z0, Z0, Z0>;
193
194/// Mass (M¹).
195pub type Mass = Dim<Z0, Z0, P1, Z0, Z0, Z0, Z0, Z0>;
196
197/// Thermodynamic temperature (Θ¹).
198pub type Temperature = Dim<Z0, Z0, Z0, P1, Z0, Z0, Z0, Z0>;
199
200/// Electric current (I¹).
201pub type Current = Dim<Z0, Z0, Z0, Z0, P1, Z0, Z0, Z0>;
202
203/// Amount of substance (N¹).
204pub type AmountOfSubstance = Dim<Z0, Z0, Z0, Z0, Z0, P1, Z0, Z0>;
205
206/// Luminous intensity (J¹).
207pub type LuminousIntensity = Dim<Z0, Z0, Z0, Z0, Z0, Z0, P1, Z0>;
208
209/// Plane angle (A¹) — treated as an independent dimension for type safety.
210pub type Angular = Dim<Z0, Z0, Z0, Z0, Z0, Z0, Z0, P1>;
211
212// ─────────────────────────────────────────────────────────────────────────────
213// Derived dimension aliases
214// ─────────────────────────────────────────────────────────────────────────────
215
216/// Area (L²).
217pub type Area = Dim<P2, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
218
219/// Volume (L³).
220pub type Volume = Dim<P3, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
221
222/// Velocity (L¹ · T⁻¹).
223pub type Velocity = Dim<P1, N1, Z0, Z0, Z0, Z0, Z0, Z0>;
224
225/// Acceleration (L¹ · T⁻²).
226pub type Acceleration = Dim<P1, N2, Z0, Z0, Z0, Z0, Z0, Z0>;
227
228/// Force (M¹ · L¹ · T⁻²).
229pub type Force = Dim<P1, N2, P1, Z0, Z0, Z0, Z0, Z0>;
230
231/// Energy (M¹ · L² · T⁻²).
232pub type Energy = Dim<P2, N2, P1, Z0, Z0, Z0, Z0, Z0>;
233
234/// Power (M¹ · L² · T⁻³).
235pub type Power = Dim<P2, N3, P1, Z0, Z0, Z0, Z0, Z0>;
236
237/// Pressure (M¹ · L⁻¹ · T⁻²) — equivalently, force per unit area (N/m²).
238pub type Pressure = Dim<N1, N2, P1, Z0, Z0, Z0, Z0, Z0>;
239
240/// Solid angle (A²) — plane angle squared (e.g. steradian, square degree).
241///
242/// Square degree (`Prod<Degree, Degree>`) is the canonical scaling unit
243/// for this dimension because [`Angular`]'s canonical is degree.
244pub type SolidAngle = Dim<Z0, Z0, Z0, Z0, Z0, Z0, Z0, P2>;
245
246/// Angular rate (A¹ · T⁻¹) — angular displacement per unit time.
247///
248/// This dimension represents *angular frequency* (radians, degrees, etc. per
249/// unit time), **not** SI cycle frequency (Hz = cycles/s). If you need cycle
250/// frequency, model it as `T⁻¹` (inverse time) with dimensionless cycles.
251pub type AngularRate = Dim<Z0, N1, Z0, Z0, Z0, Z0, Z0, P1>;
252
253/// Radiance (M¹ · T⁻³ · A⁻²) — radiant power per unit area per unit solid
254/// angle (e.g. W·m⁻²·sr⁻¹).
255pub type Radiance = Dim<Z0, N3, P1, Z0, Z0, Z0, Z0, N2>;
256
257/// Spectral radiance per unit wavelength (L⁻¹ · M¹ · T⁻³ · A⁻²) — radiance
258/// per unit wavelength (e.g. W·m⁻²·sr⁻¹·nm⁻¹).
259pub type SpectralRadiance = Dim<N1, N3, P1, Z0, Z0, Z0, Z0, N2>;
260
261/// Photon radiance (L⁻² · T⁻¹ · A⁻²) — photon count per area per time per
262/// solid angle (e.g. ph·cm⁻²·s⁻¹·sr⁻¹). Photons are treated as
263/// dimensionless counts.
264pub type PhotonRadiance = Dim<N2, N1, Z0, Z0, Z0, Z0, Z0, N2>;
265
266/// Spectral photon radiance per unit wavelength (L⁻³ · T⁻¹ · A⁻²) — photon
267/// radiance per unit wavelength (e.g. ph·cm⁻²·s⁻¹·sr⁻¹·Å⁻¹).
268pub type SpectralPhotonRadiance = Dim<N3, N1, Z0, Z0, Z0, Z0, Z0, N2>;
269
270/// Inverse solid angle (A⁻²) — used by photometric brightness scales such as
271/// the [`S10`](crate::units::radiometry::S10) "10th-magnitude stars per
272/// square degree" unit.
273pub type InverseSolidAngle = Dim<Z0, Z0, Z0, Z0, Z0, Z0, Z0, N2>;
274
275// ─────────────────────────────────────────────────────────────────────────────
276// Additional derived dimension aliases
277// ─────────────────────────────────────────────────────────────────────────────
278
279/// Frequency (T⁻¹) — reciprocal time, SI unit: hertz (Hz = s⁻¹).
280pub type Frequency = Dim<Z0, N1, Z0, Z0, Z0, Z0, Z0, Z0>;
281
282/// Mass density (M¹ · L⁻³) — SI unit: kg·m⁻³.
283pub type Density = Dim<N3, Z0, P1, Z0, Z0, Z0, Z0, Z0>;
284
285/// Luminous flux (J¹ · A²) — radiant power weighted by the luminosity
286/// function; SI unit: lumen (lm = cd·sr).
287pub type LuminousFlux = Dim<Z0, Z0, Z0, Z0, Z0, Z0, P1, P2>;
288
289/// Illuminance (J¹ · A² · L⁻²) — luminous flux per unit area;
290/// SI unit: lux (lx = lm·m⁻²).
291pub type Illuminance = Dim<N2, Z0, Z0, Z0, Z0, Z0, P1, P2>;
292
293/// Electric charge (I¹ · T¹) — SI unit: coulomb (C = A·s).
294pub type Charge = Dim<Z0, P1, Z0, Z0, P1, Z0, Z0, Z0>;
295
296/// Voltage / electromotive force (M¹ · L² · T⁻³ · I⁻¹) — SI unit: volt (V).
297pub type Voltage = Dim<P2, N3, P1, Z0, N1, Z0, Z0, Z0>;
298
299/// Electrical resistance (M¹ · L² · T⁻³ · I⁻²) — SI unit: ohm (Ω).
300pub type Resistance = Dim<P2, N3, P1, Z0, N2, Z0, Z0, Z0>;
301
302/// Electrical capacitance (M⁻¹ · L⁻² · T⁴ · I²) — SI unit: farad (F).
303pub type Capacitance = Dim<N2, P4, N1, Z0, P2, Z0, Z0, Z0>;
304
305/// Electrical inductance (M¹ · L² · T⁻² · I⁻²) — SI unit: henry (H).
306pub type Inductance = Dim<P2, N2, P1, Z0, N2, Z0, Z0, Z0>;
307
308/// Magnetic flux (M¹ · L² · T⁻² · I⁻¹) — SI unit: weber (Wb).
309pub type MagneticFlux = Dim<P2, N2, P1, Z0, N1, Z0, Z0, Z0>;
310
311/// Magnetic flux density / magnetic field (M¹ · T⁻² · I⁻¹) —
312/// SI unit: tesla (T).
313pub type MagneticFluxDensity = Dim<Z0, N2, P1, Z0, N1, Z0, Z0, Z0>;