use core::ops::{Add, Neg, Sub};
use typenum::{Diff, Integer, Negate, Prod, Sum};
pub type Dimension<T, L, M, I, K, N, J> = (T, L, M, I, K, N, J);
pub trait Dimensions {
type T: Integer;
type L: Integer;
type M: Integer;
type I: Integer;
type K: Integer;
type N: Integer;
type J: Integer;
}
impl<T: Integer, L: Integer, M: Integer, I: Integer, K: Integer, N: Integer, J: Integer> Dimensions
for Dimension<T, L, M, I, K, N, J>
{
type T = T;
type L = L;
type M = M;
type I = I;
type K = K;
type N = N;
type J = J;
}
pub type DimensionAdd<D1, D2> = Dimension<
Sum<<D1 as Dimensions>::T, <D2 as Dimensions>::T>,
Sum<<D1 as Dimensions>::L, <D2 as Dimensions>::L>,
Sum<<D1 as Dimensions>::M, <D2 as Dimensions>::M>,
Sum<<D1 as Dimensions>::I, <D2 as Dimensions>::I>,
Sum<<D1 as Dimensions>::K, <D2 as Dimensions>::K>,
Sum<<D1 as Dimensions>::N, <D2 as Dimensions>::N>,
Sum<<D1 as Dimensions>::J, <D2 as Dimensions>::J>,
>;
pub type DimensionSub<D1, D2> = Dimension<
Diff<<D1 as Dimensions>::T, <D2 as Dimensions>::T>,
Diff<<D1 as Dimensions>::L, <D2 as Dimensions>::L>,
Diff<<D1 as Dimensions>::M, <D2 as Dimensions>::M>,
Diff<<D1 as Dimensions>::I, <D2 as Dimensions>::I>,
Diff<<D1 as Dimensions>::K, <D2 as Dimensions>::K>,
Diff<<D1 as Dimensions>::N, <D2 as Dimensions>::N>,
Diff<<D1 as Dimensions>::J, <D2 as Dimensions>::J>,
>;
pub type DimensionMul<D1, D2> = DimensionAdd<D1, D2>;
pub type DimensionDiv<D1, D2> = DimensionSub<D1, D2>;
pub type DimensionPow<D, E> = Dimension<
Prod<<D as Dimensions>::T, E>,
Prod<<D as Dimensions>::L, E>,
Prod<<D as Dimensions>::M, E>,
Prod<<D as Dimensions>::I, E>,
Prod<<D as Dimensions>::K, E>,
Prod<<D as Dimensions>::N, E>,
Prod<<D as Dimensions>::J, E>,
>;
pub type DimensionRecip<D> = Dimension<
Negate<<D as Dimensions>::T>,
Negate<<D as Dimensions>::L>,
Negate<<D as Dimensions>::M>,
Negate<<D as Dimensions>::I>,
Negate<<D as Dimensions>::K>,
Negate<<D as Dimensions>::N>,
Negate<<D as Dimensions>::J>,
>;
pub trait CanMultiplyWith<Rhs: Dimensions>: Dimensions {
type Output: Dimensions;
}
impl<Lhs, Rhs> CanMultiplyWith<Rhs> for Lhs
where
Lhs: Dimensions,
Rhs: Dimensions,
<Lhs as Dimensions>::T: Add<<Rhs as Dimensions>::T>,
<Lhs as Dimensions>::L: Add<<Rhs as Dimensions>::L>,
<Lhs as Dimensions>::M: Add<<Rhs as Dimensions>::M>,
<Lhs as Dimensions>::I: Add<<Rhs as Dimensions>::I>,
<Lhs as Dimensions>::K: Add<<Rhs as Dimensions>::K>,
<Lhs as Dimensions>::N: Add<<Rhs as Dimensions>::N>,
<Lhs as Dimensions>::J: Add<<Rhs as Dimensions>::J>,
Sum<<Lhs as Dimensions>::T, <Rhs as Dimensions>::T>: Integer,
Sum<<Lhs as Dimensions>::L, <Rhs as Dimensions>::L>: Integer,
Sum<<Lhs as Dimensions>::M, <Rhs as Dimensions>::M>: Integer,
Sum<<Lhs as Dimensions>::I, <Rhs as Dimensions>::I>: Integer,
Sum<<Lhs as Dimensions>::K, <Rhs as Dimensions>::K>: Integer,
Sum<<Lhs as Dimensions>::N, <Rhs as Dimensions>::N>: Integer,
Sum<<Lhs as Dimensions>::J, <Rhs as Dimensions>::J>: Integer,
{
type Output = DimensionMul<Lhs, Rhs>;
}
pub trait CanDivideBy<Rhs: Dimensions>: Dimensions {
type Output: Dimensions;
}
impl<Lhs, Rhs> CanDivideBy<Rhs> for Lhs
where
Lhs: Dimensions,
Rhs: Dimensions,
<Lhs as Dimensions>::T: Sub<<Rhs as Dimensions>::T>,
<Lhs as Dimensions>::L: Sub<<Rhs as Dimensions>::L>,
<Lhs as Dimensions>::M: Sub<<Rhs as Dimensions>::M>,
<Lhs as Dimensions>::I: Sub<<Rhs as Dimensions>::I>,
<Lhs as Dimensions>::K: Sub<<Rhs as Dimensions>::K>,
<Lhs as Dimensions>::N: Sub<<Rhs as Dimensions>::N>,
<Lhs as Dimensions>::J: Sub<<Rhs as Dimensions>::J>,
Diff<<Lhs as Dimensions>::T, <Rhs as Dimensions>::T>: Integer,
Diff<<Lhs as Dimensions>::L, <Rhs as Dimensions>::L>: Integer,
Diff<<Lhs as Dimensions>::M, <Rhs as Dimensions>::M>: Integer,
Diff<<Lhs as Dimensions>::I, <Rhs as Dimensions>::I>: Integer,
Diff<<Lhs as Dimensions>::K, <Rhs as Dimensions>::K>: Integer,
Diff<<Lhs as Dimensions>::N, <Rhs as Dimensions>::N>: Integer,
Diff<<Lhs as Dimensions>::J, <Rhs as Dimensions>::J>: Integer,
{
type Output = DimensionDiv<Lhs, Rhs>;
}
pub trait CanReciprocate: Dimensions {
type Output: Dimensions;
}
impl<D> CanReciprocate for D
where
D: Dimensions,
<D as Dimensions>::T: Neg,
<D as Dimensions>::L: Neg,
<D as Dimensions>::M: Neg,
<D as Dimensions>::I: Neg,
<D as Dimensions>::K: Neg,
<D as Dimensions>::N: Neg,
<D as Dimensions>::J: Neg,
Negate<<D as Dimensions>::T>: Integer,
Negate<<D as Dimensions>::L>: Integer,
Negate<<D as Dimensions>::M>: Integer,
Negate<<D as Dimensions>::I>: Integer,
Negate<<D as Dimensions>::K>: Integer,
Negate<<D as Dimensions>::N>: Integer,
Negate<<D as Dimensions>::J>: Integer,
{
type Output = DimensionRecip<D>;
}
#[doc(no_inline)]
pub use typenum::{N1, N2, N3, N4, P1, P2, P3, P4, Z0};
pub type Dimensionless = Dimension<Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
pub type Time = Dimension<P1, Z0, Z0, Z0, Z0, Z0, Z0>;
pub type Length = Dimension<Z0, P1, Z0, Z0, Z0, Z0, Z0>;
pub type Mass = Dimension<Z0, Z0, P1, Z0, Z0, Z0, Z0>;
pub type ElectricCurrent = Dimension<Z0, Z0, Z0, P1, Z0, Z0, Z0>;
pub type ThermodynamicTemperature = Dimension<Z0, Z0, Z0, Z0, P1, Z0, Z0>;
pub type AmountOfSubstance = Dimension<Z0, Z0, Z0, Z0, Z0, P1, Z0>;
pub type LuminousIntensity = Dimension<Z0, Z0, Z0, Z0, Z0, Z0, P1>;
pub type Area = Dimension<Z0, P2, Z0, Z0, Z0, Z0, Z0>;
pub type Volume = Dimension<Z0, P3, Z0, Z0, Z0, Z0, Z0>;
pub type Frequency = Dimension<N1, Z0, Z0, Z0, Z0, Z0, Z0>;
pub type Velocity = Dimension<N1, P1, Z0, Z0, Z0, Z0, Z0>;
pub type Acceleration = Dimension<N2, P1, Z0, Z0, Z0, Z0, Z0>;
pub type Force = Dimension<N2, P1, P1, Z0, Z0, Z0, Z0>;
pub type Energy = Dimension<N2, P2, P1, Z0, Z0, Z0, Z0>;
pub type Power = Dimension<N3, P2, P1, Z0, Z0, Z0, Z0>;
pub type Pressure = Dimension<N2, N1, P1, Z0, Z0, Z0, Z0>;
pub type MassFlowRate = Dimension<N1, Z0, P1, Z0, Z0, Z0, Z0>;
pub type ElectricCharge = Dimension<P1, Z0, Z0, P1, Z0, Z0, Z0>;
pub type Voltage = Dimension<N3, P2, P1, N1, Z0, Z0, Z0>;
pub type Resistance = Dimension<N3, P2, P1, N2, Z0, Z0, Z0>;
pub type Conductance = Dimension<P3, N2, N1, P2, Z0, Z0, Z0>;
pub type Capacitance = Dimension<P4, N2, N1, P2, Z0, Z0, Z0>;
pub type MagneticFlux = Dimension<N2, P2, P1, N1, Z0, Z0, Z0>;
pub type MagneticFluxDensity = Dimension<N2, Z0, P1, N1, Z0, Z0, Z0>;
pub type Inductance = Dimension<N2, P2, P1, N2, Z0, Z0, Z0>;
#[cfg(test)]
mod tests {
use super::*;
trait Same<T> {}
impl<T> Same<T> for T {}
fn check<A: Same<B>, B>() {}
#[test]
fn derivations_match() {
check::<Volume, DimensionPow<Length, typenum::P3>>();
check::<Area, DimensionMul<Length, Length>>();
check::<Volume, DimensionMul<Area, Length>>();
check::<Frequency, DimensionRecip<Time>>();
check::<Velocity, DimensionDiv<Length, Time>>();
check::<Acceleration, DimensionDiv<Velocity, Time>>();
check::<Force, DimensionMul<Mass, Acceleration>>();
check::<Energy, DimensionMul<Force, Length>>();
check::<Power, DimensionDiv<Energy, Time>>();
check::<Pressure, DimensionDiv<Force, Area>>();
check::<MassFlowRate, DimensionDiv<Mass, Time>>();
check::<ElectricCharge, DimensionMul<ElectricCurrent, Time>>();
check::<Voltage, DimensionDiv<Power, ElectricCurrent>>();
check::<Resistance, DimensionDiv<Voltage, ElectricCurrent>>();
check::<Conductance, DimensionRecip<Resistance>>();
check::<Capacitance, DimensionDiv<ElectricCharge, Voltage>>();
check::<MagneticFlux, DimensionMul<Voltage, Time>>();
check::<MagneticFluxDensity, DimensionDiv<MagneticFlux, Area>>();
check::<Inductance, DimensionDiv<MagneticFlux, ElectricCurrent>>();
}
}