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};