danwi 0.4.2

Zero-cost dimensional analysis library with SI units, compile-time checking, and no_std support
Documentation
use super::{
    Quantity,
    kind::{Anon, KindAdd, KindDiv, KindMul, KindSub},
};
use crate::{
    dimension::{CanDivideBy, CanMultiplyWith, CanReciprocate, Dimensions},
    scalar::Scalar,
};
use core::ops::{Add, Div, Mul, Neg, Sub};

// Add / Sub: same dimension, single scalar op (no scaling: both sides are
// already in the SI base unit). Kinds combine through the `Kind*` traits;
// for the default `Anon` kind everything below behaves as if kinds did not
// exist.

impl<S, D, K1, K2> Add<Quantity<S, D, K2>> for Quantity<S, D, K1>
where
    S: Scalar,
    D: Dimensions,
    K1: KindAdd<K2>,
{
    type Output = Quantity<S, D, <K1 as KindAdd<K2>>::Output>;

    #[inline(always)]
    fn add(self, rhs: Quantity<S, D, K2>) -> Self::Output {
        Quantity::from_base(self.value + rhs.value)
    }
}

impl<S, D, K1, K2> Sub<Quantity<S, D, K2>> for Quantity<S, D, K1>
where
    S: Scalar,
    D: Dimensions,
    K1: KindSub<K2>,
{
    type Output = Quantity<S, D, <K1 as KindSub<K2>>::Output>;

    #[inline(always)]
    fn sub(self, rhs: Quantity<S, D, K2>) -> Self::Output {
        Quantity::from_base(self.value - rhs.value)
    }
}

// Mul / Div: dimensions combine at the type level. Named kinds have no
// `KindMul`/`KindDiv` impls, so they must be erased first.

impl<S, D1, D2, K1, K2> Mul<Quantity<S, D2, K2>> for Quantity<S, D1, K1>
where
    S: Scalar,
    D1: CanMultiplyWith<D2>,
    D2: Dimensions,
    K1: KindMul<K2>,
{
    type Output = Quantity<S, <D1 as CanMultiplyWith<D2>>::Output, <K1 as KindMul<K2>>::Output>;

    #[inline(always)]
    fn mul(self, rhs: Quantity<S, D2, K2>) -> Self::Output {
        Quantity::from_base(self.value * rhs.value)
    }
}

impl<S, D1, D2, K1, K2> Div<Quantity<S, D2, K2>> for Quantity<S, D1, K1>
where
    S: Scalar,
    D1: CanDivideBy<D2>,
    D2: Dimensions,
    K1: KindDiv<K2>,
{
    type Output = Quantity<S, <D1 as CanDivideBy<D2>>::Output, <K1 as KindDiv<K2>>::Output>;

    #[inline(always)]
    fn div(self, rhs: Quantity<S, D2, K2>) -> Self::Output {
        Quantity::from_base(self.value / rhs.value)
    }
}

// Scalar on either side: dimension and kind preserved.

#[cfg(feature = "f32")]
impl<D: Dimensions, K> Mul<f32> for Quantity<f32, D, K> {
    type Output = Quantity<f32, D, K>;

    #[inline(always)]
    fn mul(self, rhs: f32) -> Self::Output {
        Quantity::from_base(self.value * rhs)
    }
}

#[cfg(feature = "f64")]
impl<D: Dimensions, K> Mul<f64> for Quantity<f64, D, K> {
    type Output = Quantity<f64, D, K>;

    #[inline(always)]
    fn mul(self, rhs: f64) -> Self::Output {
        Quantity::from_base(self.value * rhs)
    }
}

#[cfg(feature = "f32")]
impl<D: Dimensions, K> Mul<Quantity<f32, D, K>> for f32 {
    type Output = Quantity<f32, D, K>;

    #[inline(always)]
    fn mul(self, rhs: Quantity<f32, D, K>) -> Self::Output {
        Quantity::from_base(self * rhs.value)
    }
}

#[cfg(feature = "f64")]
impl<D: Dimensions, K> Mul<Quantity<f64, D, K>> for f64 {
    type Output = Quantity<f64, D, K>;

    #[inline(always)]
    fn mul(self, rhs: Quantity<f64, D, K>) -> Self::Output {
        Quantity::from_base(self * rhs.value)
    }
}

#[cfg(feature = "f32")]
impl<D: Dimensions, K> Div<f32> for Quantity<f32, D, K> {
    type Output = Quantity<f32, D, K>;

    #[inline(always)]
    fn div(self, rhs: f32) -> Self::Output {
        Quantity::from_base(self.value / rhs)
    }
}

#[cfg(feature = "f64")]
impl<D: Dimensions, K> Div<f64> for Quantity<f64, D, K> {
    type Output = Quantity<f64, D, K>;

    #[inline(always)]
    fn div(self, rhs: f64) -> Self::Output {
        Quantity::from_base(self.value / rhs)
    }
}

// Scalar / Quantity = reciprocal of the dimension. The scalar is anonymous,
// so the quantity's kind must divide out of `Anon` (only `Anon` does).

#[cfg(feature = "f32")]
impl<D, K> Div<Quantity<f32, D, K>> for f32
where
    D: CanReciprocate,
    Anon: KindDiv<K>,
{
    type Output = Quantity<f32, <D as CanReciprocate>::Output, <Anon as KindDiv<K>>::Output>;

    #[inline(always)]
    fn div(self, rhs: Quantity<f32, D, K>) -> Self::Output {
        Quantity::from_base(self / rhs.value)
    }
}

#[cfg(feature = "f64")]
impl<D, K> Div<Quantity<f64, D, K>> for f64
where
    D: CanReciprocate,
    Anon: KindDiv<K>,
{
    type Output = Quantity<f64, <D as CanReciprocate>::Output, <Anon as KindDiv<K>>::Output>;

    #[inline(always)]
    fn div(self, rhs: Quantity<f64, D, K>) -> Self::Output {
        Quantity::from_base(self / rhs.value)
    }
}

// Negation is unconditional and keeps the kind.

impl<S: Scalar, D: Dimensions, K> Neg for Quantity<S, D, K> {
    type Output = Quantity<S, D, K>;

    #[inline(always)]
    fn neg(self) -> Self::Output {
        Quantity::from_base(-self.value)
    }
}