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
/// The `Measurement` trait and the `implement_measurement!` macro
/// provides a common way for various measurements to be implemented.
///
/// # Example
/// ```
/// #![no_std]
/// // Importing the `implement_measurement` macro from the external crate is important
/// #[macro_use]
/// extern crate measurements;
///
/// use measurements::Measurement;
///
/// struct Cubits {
/// forearms: f64
/// }
///
/// impl Measurement for Cubits {
/// fn as_base_units(&self) -> f64 {
/// self.forearms
/// }
///
/// fn from_base_units(units: f64) -> Self {
/// Cubits { forearms: units }
/// }
///
/// fn get_base_units_name(&self) -> &'static str {
/// "cu"
/// }
/// }
///
/// // Invoke the macro to automatically implement Add, Sub, etc...
/// implement_measurement! { Cubits }
///
/// // The main function here is only included to make doc test_utils compile.
/// // You should't need it in your own code.
/// fn main() { }
/// ```
#[cfg(feature = "no-std")]
use core as std;
#[cfg(feature = "no-std")]
use core::num::Float;
/// All measurements implement this.
///
/// It provides conversion functions to and from raw numbers.
pub trait Measurement {
/// Returns a string containing the most appropriate units for this quantity,
/// and a floating point value representing this quantity in those units.
/// Useful when, for example, a length might be in millimeters if it is very small,
/// or kilometers when it is very large.
///
/// The default implementation always selects the base unit. Override in your
/// Measurement impl to select better units if required.
fn get_appropriate_units(&self) -> (&'static str, f64) {
(self.get_base_units_name(), self.as_base_units())
}
/// Given a list of units and their scale relative to the base unit,
/// select the most appropriate one.
///
/// The list must be smallest to largest, e.g. ("nanometre", 10-9) to
/// ("kilometre", 10e3)
fn pick_appropriate_units(&self, list: &[(&'static str, f64)]) -> (&'static str, f64) {
for &(unit, ref scale) in list.iter().rev() {
let value = self.as_base_units() / scale;
if value >= 1.0 || value <= -1.0 {
return (unit, value);
}
}
(list[0].0, self.as_base_units() / list[0].1)
}
/// Return the base unit for this type, as a string.
/// For example "kilograms"
fn get_base_units_name(&self) -> &'static str;
/// Get this quantity in the base units
fn as_base_units(&self) -> f64;
/// Create a new quantity from the base units
fn from_base_units(units: f64) -> Self;
}
/// This is a special macro that creates the code to implement
/// `std::fmt::Display`.
#[macro_export]
macro_rules! implement_display {
($($t:ty)*) => ($(
impl ::std::fmt::Display for $t {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let (unit, value) = self.get_appropriate_units();
value.fmt(f)?; // Value
write!(f, "\u{00A0}{}", unit)
}
}
)*)
}
/// This is a special macro that creates the code to implement
/// operator and comparison overrides.
#[macro_export]
macro_rules! implement_measurement {
($($t:ty)*) => ($(
implement_display!( $t );
impl ::std::ops::Add for $t {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self::from_base_units(self.as_base_units() + rhs.as_base_units())
}
}
impl ::std::ops::Sub for $t {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self::from_base_units(self.as_base_units() - rhs.as_base_units())
}
}
// Dividing a `$t` by another `$t` returns a ratio.
//
impl ::std::ops::Div<$t> for $t {
type Output = f64;
fn div(self, rhs: Self) -> f64 {
self.as_base_units() / rhs.as_base_units()
}
}
// Dividing a `$t` by a factor returns a new portion of the measurement.
//
impl ::std::ops::Div<f64> for $t {
type Output = Self;
fn div(self, rhs: f64) -> Self {
Self::from_base_units(self.as_base_units() / rhs)
}
}
// Multiplying a `$t` by a factor increases (or decreases) that
// measurement a number of times.
impl ::std::ops::Mul<f64> for $t {
type Output = Self;
fn mul(self, rhs: f64) -> Self {
Self::from_base_units(self.as_base_units() * rhs)
}
}
// Multiplying `$t` by a factor is commutative
impl ::std::ops::Mul<$t> for f64 {
type Output = $t;
fn mul(self, rhs: $t) -> $t {
rhs * self
}
}
impl ::std::cmp::Eq for $t { }
impl ::std::cmp::PartialEq for $t {
fn eq(&self, other: &Self) -> bool {
self.as_base_units() == other.as_base_units()
}
}
impl ::std::cmp::PartialOrd for $t {
fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
self.as_base_units().partial_cmp(&other.as_base_units())
}
}
)*)
}