Skip to main content

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>;