Skip to main content

qtty_core/
dimension.rs

1//! Dimension types and traits.
2//!
3//! Dimensions are modelled as a single generic struct [`Dim`] parameterised by eight
4//! [`typenum`] signed integers representing the exponents of the fundamental physical
5//! dimensions. Multiplying two dimensions adds exponents; dividing subtracts them.
6//! Because typenum arithmetic resolves at compile time, compound types like `Length * Length`
7//! automatically become `Area` (exponent 2), and `Area / Length` collapses back to `Length`
8//! (exponent 1) — all verified by the type checker.
9//!
10//! # Layout
11//!
12//! The eight exponent slots are:
13//!
14//! | Position | Base quantity            | SI symbol |
15//! |----------|--------------------------|-----------|
16//! | `L`      | Length                   | m         |
17//! | `T`      | Time                     | s         |
18//! | `M`      | Mass                     | kg        |
19//! | `Th`     | Thermodynamic temperature| K         |
20//! | `I`      | Electric current         | A         |
21//! | `N`      | Amount of substance      | mol       |
22//! | `J`      | Luminous intensity       | cd        |
23//! | `A`      | Plane angle (auxiliary)  | rad/deg   |
24
25use core::marker::PhantomData;
26use core::ops::{Add, Sub};
27use typenum::Integer;
28
29/// Marker trait for **dimensions**.
30///
31/// Implemented automatically for every [`Dim<L,T,M,Th,I,N,J,A>`] whose type
32/// parameters satisfy the required bounds.
33pub trait Dimension: 'static {}
34
35// ─────────────────────────────────────────────────────────────────────────────
36// Core dimension struct
37// ─────────────────────────────────────────────────────────────────────────────
38
39/// A physical dimension encoded as eight typenum integer exponents.
40///
41/// This is a zero-sized type: no runtime cost.
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43pub struct Dim<L, T, M, Th, I, N, J, A>(
44    PhantomData<L>,
45    PhantomData<T>,
46    PhantomData<M>,
47    PhantomData<Th>,
48    PhantomData<I>,
49    PhantomData<N>,
50    PhantomData<J>,
51    PhantomData<A>,
52)
53where
54    L: Integer,
55    T: Integer,
56    M: Integer,
57    Th: Integer,
58    I: Integer,
59    N: Integer,
60    J: Integer,
61    A: Integer;
62
63impl<L, T, M, Th, I, N, J, A> Dimension for Dim<L, T, M, Th, I, N, J, A>
64where
65    L: Integer + 'static,
66    T: Integer + 'static,
67    M: Integer + 'static,
68    Th: Integer + 'static,
69    I: Integer + 'static,
70    N: Integer + 'static,
71    J: Integer + 'static,
72    A: Integer + 'static,
73{
74}
75
76// ─────────────────────────────────────────────────────────────────────────────
77// Dimension multiplication (adds exponents)
78// ─────────────────────────────────────────────────────────────────────────────
79
80/// Trait for multiplying two dimensions (adds exponents).
81pub trait DimMul<Rhs: Dimension>: Dimension {
82    /// The resulting dimension.
83    type Output: Dimension;
84}
85
86impl<L1, T1, M1, Th1, I1, N1, J1, A1, L2, T2, M2, Th2, I2, N2, J2, A2>
87    DimMul<Dim<L2, T2, M2, Th2, I2, N2, J2, A2>> for Dim<L1, T1, M1, Th1, I1, N1, J1, A1>
88where
89    L1: Integer + Add<L2> + 'static,
90    T1: Integer + Add<T2> + 'static,
91    M1: Integer + Add<M2> + 'static,
92    Th1: Integer + Add<Th2> + 'static,
93    I1: Integer + Add<I2> + 'static,
94    N1: Integer + Add<N2> + 'static,
95    J1: Integer + Add<J2> + 'static,
96    A1: Integer + Add<A2> + 'static,
97    L2: Integer + 'static,
98    T2: Integer + 'static,
99    M2: Integer + 'static,
100    Th2: Integer + 'static,
101    I2: Integer + 'static,
102    N2: Integer + 'static,
103    J2: Integer + 'static,
104    A2: Integer + 'static,
105    <L1 as Add<L2>>::Output: Integer + 'static,
106    <T1 as Add<T2>>::Output: Integer + 'static,
107    <M1 as Add<M2>>::Output: Integer + 'static,
108    <Th1 as Add<Th2>>::Output: Integer + 'static,
109    <I1 as Add<I2>>::Output: Integer + 'static,
110    <N1 as Add<N2>>::Output: Integer + 'static,
111    <J1 as Add<J2>>::Output: Integer + 'static,
112    <A1 as Add<A2>>::Output: Integer + 'static,
113{
114    type Output = Dim<
115        <L1 as Add<L2>>::Output,
116        <T1 as Add<T2>>::Output,
117        <M1 as Add<M2>>::Output,
118        <Th1 as Add<Th2>>::Output,
119        <I1 as Add<I2>>::Output,
120        <N1 as Add<N2>>::Output,
121        <J1 as Add<J2>>::Output,
122        <A1 as Add<A2>>::Output,
123    >;
124}
125
126// ─────────────────────────────────────────────────────────────────────────────
127// Dimension division (subtracts exponents)
128// ─────────────────────────────────────────────────────────────────────────────
129
130/// Trait for dividing two dimensions (subtracts exponents).
131pub trait DimDiv<Rhs: Dimension>: Dimension {
132    /// The resulting dimension.
133    type Output: Dimension;
134}
135
136impl<L1, T1, M1, Th1, I1, N1, J1, A1, L2, T2, M2, Th2, I2, N2, J2, A2>
137    DimDiv<Dim<L2, T2, M2, Th2, I2, N2, J2, A2>> for Dim<L1, T1, M1, Th1, I1, N1, J1, A1>
138where
139    L1: Integer + Sub<L2> + 'static,
140    T1: Integer + Sub<T2> + 'static,
141    M1: Integer + Sub<M2> + 'static,
142    Th1: Integer + Sub<Th2> + 'static,
143    I1: Integer + Sub<I2> + 'static,
144    N1: Integer + Sub<N2> + 'static,
145    J1: Integer + Sub<J2> + 'static,
146    A1: Integer + Sub<A2> + 'static,
147    L2: Integer + 'static,
148    T2: Integer + 'static,
149    M2: Integer + 'static,
150    Th2: Integer + 'static,
151    I2: Integer + 'static,
152    N2: Integer + 'static,
153    J2: Integer + 'static,
154    A2: Integer + 'static,
155    <L1 as Sub<L2>>::Output: Integer + 'static,
156    <T1 as Sub<T2>>::Output: Integer + 'static,
157    <M1 as Sub<M2>>::Output: Integer + 'static,
158    <Th1 as Sub<Th2>>::Output: Integer + 'static,
159    <I1 as Sub<I2>>::Output: Integer + 'static,
160    <N1 as Sub<N2>>::Output: Integer + 'static,
161    <J1 as Sub<J2>>::Output: Integer + 'static,
162    <A1 as Sub<A2>>::Output: Integer + 'static,
163{
164    type Output = Dim<
165        <L1 as Sub<L2>>::Output,
166        <T1 as Sub<T2>>::Output,
167        <M1 as Sub<M2>>::Output,
168        <Th1 as Sub<Th2>>::Output,
169        <I1 as Sub<I2>>::Output,
170        <N1 as Sub<N2>>::Output,
171        <J1 as Sub<J2>>::Output,
172        <A1 as Sub<A2>>::Output,
173    >;
174}
175
176// ─────────────────────────────────────────────────────────────────────────────
177// Base dimension aliases
178// ─────────────────────────────────────────────────────────────────────────────
179
180use typenum::{N1, N2, N3, P1, P2, P3, Z0};
181
182/// Dimensionless (all exponents zero).
183pub type Dimensionless = Dim<Z0, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
184
185/// Length (L¹).
186pub type Length = Dim<P1, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
187
188/// Time (T¹).
189pub type Time = Dim<Z0, P1, Z0, Z0, Z0, Z0, Z0, Z0>;
190
191/// Mass (M¹).
192pub type Mass = Dim<Z0, Z0, P1, Z0, Z0, Z0, Z0, Z0>;
193
194/// Thermodynamic temperature (Θ¹).
195pub type Temperature = Dim<Z0, Z0, Z0, P1, Z0, Z0, Z0, Z0>;
196
197/// Electric current (I¹).
198pub type Current = Dim<Z0, Z0, Z0, Z0, P1, Z0, Z0, Z0>;
199
200/// Amount of substance (N¹).
201pub type AmountOfSubstance = Dim<Z0, Z0, Z0, Z0, Z0, P1, Z0, Z0>;
202
203/// Luminous intensity (J¹).
204pub type LuminousIntensity = Dim<Z0, Z0, Z0, Z0, Z0, Z0, P1, Z0>;
205
206/// Plane angle (A¹) — treated as an independent dimension for type safety.
207pub type Angular = Dim<Z0, Z0, Z0, Z0, Z0, Z0, Z0, P1>;
208
209// ─────────────────────────────────────────────────────────────────────────────
210// Derived dimension aliases
211// ─────────────────────────────────────────────────────────────────────────────
212
213/// Area (L²).
214pub type Area = Dim<P2, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
215
216/// Volume (L³).
217pub type Volume = Dim<P3, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
218
219/// Velocity (L¹ · T⁻¹).
220pub type VelocityDim = Dim<P1, N1, Z0, Z0, Z0, Z0, Z0, Z0>;
221
222/// Acceleration (L¹ · T⁻²).
223pub type Acceleration = Dim<P1, N2, Z0, Z0, Z0, Z0, Z0, Z0>;
224
225/// Force (M¹ · L¹ · T⁻²).
226pub type Force = Dim<P1, N2, P1, Z0, Z0, Z0, Z0, Z0>;
227
228/// Energy (M¹ · L² · T⁻²).
229pub type Energy = Dim<P2, N2, P1, Z0, Z0, Z0, Z0, Z0>;
230
231/// Power (M¹ · L² · T⁻³).
232pub type Power = Dim<P2, N3, P1, Z0, Z0, Z0, Z0, Z0>;
233
234/// Frequency — angular per time (A¹ · T⁻¹).
235pub type FrequencyDim = Dim<Z0, N1, Z0, Z0, Z0, Z0, Z0, P1>;
236
237// ─────────────────────────────────────────────────────────────────────────────
238// Legacy compatibility alias
239// ─────────────────────────────────────────────────────────────────────────────
240
241/// Backward-compatible alias: `DivDim<N, D>` resolves to `<N as DimDiv<D>>::Output`.
242///
243/// This preserves source compatibility for code that previously used `DivDim<Length, Time>`.
244/// It now resolves to the same concrete type as the `Velocity` alias, since typenum
245/// arithmetic produces the identical `Dim<P1, N1, …>`.
246pub type DivDim<N, D> = <N as DimDiv<D>>::Output;
247
248/// Backward-compatible alias: `MulDim<A, B>` resolves to `<A as DimMul<B>>::Output`.
249pub type MulDim<A, B> = <A as DimMul<B>>::Output;