use crate::dimension::{
Acceleration, AmountOfSubstance, Angular, Area, Current, Energy, Force, FrequencyDim, Length,
LuminousIntensity, Mass, Power, Temperature, Time, VelocityDim, Volume,
};
use crate::scalar::Scalar;
use crate::{Quantity, Unit, Unitless};
trait SupportedDimension {}
impl SupportedDimension for Length {}
impl SupportedDimension for Time {}
impl SupportedDimension for Mass {}
impl SupportedDimension for Temperature {}
impl SupportedDimension for Current {}
impl SupportedDimension for AmountOfSubstance {}
impl SupportedDimension for LuminousIntensity {}
impl SupportedDimension for Angular {}
impl SupportedDimension for Area {}
impl SupportedDimension for Volume {}
impl SupportedDimension for VelocityDim {}
impl SupportedDimension for Acceleration {}
impl SupportedDimension for Force {}
impl SupportedDimension for Energy {}
impl SupportedDimension for Power {}
impl SupportedDimension for FrequencyDim {}
trait DimensionedUnit: Unit {}
impl<U: Unit> DimensionedUnit for U where U::Dim: SupportedDimension {}
impl<U: DimensionedUnit, S: Scalar> From<Quantity<U, S>> for Quantity<Unitless, S> {
#[inline]
fn from(quantity: Quantity<U, S>) -> Self {
Self::new(quantity.value())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::units::angular::Degrees;
use crate::units::length::Meters;
use crate::units::mass::Kilogram;
use crate::units::mass::Kilograms;
use crate::units::time::Seconds;
use crate::Unit;
use approx::assert_abs_diff_eq;
use proptest::prelude::*;
#[test]
fn unitless_new_and_value() {
let u: Quantity<Unitless> = Quantity::new(42.0);
assert_eq!(u.value(), 42.0);
}
#[test]
fn unitless_from_f64() {
let u: Quantity<Unitless> = 1.23456.into();
assert_abs_diff_eq!(u.value(), 1.23456, epsilon = 1e-12);
}
#[test]
fn display_unitless() {
let u: Quantity<Unitless> = Quantity::new(123.456);
let s = format!("{}", u);
assert_eq!(s, "123.456");
}
#[test]
fn display_unitless_integer() {
let u: Quantity<Unitless> = Quantity::new(42.0);
let s = format!("{}", u);
assert_eq!(s, "42");
}
#[test]
fn from_length() {
let m = Meters::new(42.0);
let u: Quantity<Unitless> = m.into();
assert_eq!(u.value(), 42.0);
}
#[test]
fn from_time() {
let t = Seconds::new(5.0);
let u: Quantity<Unitless> = t.into();
assert_eq!(u.value(), 5.0);
}
#[test]
fn from_mass() {
let m = Kilograms::new(2.5);
let u: Quantity<Unitless> = m.into();
assert_eq!(u.value(), 2.5);
}
#[test]
fn from_angular() {
let a = Degrees::new(90.0);
let u: Quantity<Unitless> = a.into();
assert_eq!(u.value(), 90.0);
}
#[test]
fn from_mass_preserves_non_default_scalar_type() {
let m: Quantity<Kilogram, i32> = Quantity::new(7);
let u: Quantity<Unitless, i32> = m.into();
assert_eq!(u.value(), 7);
}
#[test]
fn unitless_addition() {
let a: Quantity<Unitless> = Quantity::new(3.0);
let b: Quantity<Unitless> = Quantity::new(4.0);
assert_eq!((a + b).value(), 7.0);
}
#[test]
fn unitless_subtraction() {
let a: Quantity<Unitless> = Quantity::new(10.0);
let b: Quantity<Unitless> = Quantity::new(3.0);
assert_eq!((a - b).value(), 7.0);
}
#[test]
fn unitless_multiplication() {
let a: Quantity<Unitless> = Quantity::new(3.0);
assert_eq!((a * 4.0).value(), 12.0);
}
#[test]
fn unitless_division() {
let a: Quantity<Unitless> = Quantity::new(12.0);
assert_eq!((a / 4.0).value(), 3.0);
}
#[test]
fn unitless_ratio() {
assert_eq!(Unitless::RATIO, 1.0);
}
#[test]
fn unitless_symbol() {
assert_eq!(Unitless::SYMBOL, "");
}
proptest! {
#[test]
fn prop_unitless_arithmetic(a in -1e6..1e6f64, b in -1e6..1e6f64) {
let qa: Quantity<Unitless> = Quantity::new(a);
let qb: Quantity<Unitless> = Quantity::new(b);
prop_assert!((((qa + qb).value() - (qb + qa).value()).abs() < 1e-9));
prop_assert!(((qa + qb).value() - (a + b)).abs() < 1e-9);
}
#[test]
fn prop_from_length_preserves_value(v in -1e6..1e6f64) {
let m = Meters::new(v);
let u: Quantity<Unitless> = m.into();
prop_assert!((u.value() - v).abs() < 1e-12);
}
#[test]
fn prop_from_time_preserves_value(v in -1e6..1e6f64) {
let t = Seconds::new(v);
let u: Quantity<Unitless> = t.into();
prop_assert!((u.value() - v).abs() < 1e-12);
}
}
}