A simple unit system for Rust
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src
tests
.gitignore
.travis.yml
CHANGELOG.md
Cargo.toml
LICENSE
README.md

README.md

MIT licensed

simple_units

A simple unit system for Rust.

It allows you to write numeric code that is not only type safe but also "unit safe".

It works on stable Rust, but unfortunately that means it doesn't scale. All units (and combination of them) must be written by hand. Macros help (and maybe some more macro magic can help more) but it is still a lot of work.

For me it already payed off: I found a small bug in an old Fortran program we are using ;-)

So if your favorite unit is missing just let me know.

There already is a better unit system for Rust: Dimensioned, needs at least Rust 1.15.

And another one here: runits, here: units and here: uom

There is also a crate to help you convert between units: rink-rs

Notes

There are some blog posts / notes about unit systems in Rust:

https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/

https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

https://github.com/jaheba/stuff/blob/master/communicating_intent.md

https://www.reddit.com/r/rust/comments/5uacxs/types_units_and_quantities/

Examples:

extern crate simple_units;
use simple_units::si_units::*;

fn main() {
    let length = Meter(20.72);
    let time = Second(12.39);

    // Resulting type: MeterPerSecond
    let velocity = length / time;

    // This will not compile:
    // let error = length + time;

    // Multiply by Second gives you Meter:
    let duration = Second(35.0);
    let distance: Meter = velocity * duration;
    // Type (= unit) not needed, will be inferred:
    let distance2 = velocity * duration;
}

Conversion is also supported:

extern crate simple_units;
use simple_units::si_units::*;
use simple_units::conversion::*;

fn main() {
    let length_in_m = Meter(20.72);
    // Explicit conversion, unit implements ``from``
    let length_in_foot = Foot::from(length_in_m);

    // Compile error:
    // let length_sum = length_in_m + length_in_foot;

    // But this works:
    let length_sum = length_in_m + length_in_foot.into();

    let temperature_in_degc = DegC(20.7);
    // You must provide the type (= unit) here
    let temperature_in_k: Kelvin = temperature_in_degc.into();
}

It would be nice if Rust would allow to implement the as operator. Then you could write s.th. like this:

extern crate simple_units;
use simple_units::si_units::*;
use simple_units::conversion::*;

fn main() {
    let length_in_m = Meter(20.72);
    let length_in_foot = Foot(12.56);

    // Does not work (yet ?)
    // let length_sum = length_in_m + (length_in_foot as Meter);
}

I have plans for a better unit system, based on build.rs and comments: Basically that means to scan all *.rs Rust source files and evaluate the expressions that have a special comment:

fn main() {
    let length = 20.72; // #[m]
    let time = 12.39; // #[s]

    // Resulting type: #[m / s]
    // No need to specify, will be inferred
    let velocity = length / time;

    // build.rs will give an error:
    // let error = length + time;

    // Multiply by #[s] gives you #[m]:
    let duration = 35.0; // #[s]
    let distance = velocity * duration; // This would be #[m], but could be omitted
}

Note the special #[] notation to describe units. Between the comment begin token and the unit description only space and tabs will be allowed. After that you can place any comments. Otherwise the unit description will be ignored as in the example above.

This will work on stable Rust.