unitforge 0.4.3

A library for unit and quantity consistent computations in Rust
Documentation
#![cfg(feature = "serde")]

#[cfg(feature = "ndarray")]
use ndarray::arr1;
use unitforge::quantities::{Force, ForceUnit};
use unitforge::small_linalg::{Matrix3, Vector3};
use unitforge::PhysicsQuantity;
#[cfg(not(any(feature = "storage-f64", feature = "storage-f32")))]
use unitforge::MAX_ABS_QUANTITY_POWER;

#[test]
fn roundtrip_quantity() {
    let original = Force::new(100.0, ForceUnit::kN);

    let json = serde_json::to_string(&original).expect("Failed to serialize");
    let deserialized: Force = serde_json::from_str(&json).expect("Failed to deserialize");

    assert_eq!(deserialized.to(ForceUnit::N), original.to(ForceUnit::N));
}

#[test]
#[cfg(feature = "ndarray")]
fn roundtrip_quantity_ndarray() {
    let original = arr1(&[
        Force::new(50.0, ForceUnit::kN),
        Force::new(75.0, ForceUnit::kN),
    ]);

    let json = serde_json::to_string(&original).expect("Failed to serialize");
    let deserialized: ndarray::Array1<Force> =
        serde_json::from_str(&json).expect("Failed to deserialize");

    assert_eq!(
        deserialized[1].to(ForceUnit::N),
        original[1].to(ForceUnit::N)
    );
}

#[test]
fn roundtrip_vector() {
    let original: Vector3<Force> = Vector3::from_f64([1.0, 2.0, 3.0]);

    let json = serde_json::to_string(&original).expect("Failed to serialize");
    let deserialized: Vector3<Force> = serde_json::from_str(&json).expect("Failed to deserialize");

    assert_eq!(deserialized, original);
}

#[test]
fn roundtrip_matrix() {
    let mat = Matrix3::new([[3.0_f64; 3]; 3]);
    let force = Force::new(1.0, ForceUnit::kN);
    let original = mat * force;

    let json = serde_json::to_string(&original).expect("Failed to serialize");
    let deserialized: Matrix3<Force> = serde_json::from_str(&json).expect("Failed to deserialize");

    for i in 0..3 {
        for j in 0..3 {
            assert_eq!(deserialized[(i, j)], Force::new(3.0, ForceUnit::kN));
        }
    }
}

#[test]
#[cfg(not(any(feature = "storage-f64", feature = "storage-f32")))]
fn deserialize_canonicalizes_unnormalized_quantity_parts() {
    let deserialized: Force =
        serde_json::from_str(r#"{"multiplier":1000.0,"power":0}"#).expect("deserialize force");

    assert_eq!(deserialized.get_tuple(), (1.0, 3));
    assert_eq!(deserialized.to(ForceUnit::N), 1000.0);
}

#[test]
#[cfg(not(any(feature = "storage-f64", feature = "storage-f32")))]
fn deserialize_saturates_large_positive_power_to_infinity() {
    let json = format!(r#"{{"multiplier":1.0,"power":{}}}"#, MAX_ABS_QUANTITY_POWER);
    let deserialized: Force = serde_json::from_str(&json).expect("deserialize force");

    assert!(deserialized.as_f64().is_infinite());
    assert!(deserialized.as_f64().is_sign_positive());
    assert_eq!(deserialized.get_power(), 0);
}

#[test]
#[cfg(not(any(feature = "storage-f64", feature = "storage-f32")))]
fn deserialize_saturates_large_negative_power_to_zero() {
    let json = format!(
        r#"{{"multiplier":1.0,"power":{}}}"#,
        -MAX_ABS_QUANTITY_POWER
    );
    let deserialized: Force = serde_json::from_str(&json).expect("deserialize force");

    assert_eq!(deserialized.get_tuple(), (0.0, 0));
    assert_eq!(deserialized.to(ForceUnit::N), 0.0);
}

#[test]
#[cfg(any(feature = "storage-f64", feature = "storage-f32"))]
fn plain_storage_serializes_value_field() {
    let original = Force::new(100.0, ForceUnit::kN);

    let json = serde_json::to_value(original).expect("serialize force");
    assert_eq!(
        json.get("value").and_then(|value| value.as_f64()),
        Some(100000.0)
    );
    assert!(json.get("multiplier").is_none());
    assert!(json.get("power").is_none());
}

#[test]
#[cfg(any(feature = "storage-f64", feature = "storage-f32"))]
fn plain_storage_deserializes_value_field() {
    let deserialized: Force =
        serde_json::from_str(r#"{"value":1000.0}"#).expect("deserialize force");

    assert_eq!(deserialized.as_f64(), 1000.0);
    assert_eq!(deserialized.to(ForceUnit::N), 1000.0);
}