use crate::units::*;
use crate::si::*;
#[derive(Clone, Copy, Debug)]
pub 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>;
pub trait ConstAdd<const A: i32, const B: i32> {
const OUTPUT: i32;
}
impl<const A: i32, const B: i32> ConstAdd<A, B> for () {
const OUTPUT: i32 = A + B;
}
pub trait ConstNeg<const N: i32> {
const OUTPUT: i32;
}
impl<const N: i32> ConstNeg<N> for () {
const OUTPUT: i32 = -N;
}
pub trait ConstDiv<const A: i32, const B: i32> {
const OUTPUT: i32;
}
impl<const A: i32, const B: i32> ConstDiv<A, B> for () {
const OUTPUT: i32 = A / B;
}
pub trait ConstCheck<const N: i32> {}
impl<const N: i32> ConstCheck<N> for () {}
pub trait MultiplyDimensions<Other> {
type Output;
}
impl<
const L1: i32, const M1: i32, const T1: i32,
const Θ1: i32, const I1: i32, const N1: i32, const J1: i32,
const L2: i32, const M2: i32, const T2: i32,
const Θ2: i32, const I2: i32, const N2: i32, const J2: i32,
> MultiplyDimensions<Dimension<L2, M2, T2, Θ2, I2, N2, J2>>
for Dimension<L1, M1, T1, Θ1, I1, N1, J1>
where
(): ConstCheck<{ <() as ConstAdd<L1, L2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<M1, M2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<T1, T2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<Θ1, Θ2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<I1, I2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<N1, N2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<J1, J2>>::OUTPUT }>,
{
type Output = Dimension<
{ <() as ConstAdd<L1, L2>>::OUTPUT },
{ <() as ConstAdd<M1, M2>>::OUTPUT },
{ <() as ConstAdd<T1, T2>>::OUTPUT },
{ <() as ConstAdd<Θ1, Θ2>>::OUTPUT },
{ <() as ConstAdd<I1, I2>>::OUTPUT },
{ <() as ConstAdd<N1, N2>>::OUTPUT },
{ <() as ConstAdd<J1, J2>>::OUTPUT }
>;
}
pub trait SquareDimension {
type Output;
}
impl<
const L: i32, const M: i32, const T: i32,
const Θ: i32, const I: i32, const N: i32, const J: i32
> SquareDimension for Dimension<L, M, T, Θ, I, N, J>
where
(): ConstCheck<{ <() as ConstAdd<L, L>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<M, M>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<T, T>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<Θ, Θ>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<I, I>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<N, N>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstAdd<J, J>>::OUTPUT }>,
{
type Output = Dimension<
{ <() as ConstAdd<L, L>>::OUTPUT },
{ <() as ConstAdd<M, M>>::OUTPUT },
{ <() as ConstAdd<T, T>>::OUTPUT },
{ <() as ConstAdd<Θ, Θ>>::OUTPUT },
{ <() as ConstAdd<I, I>>::OUTPUT },
{ <() as ConstAdd<N, N>>::OUTPUT },
{ <() as ConstAdd<J, J>>::OUTPUT }
>;
}
pub trait SqrtDimension {
type Output;
}
impl<
const L: i32, const M: i32, const T: i32,
const Θ: i32, const I: i32, const N: i32, const J: i32
> SqrtDimension for Dimension<L, M, T, Θ, I, N, J>
where
(): ConstCheck<{ <() as ConstDiv<L, 2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstDiv<M, 2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstDiv<T, 2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstDiv<Θ, 2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstDiv<I, 2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstDiv<N, 2>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstDiv<J, 2>>::OUTPUT }>,
{
type Output = Dimension<
{ <() as ConstDiv<L, 2>>::OUTPUT },
{ <() as ConstDiv<M, 2>>::OUTPUT },
{ <() as ConstDiv<T, 2>>::OUTPUT },
{ <() as ConstDiv<Θ, 2>>::OUTPUT },
{ <() as ConstDiv<I, 2>>::OUTPUT },
{ <() as ConstDiv<N, 2>>::OUTPUT },
{ <() as ConstDiv<J, 2>>::OUTPUT }
>;
}
pub trait InvertDimension {
type Output;
}
impl<
const L: i32, const M: i32, const T: i32,
const Θ: i32, const I: i32, const N: i32, const J: i32
> InvertDimension for Dimension<L, M, T, Θ, I, N, J>
where
(): ConstCheck<{ <() as ConstNeg<L>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstNeg<M>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstNeg<T>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstNeg<Θ>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstNeg<I>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstNeg<N>>::OUTPUT }>,
(): ConstCheck<{ <() as ConstNeg<J>>::OUTPUT }>,
{
type Output = Dimension<
{ <() as ConstNeg<L>>::OUTPUT },
{ <() as ConstNeg<M>>::OUTPUT },
{ <() as ConstNeg<T>>::OUTPUT },
{ <() as ConstNeg<Θ>>::OUTPUT },
{ <() as ConstNeg<I>>::OUTPUT },
{ <() as ConstNeg<N>>::OUTPUT },
{ <() as ConstNeg<J>>::OUTPUT }
>;
}
impl<const L: i32, const M: i32, const T: i32, const Θ: i32, const I: i32, const N: i32, const J: i32>
Default for Dimension<L, M, T, Θ, I, N, J>
{
fn default() -> Self {
Self
}
}
pub type Dimensionless = Dimension<0, 0, 0, 0, 0, 0, 0>;
pub type Length = Dimension<1, 0, 0, 0, 0, 0, 0>;
pub type Mass = Dimension<0, 1, 0, 0, 0, 0, 0>;
pub type Time = Dimension<0, 0, 1, 0, 0, 0, 0>;
pub type Temperature = Dimension<0, 0, 0, 1, 0, 0, 0>;
pub type Current = Dimension<0, 0, 0, 0, 1, 0, 0>;
pub type Amount = Dimension<0, 0, 0, 0, 0, 1, 0>;
pub type LuminousIntensity = Dimension<0, 0, 0, 0, 0, 0, 1>;
pub trait BaseUnitForDim {
type Unit: crate::units::Unit<Dimension = Self>;
fn base_unit() -> Self::Unit;
}
impl BaseUnitForDim for Dimensionless {
type Unit = Unitless;
fn base_unit() -> Self::Unit {
Self::Unit::default()
}
}
impl BaseUnitForDim for Length {
type Unit = Meter;
fn base_unit() -> Self::Unit {
Self::Unit::default()
}
}
impl BaseUnitForDim for Mass {
type Unit = Kilogram;
fn base_unit() -> Self::Unit {
Self::Unit::default()
}
}
impl BaseUnitForDim for Time {
type Unit = Second;
fn base_unit() -> Self::Unit {
Self::Unit::default()
}
}
impl BaseUnitForDim for Temperature {
type Unit = Kelvin;
fn base_unit() -> Self::Unit {
Self::Unit::default()
}
}
impl BaseUnitForDim for Current {
type Unit = Ampere;
fn base_unit() -> Self::Unit {
Self::Unit::default()
}
}
impl BaseUnitForDim for Amount {
type Unit = Mole;
fn base_unit() -> Self::Unit {
Self::Unit::default()
}
}
impl BaseUnitForDim for LuminousIntensity {
type Unit = Candela;
fn base_unit() -> Self::Unit {
Self::Unit::default()
}
}
#[macro_export]
macro_rules! base_unit_dim {
($dim:ty) => {
<$dim as BaseUnitForDim>::Unit
};
}
#[macro_export]
macro_rules! dim_inv {
($dim:tt) => {
<$dim as InvertDimension>::Output
};
}
#[macro_export]
macro_rules! dim_mul {
($lhs:tt, $rhs:tt) => {
<$lhs as MultiplyDimensions<$rhs>>::Output
};
}
#[macro_export]
macro_rules! dim_div {
($lhs:tt, $rhs:tt) => {
<$lhs as MultiplyDimensions<<$rhs as InvertDimension>::Output>>::Output
};
}
#[macro_export]
macro_rules! assert_dimension {
($value:expr, $expected:ty) => {{
let _: Tensor<_,$expected, _,_, _> = $value;
$value
}};
}