danwi 0.4.1

Zero-cost dimensional analysis library with SI units, compile-time checking, and no_std support
Documentation

danwi

build Crates.io Version Crates.io License docs.rs

A zero-cost dimensional analysis library for Rust with SI units, compile-time type checking, and no_std support.

Usage

use danwi::prelude::*;

// dimensions combine at the type level; mismatches are compile errors
let v = 5.0.mA() * 2.0.kOhm();
assert_eq!(v, 10.0.V());

// convert and format in any unit of the same dimension
assert_eq!(v.to(mV), 10000.0);
println!("{}", v.display_as(mV)); // 10000 mV

// values are stored in SI base units, so mixed prefixes just work
let len = 100.0.m() + 50.0 * cm + 0.001 * km;
assert_eq!(len.value(), 101.5);

// non-SI units: minute, hour, Celsius, litre, inch, ...
let temp = 25.0.celsius();
assert_eq!(temp.to(K), 298.15);
println!("{}", temp.display_as(degC)); // 25 °C

Custom units are one line each; the built-in set is itself a single units! invocation:

mod imperial {
    danwi::units! {
        mile: danwi::dimension::Length { symbol: mi, scale: 1_609_344 / 1_000 },
    }
}

use danwi::prelude::*;
use imperial::ext::F64QuantityExt as _;

assert_eq!(1.0.mile(), 1609.344.m());

Some quantities share a dimension but mean different things: torque and energy are both M·L²·T⁻². Kinds keep them apart. Every quantity has an invisible default kind, so nothing changes until you opt in with cast_kind; a named kind only adds and compares with itself, and must be erased explicitly before multiplying:

use danwi::{kind::Torque, prelude::*};

let torque = (50.0.N() * 0.4.m()).cast_kind::<Torque>();
assert_eq!(torque + torque, (40.0.J()).cast_kind());
// torque + 5.0.J() does not compile; neither does torque / 2.0.s()
assert_eq!(torque.erase_kind(), 20.0.J());

Custom kinds are one line: danwi::kinds! { Activity; }.

Getting started

[dependencies]
danwi = "0.4"

The default scalar type is f64. For f32, enable the feature:

danwi = { version = "0.4", features = ["f32"] }                           # both
danwi = { version = "0.4", default-features = false, features = ["f32"] } # f32 only

Import the prelude and go:

use danwi::prelude::*;

let i = 12.0.V() / 4.0.kOhm();
assert_eq!(i, 3.0.mA());

With both scalar features enabled, an unsuffixed literal in value * unit syntax can be ambiguous (write 10.0_f64 * V); the extension methods (10.0.V()) never are.

Construction and conversion compile to at most one float op each, and everything in between is plain scalar arithmetic; verify with cargo rustc --release --example asm_check -- --emit=asm.