Ferrunitas - Type-Safe Unit Conversion Library
A Rust library for compile-time dimensional analysis and unit conversions. Ferrunitas provides type safety for physical quantities and prevents dimensional errors at compile time through Rust's powerful type system.
Current build and test state:
Features
- Compile-time dimensional analysis: Prevents adding incompatible quantities (e.g. mass + length) at compile time
- Type-safe unit conversions: Zero runtime overhead conversions between compatible units
- Flexible API: Work with specific units (
Measure<Metre>) or generic quantities (Length) - Extensive unit system: Complete SI base units, derived units, and common non-SI units
- Prefix support: Metric prefixes (kilo, milli, etc.) with easy unit definition
- Custom unit definition: Macros for defining your own units, quantities, and prefixes
- Quantity tagging (optional): Distinguish between dimensionally equivalent but semantically different quantities (e.g.,
AnglevsInformation) - Zero-cost abstractions: All dimensional checking happens at compile time
Usage
Basics
use *;
use ;
Relevant imports
// For dimensional formatting
use ;
// For access to all definitions to units, quantities and prefixes
use *;
// Crate root access to most common struct Measure and trait Unit to make methods available
use ;
// Macros for own definitions (typenum consts for quantity macro)
use *;
use ;
Working with Quantities vs Measures
Ferrunitas offers two main ways to work with physical values (they are compatitble with each other regarding arithmetics):
Measures - Values with specific units:
let mass = new; // Measure<Kilogram>
let length = new; // Measure<Foot>
let sum = mass + new; // Addition works across compatible units
Quantities - Dimensioned values without specific units:
let mass: Mass = new.into_q; // Convert to quantity
let length: Length = new.into_q; // Convert to quantity
let force: Force = mass * acceleration; // Multiplication creates new quantity
Unit Conversions
// Multiple ways to convert units
let liters = new;
// Via quantity (intermediate step)
let volume: Volume = liters.into_q;
let cubic_cm: = volume.as_measure;
// Direct conversion
let cubic_cm_direct: = liters.convert;
// One-line conversion
let cubic_cm_oneline = ;
Physics Calculations
// All operations are dimensionally checked at compile time
let mass = new;
let acceleration = new;
let force: Force = mass * acceleration; // F = ma
let distance = new;
let work: Energy = force * distance; // W = F·d
let time = new;
let power: Power = work / time; // P = W/t
println!;
Custom Units and Quantities
Define your own units using the provided macros:
use ;
// Define a new quantity (7 SI base dimensions: M, L, T, I, Th, N, J)
quantity!;
// Define a new quantity with tagging (requires `quantity_tags` feature)
quantity!;
// Define a new prefix
prefix!;
// Define new units
unit!;
unit!;
unit!;
// Compound units with quantity tagging (requires `quantity_tags` feature)
unit!;
Quantity Tagging (Optional Feature)
When the quantity_tags feature is enabled, Ferrunitas can distinguish between quantities that are dimensionally identical but represent different physical concepts:
// Enable with: cargo build --features="quantity_tags"
use *;
use Unit;
// These are both dimensionless, but represent different concepts
let data = new;
let angle = new;
// Without quantity_tags: these can be added directly
// With quantity_tags: compilation error - different quantity types!
// let invalid = data + angle; // Error with quantity_tags enabled
// Instead, you need to explicitly specify the target quantity:
let combined = data.into_q. +
angle.into_q.;
// This helps prevent mixing semantically different values
let area1 = new;
let area2 = new;
let solid_angle = new;
// Without tags: this works (both are dimensionless ratios)
// With tags: need to specify the result type
let result = . + solid_angle;
Function Signatures
Ferrunitas provides flexible function signatures for different use cases:
// Accept specific units
// Accept any unit of a quantity type
// Work directly with quantities
Examples
The examples/ directory contains comprehensive usage examples:
basics.rs- Core concepts: measures, quantities, conversions, and arithmeticfunctions.rs- Different patterns for writing functions with dimensional typesadvanced.rs- Custom unit definitions using macrosmisc.rs- Dimensional introspection, debugging utilities, and quantity tagging demonstration
Run examples with:
# To see quantity tagging in action:
Limitations / Notes
- Internal storage uses
f64; typical floating point caveats apply, see examples/misc.rs. - Rounding / formatting of display values is a caller concern, however usual format specifiers are respected.
- Offsets are supported for temperature scales, but are quite limited in usage besides simple conversion.
Contributing
Contributions are welcome! Please feel free to submit a pull request or open an issue for any suggestions or improvements.
License
This project is licensed under the Apache-2.0 License.