absolute_unit 0.11.4

A unit system for Rust's type system to catch unit errors in your physical calculations.
Documentation
use crate::{
    Acceleration, Length, LengthUnit, Real, Scalar, Unit, V3, Velocity,
    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, ops::Mul};

pub trait TimeUnit: Unit + Copy + Debug + Eq + PartialEq + 'static {
    const SECONDS_IN_UNIT: f64;
}

#[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 Time<Unit: TimeUnit> {
    v: Real,
    #[cfg_attr(feature = "serde", serde(skip))]
    #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
    phantom_1: PhantomData<Unit>,
}
supports_quantity_ops!(Time<A>, TimeUnit);
supports_shift_ops!(Time<A1>, Time<A2>, TimeUnit);
supports_scalar_ops!(Time<A>, TimeUnit);
supports_cancellation!(Time<A1>, Time<A2>, TimeUnit);
supports_absdiffeq!(Time<A>, TimeUnit);
supports_value_type_conversion!(Time<A>, TimeUnit, impl_value_type_conversions);

impl<Unit> fmt::Display for Time<Unit>
where
    Unit: TimeUnit,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0.4}{}", self.v, Unit::UNIT_SHORT_NAME)
    }
}

impl<'a, UnitA, UnitB> From<&'a Time<UnitA>> for Time<UnitB>
where
    UnitA: TimeUnit,
    UnitB: TimeUnit,
{
    fn from(v: &'a Time<UnitA>) -> Self {
        Self {
            v: v.v * Real(UnitA::SECONDS_IN_UNIT / UnitB::SECONDS_IN_UNIT),
            phantom_1: PhantomData,
        }
    }
}

impl<UnitT0, UnitL, UnitT1> Mul<V3<Velocity<UnitL, UnitT1>>> for Time<UnitT0>
where
    UnitT0: TimeUnit,
    UnitL: LengthUnit,
    UnitT1: TimeUnit,
{
    type Output = V3<Length<UnitL>>;

    fn mul(self, rhs: V3<Velocity<UnitL, UnitT1>>) -> Self::Output {
        V3::new_dvec3(*rhs.dvec3() * Time::<UnitT1>::from(&self).f64())
    }
}

impl<UnitT0, UnitL, UnitT1> Mul<Time<UnitT0>> for V3<Velocity<UnitL, UnitT1>>
where
    UnitT0: TimeUnit,
    UnitL: LengthUnit,
    UnitT1: TimeUnit,
{
    type Output = V3<Length<UnitL>>;

    fn mul(self, rhs: Time<UnitT0>) -> Self::Output {
        V3::new_dvec3(*self.dvec3() * Time::<UnitT1>::from(&rhs).f64())
    }
}

impl<UnitT0, UnitL, UnitT1> Mul<V3<Acceleration<UnitL, UnitT1>>> for Time<UnitT0>
where
    UnitT0: TimeUnit,
    UnitL: LengthUnit,
    UnitT1: TimeUnit,
{
    type Output = V3<Velocity<UnitL, UnitT1>>;

    fn mul(self, rhs: V3<Acceleration<UnitL, UnitT1>>) -> Self::Output {
        V3::new_dvec3(*rhs.dvec3() * Time::<UnitT1>::from(&self).f64())
    }
}

impl<UnitL, UnitT0, UnitT1> Mul<Time<UnitT0>> for V3<Acceleration<UnitL, UnitT1>>
where
    UnitL: LengthUnit,
    UnitT0: TimeUnit,
    UnitT1: TimeUnit,
{
    type Output = V3<Velocity<UnitL, UnitT1>>;

    fn mul(self, other: Time<UnitT0>) -> Self::Output {
        V3::<Velocity<UnitL, UnitT1>>::new_dvec3(self.dvec3() * Time::<UnitT1>::from(&other).f64())
    }
}

#[cfg(test)]
mod test {
    use crate::{hours, scalar, seconds};
    use approx::assert_abs_diff_eq;

    #[test]
    fn test_time() {
        let h = hours!(1);
        println!("h: {h}");
        println!("s: {}", seconds!(h));
        assert_abs_diff_eq!(seconds!(h), seconds!(3_600));
    }

    #[test]
    fn test_time_scalar() {
        assert_abs_diff_eq!(seconds!(2) * scalar!(2), seconds!(4));
    }
}