dlt/
dimension.rs

1use crate::units::*;
2use crate::si::*;
3
4#[derive(Clone, Copy, Debug)]
5
6pub struct Dimension<const L: i32, const M: i32, const T: i32, const Θ: i32 = 0, const I: i32 = 0, const N: i32 = 0, const J: i32 = 0>;
7
8// A helper trait for compile‑time addition.
9pub trait ConstAdd<const A: i32, const B: i32> {
10    const OUTPUT: i32;
11}
12impl<const A: i32, const B: i32> ConstAdd<A, B> for () {
13    const OUTPUT: i32 = A + B;
14}
15
16// Helper trait for negation.
17pub trait ConstNeg<const N: i32> {
18    const OUTPUT: i32;
19}
20impl<const N: i32> ConstNeg<N> for () {
21    const OUTPUT: i32 = -N;
22}
23
24// helper trait for integer division
25pub trait ConstDiv<const A: i32, const B: i32> {
26    const OUTPUT: i32;
27}
28
29impl<const A: i32, const B: i32> ConstDiv<A, B> for () {
30    const OUTPUT: i32 = A / B;
31}
32
33
34
35
36
37
38// Dummy constraint to force computed constants to be used.
39pub trait ConstCheck<const N: i32> {}
40impl<const N: i32> ConstCheck<N> for () {}
41
42// MultiplyDimensions using the dummy ConstCheck bounds.
43pub trait MultiplyDimensions<Other> {
44    type Output;
45}
46impl<
47    const L1: i32, const M1: i32, const T1: i32,
48    const Θ1: i32, const I1: i32, const N1: i32, const J1: i32,
49    const L2: i32, const M2: i32, const T2: i32,
50    const Θ2: i32, const I2: i32, const N2: i32, const J2: i32,
51> MultiplyDimensions<Dimension<L2, M2, T2, Θ2, I2, N2, J2>>
52    for Dimension<L1, M1, T1, Θ1, I1, N1, J1>
53where
54    (): ConstCheck<{ <() as ConstAdd<L1, L2>>::OUTPUT }>,
55    (): ConstCheck<{ <() as ConstAdd<M1, M2>>::OUTPUT }>,
56    (): ConstCheck<{ <() as ConstAdd<T1, T2>>::OUTPUT }>,
57    (): ConstCheck<{ <() as ConstAdd<Θ1, Θ2>>::OUTPUT }>,
58    (): ConstCheck<{ <() as ConstAdd<I1, I2>>::OUTPUT }>,
59    (): ConstCheck<{ <() as ConstAdd<N1, N2>>::OUTPUT }>,
60    (): ConstCheck<{ <() as ConstAdd<J1, J2>>::OUTPUT }>,
61{
62    type Output = Dimension<
63        { <() as ConstAdd<L1, L2>>::OUTPUT },
64        { <() as ConstAdd<M1, M2>>::OUTPUT },
65        { <() as ConstAdd<T1, T2>>::OUTPUT },
66        { <() as ConstAdd<Θ1, Θ2>>::OUTPUT },
67        { <() as ConstAdd<I1, I2>>::OUTPUT },
68        { <() as ConstAdd<N1, N2>>::OUTPUT },
69        { <() as ConstAdd<J1, J2>>::OUTPUT }
70    >;
71}
72
73pub trait SquareDimension {
74    type Output;
75}
76
77// square the dimension.
78impl<
79    const L: i32, const M: i32, const T: i32,
80    const Θ: i32, const I: i32, const N: i32, const J: i32
81> SquareDimension for Dimension<L, M, T, Θ, I, N, J>
82where
83    (): ConstCheck<{ <() as ConstAdd<L, L>>::OUTPUT }>,
84    (): ConstCheck<{ <() as ConstAdd<M, M>>::OUTPUT }>,
85    (): ConstCheck<{ <() as ConstAdd<T, T>>::OUTPUT }>,
86    (): ConstCheck<{ <() as ConstAdd<Θ, Θ>>::OUTPUT }>,
87    (): ConstCheck<{ <() as ConstAdd<I, I>>::OUTPUT }>,
88    (): ConstCheck<{ <() as ConstAdd<N, N>>::OUTPUT }>,
89    (): ConstCheck<{ <() as ConstAdd<J, J>>::OUTPUT }>,
90{
91    type Output = Dimension<
92        { <() as ConstAdd<L, L>>::OUTPUT },
93        { <() as ConstAdd<M, M>>::OUTPUT },
94        { <() as ConstAdd<T, T>>::OUTPUT },
95        { <() as ConstAdd<Θ, Θ>>::OUTPUT },
96        { <() as ConstAdd<I, I>>::OUTPUT },
97        { <() as ConstAdd<N, N>>::OUTPUT },
98        { <() as ConstAdd<J, J>>::OUTPUT }
99    >;
100}
101
102pub trait SqrtDimension {
103    type Output;
104}
105
106// square root the dimension.
107impl<
108    const L: i32, const M: i32, const T: i32,
109    const Θ: i32, const I: i32, const N: i32, const J: i32
110> SqrtDimension for Dimension<L, M, T, Θ, I, N, J>
111
112where
113    (): ConstCheck<{ <() as ConstDiv<L, 2>>::OUTPUT }>,
114    (): ConstCheck<{ <() as ConstDiv<M, 2>>::OUTPUT }>,
115    (): ConstCheck<{ <() as ConstDiv<T, 2>>::OUTPUT }>,
116    (): ConstCheck<{ <() as ConstDiv<Θ, 2>>::OUTPUT }>,
117    (): ConstCheck<{ <() as ConstDiv<I, 2>>::OUTPUT }>,
118    (): ConstCheck<{ <() as ConstDiv<N, 2>>::OUTPUT }>,
119    (): ConstCheck<{ <() as ConstDiv<J, 2>>::OUTPUT }>,
120{
121    type Output = Dimension<
122        { <() as ConstDiv<L, 2>>::OUTPUT },
123        { <() as ConstDiv<M, 2>>::OUTPUT },
124        { <() as ConstDiv<T, 2>>::OUTPUT },
125        { <() as ConstDiv<Θ, 2>>::OUTPUT },
126        { <() as ConstDiv<I, 2>>::OUTPUT },
127        { <() as ConstDiv<N, 2>>::OUTPUT },
128        { <() as ConstDiv<J, 2>>::OUTPUT }
129    >;
130}
131// InvertDimension using the dummy ConstCheck bounds.
132pub trait InvertDimension {
133    type Output;
134}
135impl<
136    const L: i32, const M: i32, const T: i32,
137    const Θ: i32, const I: i32, const N: i32, const J: i32
138> InvertDimension for Dimension<L, M, T, Θ, I, N, J>
139where
140    (): ConstCheck<{ <() as ConstNeg<L>>::OUTPUT }>,
141    (): ConstCheck<{ <() as ConstNeg<M>>::OUTPUT }>,
142    (): ConstCheck<{ <() as ConstNeg<T>>::OUTPUT }>,
143    (): ConstCheck<{ <() as ConstNeg<Θ>>::OUTPUT }>,
144    (): ConstCheck<{ <() as ConstNeg<I>>::OUTPUT }>,
145    (): ConstCheck<{ <() as ConstNeg<N>>::OUTPUT }>,
146    (): ConstCheck<{ <() as ConstNeg<J>>::OUTPUT }>,
147{
148    type Output = Dimension<
149        { <() as ConstNeg<L>>::OUTPUT },
150        { <() as ConstNeg<M>>::OUTPUT },
151        { <() as ConstNeg<T>>::OUTPUT },
152        { <() as ConstNeg<Θ>>::OUTPUT },
153        { <() as ConstNeg<I>>::OUTPUT },
154        { <() as ConstNeg<N>>::OUTPUT },
155        { <() as ConstNeg<J>>::OUTPUT }
156    >;
157}
158
159// Since Dimension is zero‑sized, we can implement Default.
160impl<const L: i32, const M: i32, const T: i32, const Θ: i32, const I: i32, const N: i32, const J: i32>
161    Default for Dimension<L, M, T, Θ, I, N, J>
162{
163    fn default() -> Self {
164        Self
165    }
166}
167
168// Removed the NormalizeDimension and AutoNormalize traits.
169
170// Some type aliases for common dimensions.
171pub type Dimensionless = Dimension<0, 0, 0, 0, 0, 0, 0>;
172// L
173pub type Length = Dimension<1, 0, 0, 0, 0, 0, 0>;
174// M
175pub type Mass = Dimension<0, 1, 0, 0, 0, 0, 0>;
176// T
177pub type Time = Dimension<0, 0, 1, 0, 0, 0, 0>;
178// Θ
179pub type Temperature = Dimension<0, 0, 0, 1, 0, 0, 0>;
180// I
181pub type Current = Dimension<0, 0, 0, 0, 1, 0, 0>;
182// N
183pub type Amount = Dimension<0, 0, 0, 0, 0, 1, 0>;
184// J
185pub type LuminousIntensity = Dimension<0, 0, 0, 0, 0, 0, 1>;
186
187pub trait BaseUnitForDim {
188    type Unit: crate::units::Unit<Dimension = Self>;
189    fn base_unit() -> Self::Unit;
190}
191
192impl BaseUnitForDim for Dimensionless {
193    type Unit = Unitless;
194    fn base_unit() -> Self::Unit {
195        Self::Unit::default()
196    }
197}
198
199impl BaseUnitForDim for Length {
200    type Unit = Meter;
201    fn base_unit() -> Self::Unit {
202        Self::Unit::default()
203    }
204}
205
206impl BaseUnitForDim for Mass {
207    type Unit = Kilogram;
208    fn base_unit() -> Self::Unit {
209        Self::Unit::default()
210    }
211}
212
213impl BaseUnitForDim for Time {
214    type Unit = Second;
215    fn base_unit() -> Self::Unit {
216        Self::Unit::default()
217    }
218}
219
220impl BaseUnitForDim for Temperature {
221    type Unit = Kelvin;
222    fn base_unit() -> Self::Unit {
223        Self::Unit::default()
224    }
225}
226
227impl BaseUnitForDim for Current {
228    type Unit = Ampere;
229    fn base_unit() -> Self::Unit {
230        Self::Unit::default()
231    }
232}
233
234impl BaseUnitForDim for Amount {
235    type Unit = Mole;
236    fn base_unit() -> Self::Unit {
237        Self::Unit::default()
238    }
239}
240
241impl BaseUnitForDim for LuminousIntensity {
242    type Unit = Candela;
243    fn base_unit() -> Self::Unit {
244        Self::Unit::default()
245    }
246}
247
248// base unit for dimension macro
249#[macro_export]
250macro_rules! base_unit_dim {
251    ($dim:ty) => {
252        <$dim as BaseUnitForDim>::Unit
253    };
254}
255
256// Implement multiplication for dimensions.
257
258#[macro_export]
259macro_rules! dim_inv {
260    ($dim:tt) => {
261        <$dim as InvertDimension>::Output
262    };
263}
264
265#[macro_export]
266macro_rules! dim_mul {
267    ($lhs:tt, $rhs:tt) => {
268        <$lhs as MultiplyDimensions<$rhs>>::Output
269    };
270}
271
272#[macro_export]
273macro_rules! dim_div {
274    ($lhs:tt, $rhs:tt) => {
275        <$lhs as MultiplyDimensions<<$rhs as InvertDimension>::Output>>::Output
276    };
277}
278
279/// Asserts that the type of `$value` is a Tensor with the expected dimension type.
280/// Returns `$value` on success so that the macro can be used inline.
281#[macro_export]
282macro_rules! assert_dimension {
283    ($value:expr, $expected:ty) => {{
284        let _: Tensor<_,$expected, _,_, _> = $value;
285        $value
286    }};
287}