1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! # Measurements
//!
//! Measurements is a crate that lets you represent physical quantities, such
//! as Lengths, Masses, Pressures, etc. Each quantity has a series of
//! functions that allow you to convert to and from common units. You can also
//! perform arithmetic on the quantities - for example you can divide a Force
//! by an Area to get a Pressure.

#![deny(warnings, missing_docs)]

#![cfg_attr(feature="no_std", no_std)]

#[cfg(feature = "no_std")]
use core as std;
#[cfg(feature = "no_std")]
use core::time as time;

#[cfg(not(feature = "no_std"))]
use std::time as time;

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::f64::consts::PI as PI;

#[macro_use]
mod measurement;
pub use measurement::Measurement;

pub mod length;
pub use length::{Distance, Length};

pub mod temperature;
pub use temperature::{Temperature, TemperatureDelta};

pub mod mass;
pub use mass::Mass;

pub mod volume;
pub use volume::Volume;

pub mod pressure;
pub use pressure::Pressure;

pub mod speed;
pub use speed::Speed;

pub mod acceleration;
pub use acceleration::Acceleration;

pub mod energy;
pub use energy::Energy;

pub mod power;
pub use power::Power;

pub mod voltage;
pub use voltage::Voltage;

pub mod current;
pub use current::Current;

pub mod resistance;
pub use resistance::Resistance;

pub mod force;
pub use force::Force;

pub mod area;
pub use area::Area;

pub mod angle;
pub use angle::Angle;

pub mod frequency;
pub use frequency::Frequency;

pub mod angular_velocity;
pub use angular_velocity::AngularVelocity;

pub mod torque;
pub use torque::Torque;

pub mod data;
pub use data::Data;

mod torque_energy;
pub use torque_energy::TorqueEnergy;

pub mod prelude;

pub mod test_utils;

/// For given types A, B and C, implement, using base units:
///     - A = B * C
///     - A = C * B
///     - B = A / C
///     - C = A / B
macro_rules! impl_maths {
    ($a:ty, $b:ty) => {
        impl std::ops::Mul<$b> for $b {
            type Output = $a;

            fn mul(self, rhs: $b) -> Self::Output {
                Self::Output::from_base_units(self.as_base_units() * rhs.as_base_units())
            }
        }

        impl std::ops::Div<$b> for $a {
            type Output = $b;

            fn div(self, rhs: $b) -> Self::Output {
                Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
            }
        }
    };

    ($a:ty, $b:ty, $c:ty) => {
        impl std::ops::Mul<$b> for $c {
            type Output = $a;

            fn mul(self, rhs: $b) -> Self::Output {
                Self::Output::from_base_units(self.as_base_units() * rhs.as_base_units())
            }
        }

        impl std::ops::Mul<$c> for $b {
            type Output = $a;

            fn mul(self, rhs: $c) -> Self::Output {
                Self::Output::from_base_units(self.as_base_units() * rhs.as_base_units())
            }
        }

        impl std::ops::Div<$c> for $a {
            type Output = $b;

            fn div(self, rhs: $c) -> Self::Output {
                Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
            }
        }

        impl std::ops::Div<$b> for $a {
            type Output = $c;

            fn div(self, rhs: $b) -> Self::Output {
                Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
            }
        }
    }
}

impl Measurement for time::Duration {
    fn as_base_units(&self) -> f64 {
        self.as_secs() as f64 + (f64::from(self.subsec_nanos()) * 1e-9)
    }

    fn from_base_units(units: f64) -> Self {
        let subsec_nanos = ((units * 1e9) % 1e9) as u32;
        let secs = units as u64;
        time::Duration::new(secs, subsec_nanos)
    }

    fn get_base_units_name(&self) -> &'static str {
        "s"
    }
}

impl_maths!(Area, Length);
impl_maths!(Energy, time::Duration, Power);
impl_maths!(Force, Mass, Acceleration);
impl_maths!(Force, Pressure, Area);
impl_maths!(Length, time::Duration, Speed);
impl_maths!(Power, Force, Speed);
impl_maths!(Speed, time::Duration, Acceleration);
impl_maths!(Volume, Length, Area);
impl_maths!(Power, AngularVelocity, Torque);
impl_maths!(Power, Voltage, Current);
impl_maths!(Voltage, Resistance, Current);

// Force * Distance is ambiguous. Create an ambiguous struct the user can then
// cast into either Torque or Energy.

impl_maths!(TorqueEnergy, Force, Length);

// Implement the divisions manually (the above macro only implemented the
// TorqueEnergy / X operations).

impl std::ops::Div<Length> for Torque {
    type Output = Force;

    fn div(self, rhs: Length) -> Self::Output {
        Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
    }
}

impl std::ops::Div<Force> for Torque {
    type Output = Length;

    fn div(self, rhs: Force) -> Self::Output {
        Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
    }
}

impl std::ops::Div<Length> for Energy {
    type Output = Force;

    fn div(self, rhs: Length) -> Self::Output {
        Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
    }
}

impl std::ops::Div<Force> for Energy {
    type Output = Length;

    fn div(self, rhs: Force) -> Self::Output {
        Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
    }
}