absolute_unit 0.11.4

A unit system for Rust's type system to catch unit errors in your physical calculations.
Documentation
use crate::{
    DynamicUnits, ForceUnit, LengthUnit, Real, impl_value_type_conversions, supports_absdiffeq,
    supports_cancellation, supports_quantity_ops, supports_scalar_ops, supports_shift_ops,
    supports_value_type_conversion,
};
use std::{fmt, fmt::Debug, marker::PhantomData};

#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub struct Torque<UnitForce: ForceUnit, UnitLength: LengthUnit> {
    v: Real,
    #[cfg_attr(feature = "serde", serde(skip))]
    #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
    phantom_1: PhantomData<UnitForce>,
    #[cfg_attr(feature = "serde", serde(skip))]
    #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
    phantom_2: PhantomData<UnitLength>,
}
supports_quantity_ops!(Torque<A, B>, ForceUnit, LengthUnit);
supports_shift_ops!(Torque<A1, B1>, Torque<A2, B2>, ForceUnit, LengthUnit);
supports_scalar_ops!(Torque<A, B>, ForceUnit, LengthUnit);
supports_cancellation!(Torque<A1, B1>, Torque<A2, B2>, ForceUnit, LengthUnit);
supports_absdiffeq!(Torque<A, B>, ForceUnit, LengthUnit);
supports_value_type_conversion!(Torque<A, B>, ForceUnit, LengthUnit, impl_value_type_conversions);

impl<F, L> fmt::Display for Torque<F, L>
where
    F: ForceUnit,
    L: LengthUnit,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.v.0, f)?;
        write!(f, "{}*{}", F::UNIT_SHORT_NAME, L::UNIT_SHORT_NAME)
    }
}

impl<'a, FA, LA, FB, LB> From<&'a Torque<FA, LA>> for Torque<FB, LB>
where
    FA: ForceUnit,
    LA: LengthUnit,
    FB: ForceUnit,
    LB: LengthUnit,
{
    fn from(v: &'a Torque<FA, LA>) -> Self {
        let force_ratio = Real(FA::NEWTONS_IN_UNIT / FB::NEWTONS_IN_UNIT);
        let length_ratio = Real(LA::METERS_IN_UNIT / LB::METERS_IN_UNIT);
        Self {
            v: v.v * force_ratio * length_ratio,
            phantom_1: PhantomData,
            phantom_2: PhantomData,
        }
    }
}

impl<F, L> Torque<F, L>
where
    F: ForceUnit,
    L: LengthUnit,
{
    pub fn as_dyn(&self) -> DynamicUnits {
        DynamicUnits::new3o2::<F::UnitMass, F::UnitLength, L, F::UnitTime, F::UnitTime>(self.v)
    }
}

impl<F, L> From<DynamicUnits> for Torque<F, L>
where
    F: ForceUnit,
    L: LengthUnit,
{
    fn from(v: DynamicUnits) -> Self {
        let f = v.real();
        v.assert_units_equal(DynamicUnits::new3o2::<
            F::UnitMass,
            F::UnitLength,
            L,
            F::UnitTime,
            F::UnitTime,
        >(Real::ZERO));
        Self {
            v: f,
            phantom_1: PhantomData,
            phantom_2: PhantomData,
        }
    }
}

#[cfg(test)]
mod test {
    use crate::newton_meters;
    use approx::assert_abs_diff_eq;

    #[test]
    fn test_torque() {
        let nm = newton_meters!(100.);
        println!("{nm}");
        assert_abs_diff_eq!(nm, newton_meters!(100.));
    }
}