#dimensional-analysis #unit-conversion #si-units #units #measurement #unit #si

no-std runtime_units

A run-time Rust library for working with units of measurement and conversions between them

14 releases

0.3.0 Jun 11, 2024
0.2.5 Apr 16, 2024
0.2.3 Mar 20, 2024
0.1.6 Mar 12, 2024
0.1.1 Feb 28, 2024

#56 in Value formatting

MIT license

725KB
8K SLoC

runtime_units

The goal for this library is to serve as a run-time Rust library for working with units of measurement and conversions between them. Most robust units libraries for Rust are designed for compile-time constant analysis. If one of those crates meets your needs, you should probably use one of those instead.

Much of the code (particularly the unit definitions) were adapted from the excellent uom library (https://github.com/iliekturtles/uom). This library was designed to support cases where compile time analysis isn't a great fit. This can presently handle conversions of everything supported by uom except temperature (temperature intervals are supported).

Usage

An example of including all units and serialization support:

[dependencies]
runtime_units = { version = "0.3.0", features = ["All", "serde"] }

no_std is supported if the std feature flag is removed.

Individual unit types are supported as features, allowing you to pare down the library to what you need. Serialization is optionally supported via the serde feature tag, and utoipa schemas can optionally be generated via the utoipa tag. By default, only the base SI units are enabled (https://en.wikipedia.org/wiki/SI_base_unit).

Quantities and Units

This library consists of three sets of data structures:

  1. Unit data structures. These store data regarding unit itself, and the storage of the unit definition itself (e.g. the dimensions of the unit, and the conversion factor to convert a given unit to its base quantity). These can be serialized (if serde is enabled), and converted to a utoipa schema (if the utoipa feature flag is enabled).
  2. Scalar Quantity data structures. These store a scalar value and an associated unit. Also serializable like the units, and most math operations can be performed on them directly (e.g. scalar Mul/Div, multipliying quantites by each other, equality operators).
  3. Array Quantity data structures. These store an array and an associated unit. Analogous to (2).

More details:

All available units are contained in the Units enum. Lists of available units can be easily retrieved from the UnitTypes enum. For each quantity processed (depending on the features you compile with), a unit enumeration is created for each unit type (e.g. LengthUnit, EnergyUnit).

Quantities contain a value (currently restricted to f64), and the unit enumeration mentioned above to store the unit. These are then converted to QuantityBase. All available quantities can be encapsulated in the Quantities enum. A struct is created for each quantity (e.g. Length, Area), and these contain methods to convert from a Units, or its own internal unit enumeration. As an example, Length can convert from a given LengthUnit, and contains helper methods to convert from its current unit to any of the other enumerations (e.g. to_meters(), to_kilometers(), etc.).

Example:

use runtime_units::{Length, Acceleration, UnitTypes, Units, QuantityBase, Time};

fn example()
{
    let length = Length::meter(10.0);
    let length_cm = length.to_centimeter();
    assert_eq!(length, length_cm);
    let velocity = Acceleration::meter_per_second_squared(1.0) * Time::second(10.0);
    assert_eq!(length / Time::second(1.0), velocity); 

    let unit = Units::Length(units::LengthUnit::angstrom);
    let _ = length.try_convert(unit).unwrap();

    // list units available for Length:
    for unit in UnitTypes::Length.units()
    {
        println!("{unit}");
    }

    let quantity = Quantities::Acceleration(Acceleration::centimeter_per_second_squared(10.0));
    assert_eq!(velocity, QuantityBase::from(quantity) * Time::second(100.0));

    // Get a unit type from a string
    let _units = UnitTypes::Length.to_unit("m").unwrap();

    // Different ways to print base units of a quantity
    println!("Base Units of Velocity = {}", velocity.definition().unit_string());
    println!("Base Units of Acceleration = {}", Acceleration::meter_per_second_squared(1.0).definition().unit_string());
    
}

Performance

Currently conversions on my laptop cost < 1 nsec if converting between the same quantity, and up to 3 nsec using the convert method from Quantity.

API Stability

This library is still a work in progress. Expect futher changes to the API as it matures.

Pull requests are welcome. For the most part conversions are based on UOM data.

Dependencies

~0.3–1.9MB
~39K SLoC