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
8pub 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
16pub trait ConstNeg<const N: i32> {
18 const OUTPUT: i32;
19}
20impl<const N: i32> ConstNeg<N> for () {
21 const OUTPUT: i32 = -N;
22}
23
24pub 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
38pub trait ConstCheck<const N: i32> {}
40impl<const N: i32> ConstCheck<N> for () {}
41
42pub 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
77impl<
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
106impl<
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}
131pub 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
159impl<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
168pub type Dimensionless = Dimension<0, 0, 0, 0, 0, 0, 0>;
172pub type Length = Dimension<1, 0, 0, 0, 0, 0, 0>;
174pub type Mass = Dimension<0, 1, 0, 0, 0, 0, 0>;
176pub type Time = Dimension<0, 0, 1, 0, 0, 0, 0>;
178pub type Temperature = Dimension<0, 0, 0, 1, 0, 0, 0>;
180pub type Current = Dimension<0, 0, 0, 0, 1, 0, 0>;
182pub type Amount = Dimension<0, 0, 0, 0, 0, 1, 0>;
184pub 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#[macro_export]
250macro_rules! base_unit_dim {
251 ($dim:ty) => {
252 <$dim as BaseUnitForDim>::Unit
253 };
254}
255
256#[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#[macro_export]
282macro_rules! assert_dimension {
283 ($value:expr, $expected:ty) => {{
284 let _: Tensor<_,$expected, _,_, _> = $value;
285 $value
286 }};
287}