simple-si-units

GitHub Workflow Build Status GitHub Workflow Test Status Crate.io Redistribution license

This Rust library provides compiler-checked types for the standard set of SI units, as specified by the US National Institute of Standards and Technology (this project is not officially endorsed by NIST).

What's included?

Units

This crate provides types for the following units. Other kinds of quantities not listed below (eg jolt) are beyond the scope of this crate.

Base SI units (and standard unit of measure):

Derived units:

What's NOT included?

Roadmap

The version of this library will be incremented to reflect progress through the various milestones. The goal is to reach version 1.0 (API stable) as quickly as practical.

How it works

For each type of unit (eg Distance), Simple SI Units provides a generic struct to represent the unit and which implements common type conversion. For example, dividing a Distance by a Time results in a Velocity: rust todo!();

Since these structs use generic type templates for the internal data type, you can use any number-like data type with these structs, including numcomplex::Complex and numbigfloat::BigFloat (see caveat section below regarding primitive types other than f64).

Adding your own units

Simple SI Units does not provide an exhaustive list of possible units of measure. To create your own units, use the UnitStruct procedural macro and NumLike trait bundle (NumLike is just shorthand for Sized+std::ops::*<Output=Self>, you could instead use the Num trait from the num-traits crate if you prefer):

```rust use simplesiunits::{UnitStruct, NumLike};

[derive(UnitStruct, Debug, Copy, Clone)]

struct HyperVelocity{ squaremetersper_second: T }

fn weighted_sum(a: HyperVelocity, b: HyperVelocity, weight: f64) -> HyperVelocity where T:NumLike + From { return weighta + (1.-weight)b; } ```

Caveats

There are a few limitations owing to the Rust compiler's lack of type specialization in stable Rust, the most notable of which is that some functions won't work with f32 as the input type.

Primitive types other than f64

Many of the member functions will only work with number types that implement From<f64> (because they need to multiply by an internal coefficient of type f64), so while you can still instantiate these structs with f32 and other primitive types (eg Mass{kg: 1.1_f32} will work), you will have to wrap primitive types other than f64 to use the constructor functions (eg Mass::from_g(1100_f32) will not work). Thus to use f32 or other primitives which are not convertible from f64, you will need to wrap them with an implementation of From<f64>. For example: rust struct MyFloat32 { x: f32 } impl MyFloat32 { pub fn new(n: f32) -> Self{return Self{x: n}} } impl From<f64> for MyFloat32 { fn from(n: f64) -> Self {return Self::new(n as f32)} } impl std::ops::Add<Self> for MyFloat32 { type Output = Self; fn add(self, rhs: Self) -> Self::Output {Self{ x: self.x + rhs.x }} } impl std::ops::Sub<Self> for MyFloat32 { type Output = Self; fn sub(self, rhs: Self) -> Self::Output {Self{ x: self.x - rhs.x }} } impl std::ops::Div<Self> for MyFloat32 { type Output = Self; fn div(self, rhs: Self) -> Self::Output {Self{ x: self.x / rhs.x}} } impl std::ops::Mul<Self> for MyFloat32 { type Output = Self; fn mul(self, rhs: Self) -> Self::Output {Self{ x: self.x * rhs.x }} } fn my_fn() -> Mass<MyFloat32>{ let m = Mass::from_g(MyFloat32::new(1100_f32)); return m * MyFloat32::new(0.5); }

License

This library is open source, licensed under the Mozilla Public License version 2.0. In summary, you may include this source code as-is in both open-source and proprietary projects without requesting permission from me, but if you modify the source code from this library then you must make your modified version of this library available under an open-source license.