use std::ops;
use typenum::operator_aliases::{Diff, Sum};
use super::dim::Dim;
use super::qty::Qty;
#[allow(clippy::type_complexity)]
pub fn diff_qty<L1, M1, T1, I1, Th1, N1x, J1, L2, M2, T2, I2, Th2, N2x, J2>(
expr: &Qty<Dim<L1, M1, T1, I1, Th1, N1x, J1>>,
var: &Qty<Dim<L2, M2, T2, I2, Th2, N2x, J2>>,
) -> Qty<
Dim<
Diff<L1, L2>,
Diff<M1, M2>,
Diff<T1, T2>,
Diff<I1, I2>,
Diff<Th1, Th2>,
Diff<N1x, N2x>,
Diff<J1, J2>,
>,
>
where
L1: ops::Sub<L2>,
M1: ops::Sub<M2>,
T1: ops::Sub<T2>,
I1: ops::Sub<I2>,
Th1: ops::Sub<Th2>,
N1x: ops::Sub<N2x>,
J1: ops::Sub<J2>,
{
Qty::from_ex(expr.inner().diff(var.inner()))
}
#[allow(clippy::type_complexity)]
pub fn integrate_qty<L1, M1, T1, I1, Th1, N1x, J1, L2, M2, T2, I2, Th2, N2x, J2>(
expr: &Qty<Dim<L1, M1, T1, I1, Th1, N1x, J1>>,
var: &Qty<Dim<L2, M2, T2, I2, Th2, N2x, J2>>,
) -> Qty<
Dim<
Sum<L1, L2>,
Sum<M1, M2>,
Sum<T1, T2>,
Sum<I1, I2>,
Sum<Th1, Th2>,
Sum<N1x, N2x>,
Sum<J1, J2>,
>,
>
where
L1: ops::Add<L2>,
M1: ops::Add<M2>,
T1: ops::Add<T2>,
I1: ops::Add<I2>,
Th1: ops::Add<Th2>,
N1x: ops::Add<N2x>,
J1: ops::Add<J2>,
{
Qty::from_ex(expr.inner().integrate(var.inner()))
}
#[cfg(test)]
mod tests {
use super::super::dim::*;
use super::super::si::*;
use super::*;
#[test]
fn diff_length_by_time_is_velocity() {
let ctx = crate::api::context::Context::new();
let x: Qty<LengthDim> = Qty::from_ex(ctx.symbol("x"));
let t: Qty<TimeDim> = Qty::from_ex(ctx.symbol("t"));
let result = diff_qty(&x, &t);
let _v: Velocity = result.into();
}
#[test]
fn diff_velocity_by_time_is_acceleration() {
let ctx = crate::api::context::Context::new();
let v: Qty<VelocityDim> = Qty::from_ex(ctx.symbol("v"));
let t: Qty<TimeDim> = Qty::from_ex(ctx.symbol("t"));
let result = diff_qty(&v, &t);
let _a: Acceleration = result.into();
}
#[test]
fn diff_energy_by_length_is_force() {
let ctx = crate::api::context::Context::new();
let e: Qty<EnergyDim> = Qty::from_ex(ctx.symbol("E"));
let x: Qty<LengthDim> = Qty::from_ex(ctx.symbol("x"));
let result = diff_qty(&e, &x);
let _f: Force = result.into();
}
#[test]
fn integrate_force_over_length_is_energy() {
let ctx = crate::api::context::Context::new();
let f: Qty<ForceDim> = Qty::from_ex(ctx.symbol("F"));
let x: Qty<LengthDim> = Qty::from_ex(ctx.symbol("x"));
let result = integrate_qty(&f, &x);
let _w: Energy = result.into();
}
#[test]
fn integrate_velocity_over_time_is_length() {
let ctx = crate::api::context::Context::new();
let v: Qty<VelocityDim> = Qty::from_ex(ctx.symbol("v"));
let t: Qty<TimeDim> = Qty::from_ex(ctx.symbol("t"));
let result = integrate_qty(&v, &t);
let _x: Length = result.into();
}
#[test]
fn ftc_roundtrip_velocity() {
let ctx = crate::api::context::Context::new();
let v: Qty<VelocityDim> = Qty::from_ex(ctx.symbol("v"));
let t: Qty<TimeDim> = Qty::from_ex(ctx.symbol("t"));
let integrated = integrate_qty(&v, &t);
let t2: Qty<TimeDim> = Qty::from_ex(ctx.symbol("t"));
let roundtrip = diff_qty(&integrated, &t2);
let _v2: Velocity = roundtrip.into();
}
#[test]
fn named_type_workflow() {
let ctx = crate::api::context::Context::new();
let x = Length::symbol(&ctx, "x");
let t = Time::symbol(&ctx, "t");
let v: Velocity = diff_qty(&x.as_qty(), &t.as_qty()).into();
assert_eq!(Velocity::dim_name_str(), "Velocity");
assert_eq!(Velocity::dim_symbol_str(), "m/s");
let _ = v;
}
}
pub trait DiffWrt<Var> {
type Output;
fn diff_wrt(&self, var: &Var) -> Self::Output;
}
pub trait IntWrt<Var> {
type Output;
fn integrate_wrt(&self, var: &Var) -> Self::Output;
}
macro_rules! impl_diff_wrt {
($Expr:ty, $Var:ty => $Out:ty) => {
impl DiffWrt<$Var> for $Expr {
type Output = $Out;
fn diff_wrt(&self, var: &$Var) -> $Out {
<$Out>::from_ex(self.inner().diff(var.inner()))
}
}
};
}
macro_rules! impl_int_wrt {
($Expr:ty, $Var:ty => $Out:ty) => {
impl IntWrt<$Var> for $Expr {
type Output = $Out;
fn integrate_wrt(&self, var: &$Var) -> $Out {
<$Out>::from_ex(self.inner().integrate(var.inner()))
}
}
};
}
use super::si::*;
impl_diff_wrt!(Length, Time => Velocity);
impl_diff_wrt!(Velocity, Time => Acceleration);
impl_diff_wrt!(Angle, Time => AngularVelocity);
impl_diff_wrt!(AngularVelocity, Time => AngularAcceleration);
impl_diff_wrt!(Energy, Time => Power);
impl_diff_wrt!(Momentum, Time => Force);
impl_diff_wrt!(AngularMomentum, Time => Torque);
impl_diff_wrt!(Charge, Time => Current);
impl_diff_wrt!(MagneticFlux, Time => Voltage);
impl_diff_wrt!(Energy, Length => Force);
impl_diff_wrt!(Energy, Angle => Torque);
impl_diff_wrt!(Momentum, Length => Stiffness); impl_diff_wrt!(Force, Length => Stiffness);
impl_diff_wrt!(Energy, Velocity => Momentum);
impl_diff_wrt!(Energy, AngularVelocity => AngularMomentum);
impl_diff_wrt!(Power, Current => Voltage);
impl_diff_wrt!(Power, Voltage => Current);
impl_int_wrt!(Velocity, Time => Length);
impl_int_wrt!(Acceleration, Time => Velocity);
impl_int_wrt!(AngularVelocity, Time => Angle);
impl_int_wrt!(AngularAcceleration, Time => AngularVelocity);
impl_int_wrt!(Power, Time => Energy);
impl_int_wrt!(Force, Time => Momentum);
impl_int_wrt!(Torque, Time => AngularMomentum);
impl_int_wrt!(Current, Time => Charge);
impl_int_wrt!(Voltage, Time => MagneticFlux);
impl_int_wrt!(Force, Length => Energy);
impl_int_wrt!(Stiffness, Length => Force);
impl_int_wrt!(Momentum, Velocity => Energy); impl_int_wrt!(AngularMomentum, AngularVelocity => Energy);
impl_diff_wrt!(Length, Angle => Length);
impl_diff_wrt!(Velocity, Angle => Velocity);
impl_diff_wrt!(Acceleration, Angle => Acceleration);
impl_diff_wrt!(Force, Angle => Force);
impl_diff_wrt!(Torque, Angle => Torque);
impl_diff_wrt!(AngularMomentum, Angle => AngularMomentum);
impl_diff_wrt!(MomentOfInertia, Angle => MomentOfInertia);
impl_int_wrt!(Torque, Angle => Energy); impl_int_wrt!(Length, Angle => Length); impl_int_wrt!(Force, Angle => Force);
impl_int_wrt!(AngularMomentum, Angle => AngularMomentum);