measurements/
lib.rs

1//! # Measurements
2//!
3//! Measurements is a crate that lets you represent physical quantities, such
4//! as Lengths, Masses, Pressures, etc. Each quantity has a series of
5//! functions that allow you to convert to and from common units. You can also
6//! perform arithmetic on the quantities - for example you can divide a Force
7//! by an Area to get a Pressure.
8
9#![deny(warnings, missing_docs)]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12#[cfg(not(feature = "std"))]
13use core as std;
14#[cfg(not(feature = "std"))]
15use core::time;
16
17#[cfg(feature = "std")]
18use std::time;
19
20#[cfg(feature = "serde")]
21#[macro_use]
22extern crate serde;
23
24#[cfg(feature = "from_str")]
25extern crate regex;
26
27use std::f64::consts::PI;
28
29#[macro_use]
30mod measurement;
31pub use measurement::Measurement;
32
33pub mod length;
34pub use length::{Distance, Length};
35
36pub mod temperature;
37pub use temperature::{Temperature, TemperatureDelta};
38
39pub mod humidity;
40pub use humidity::Humidity;
41
42pub mod mass;
43pub use mass::Mass;
44
45pub mod volume;
46pub use volume::Volume;
47
48pub mod density;
49pub use density::Density;
50
51pub mod pressure;
52pub use pressure::Pressure;
53
54pub mod speed;
55pub use speed::Speed;
56
57pub mod acceleration;
58pub use acceleration::Acceleration;
59
60pub mod energy;
61pub use energy::Energy;
62
63pub mod power;
64pub use power::Power;
65
66pub mod voltage;
67pub use voltage::Voltage;
68
69pub mod current;
70pub use current::Current;
71
72pub mod resistance;
73pub use resistance::Resistance;
74
75pub mod force;
76pub use force::Force;
77
78pub mod area;
79pub use area::Area;
80
81pub mod angle;
82pub use angle::Angle;
83
84pub mod frequency;
85pub use frequency::Frequency;
86
87pub mod angular_velocity;
88pub use angular_velocity::AngularVelocity;
89
90pub mod torque;
91pub use torque::Torque;
92
93pub mod data;
94pub use data::Data;
95
96mod torque_energy;
97pub use torque_energy::TorqueEnergy;
98
99pub mod prelude;
100
101pub mod test_utils;
102
103/// For given types A, B and C, implement, using base units:
104///     - A = B * C
105///     - A = C * B
106///     - B = A / C
107///     - C = A / B
108macro_rules! impl_maths {
109    ($a:ty, $b:ty) => {
110        impl std::ops::Mul<$b> for $b {
111            type Output = $a;
112
113            fn mul(self, rhs: $b) -> Self::Output {
114                Self::Output::from_base_units(self.as_base_units() * rhs.as_base_units())
115            }
116        }
117
118        impl std::ops::Div<$b> for $a {
119            type Output = $b;
120
121            fn div(self, rhs: $b) -> Self::Output {
122                Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
123            }
124        }
125    };
126
127    ($a:ty, $b:ty, $c:ty) => {
128        impl std::ops::Mul<$b> for $c {
129            type Output = $a;
130
131            fn mul(self, rhs: $b) -> Self::Output {
132                Self::Output::from_base_units(self.as_base_units() * rhs.as_base_units())
133            }
134        }
135
136        impl std::ops::Mul<$c> for $b {
137            type Output = $a;
138
139            fn mul(self, rhs: $c) -> Self::Output {
140                Self::Output::from_base_units(self.as_base_units() * rhs.as_base_units())
141            }
142        }
143
144        impl std::ops::Div<$c> for $a {
145            type Output = $b;
146
147            fn div(self, rhs: $c) -> Self::Output {
148                Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
149            }
150        }
151
152        impl std::ops::Div<$b> for $a {
153            type Output = $c;
154
155            fn div(self, rhs: $b) -> Self::Output {
156                Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
157            }
158        }
159    };
160}
161
162impl Measurement for time::Duration {
163    fn as_base_units(&self) -> f64 {
164        self.as_secs() as f64 + (f64::from(self.subsec_nanos()) * 1e-9)
165    }
166
167    fn from_base_units(units: f64) -> Self {
168        let subsec_nanos = ((units * 1e9) % 1e9) as u32;
169        let secs = units as u64;
170        time::Duration::new(secs, subsec_nanos)
171    }
172
173    fn get_base_units_name(&self) -> &'static str {
174        "s"
175    }
176}
177
178impl_maths!(Area, Length);
179impl_maths!(Energy, time::Duration, Power);
180impl_maths!(Force, Mass, Acceleration);
181impl_maths!(Force, Pressure, Area);
182impl_maths!(Length, time::Duration, Speed);
183impl_maths!(Power, Force, Speed);
184impl_maths!(Speed, time::Duration, Acceleration);
185impl_maths!(Volume, Length, Area);
186impl_maths!(Power, AngularVelocity, Torque);
187impl_maths!(Power, Voltage, Current);
188impl_maths!(Voltage, Resistance, Current);
189
190// Force * Distance is ambiguous. Create an ambiguous struct the user can then
191// cast into either Torque or Energy.
192
193impl_maths!(TorqueEnergy, Force, Length);
194
195// Implement the divisions manually (the above macro only implemented the
196// TorqueEnergy / X operations).
197
198impl std::ops::Div<Length> for Torque {
199    type Output = Force;
200
201    fn div(self, rhs: Length) -> Self::Output {
202        Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
203    }
204}
205
206impl std::ops::Div<Force> for Torque {
207    type Output = Length;
208
209    fn div(self, rhs: Force) -> Self::Output {
210        Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
211    }
212}
213
214impl std::ops::Div<Length> for Energy {
215    type Output = Force;
216
217    fn div(self, rhs: Length) -> Self::Output {
218        Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
219    }
220}
221
222impl std::ops::Div<Force> for Energy {
223    type Output = Length;
224
225    fn div(self, rhs: Force) -> Self::Output {
226        Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
227    }
228}