Skip to main content

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