dana/lib.rs
1//! Compile-time [dimensional analysis] via generic types.
2//!
3//! [dimensional analysis]: https://en.wikipedia.org/wiki/Dimensional_analysis
4//!
5//! The core of the crate is the [`Unit`] trait, which marks a struct or enum as
6//! being a representation of a dimensional unit. Units may have multiple
7//! variants, each with a different scaling factor.
8//!
9//! The most important exported type is [`Quantity`]. A `Quantity` is generic
10//! over `Unit` types and numeric [`Value`] types, and serves to pair a
11//! dimensionless value with a dimensional unit. The default scalar type is
12//! `f64`, but [`Value`] is automatically implemented for any type that
13//! implements the correct set of traits.
14//!
15//! # Examples
16//!
17//! The goal of dimensional analysis is to ensure correctness when doing
18//! calculations on physical quantities. Operations are only valid between
19//! quantities of compatible units, and units must be conserved in order to
20//! get correct results.
21//!
22//! The fundamental principle of this library is to represent quantities with
23//! incompatible units as different types, so that attempting to use them
24//! together results in a compiler error.
25//!
26//! The following function takes a distance an object has moved, as well as the
27//! amount of time it took to move that distance, and calculates the average
28//! speed of the object:
29//! ```
30//! use dana::{Quantity, units::{Length, Speed, Time}};
31//!
32//! fn speed(dist: Quantity<Length>, time: Quantity<Time>) -> Quantity<Speed> {
33//! dist / time
34//! }
35//! ```
36//!
37//! This calculation is correctly performed by dividing the distance moved by
38//! the time taken. Attempting to perform the wrong operation will produce
39//! the wrong type, resulting in a "mismatched types" error:
40//! ```compile_fail
41//! # use dana::{Quantity, units::{Length, Speed, Time}};
42//! #
43//! fn speed(dist: Quantity<Length>, time: Quantity<Time>) -> Quantity<Speed> {
44//! time / dist
45//! }
46//! ```
47//!
48//! ## Defining Quantities
49//!
50// TODO: Focus less heavily on `qty!` here. Link to it and recommend it, but
51// then describe non-macro definition.
52//! Using the full syntax is verbose to the point of near-unreadability:
53//! ```
54//! use dana::{Quantity, units::*};
55//!
56//! let grav: Quantity<UnitDiv<Length, UnitSquared<Time>>> = Quantity {
57//! unit: UnitDiv::new(Length::Meter, UnitSquared::new(Time::Second)),
58//! value: 9.81,
59//! };
60//! ```
61//!
62//! This can be reduced somewhat by using type inference, [`Quantity::new`] or
63//! [`Unit::quantity`], standard library math operators, and the methods of
64//! unit traits. The result is better, but still difficult to read for more
65//! complex expressions:
66//! ```
67//! use dana::{Quantity, units::{concrete::*, traits::CanSquare}};
68//!
69//! let grav = Quantity::new(
70//! Length::Meter / Time::Second.squared(),
71//! 9.81,
72//! );
73//! ```
74//!
75//! To make large units more workable, the [`qty`] macro interprets combinations
76//! of units using a wider range of operators than the standard library
77//! traits provide:
78//! ```
79//! use dana::{qty, units::concrete::*};
80//!
81//! let grav = qty![9.81 Length::Meter / (Time::Second ^ 2)];
82//! ```
83//!
84//! Finally, the [`symbols`] module provides standard SI unit symbols as
85//! constants and type aliases, bringing the syntax very close to a pure
86//! mathematical form:
87//! ```
88//! use dana::{qty, symbols::*};
89//!
90//! let grav = qty![9.81 m/s^2];
91//! ```
92
93#![no_std]
94#![cfg_attr(feature = "simd", feature(portable_simd))]
95
96// NOTE: Hack to allow proc macros to work both inside and outside the crate.
97extern crate self as dana;
98
99#[macro_use]
100pub mod macros;
101pub mod prelude;
102
103pub mod constants;
104#[allow(missing_docs)]
105pub mod dimension;
106pub mod equations;
107pub mod quantity;
108pub mod symbols;
109pub mod units;
110pub mod value;
111
112pub mod error;
113
114#[cfg(feature = "simd")]
115#[allow(missing_docs)]
116pub mod simd;
117
118pub use quantity::Quantity;
119pub use units::Unit;
120pub use value::Value;
121use value::{_conv_f64, _conv_i32};