Skip to content

Commit 2b4a8a2

Browse files
author
James O'Cull
committed
Created a trait and macro for implementing measurements the same way.
1 parent 767dcce commit 2b4a8a2

File tree

6 files changed

+144
-158
lines changed

6 files changed

+144
-158
lines changed

src/length/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
mod traits;
1+
use super::measurement::*;
22

33
// Constants, metric
44
const METER_NANOMETER_FACTOR: f64 = 1000000000.0;
@@ -132,3 +132,15 @@ impl Length {
132132
self.meters * METER_MILE_FACTOR
133133
}
134134
}
135+
136+
impl Measurement for Length {
137+
fn get_base_units(&self) -> f64 {
138+
self.meters
139+
}
140+
141+
fn from_base_units(units: f64) -> Self {
142+
Self::from_meters(units)
143+
}
144+
}
145+
146+
implement_measurement! { Length }

src/length/traits.rs

Lines changed: 0 additions & 77 deletions
This file was deleted.

src/lib.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
1-
#[cfg(test)]
2-
mod tests;
1+
/// The `Measurement` trait and the `implement_measurement!` macro
2+
/// provides a common way for various measurements to be implemented.
3+
///
4+
/// # Example
5+
/// ```
6+
/// #[macro_use]
7+
/// use measurements::measurement::*;
8+
///
9+
/// struct Cubits {
10+
/// forearms: f64
11+
/// }
12+
///
13+
/// impl Measurement for Cubits {
14+
/// fn get_base_units(&self) -> f64 {
15+
/// self.forearms
16+
/// }
17+
///
18+
/// fn from_base_units(units: f64) -> Self {
19+
/// Cubits { forearms: units }
20+
/// }
21+
/// }
22+
///
23+
/// // Invoke the macro to automatically implement Add, Sub, etc...
24+
/// // implement_measurement! { Cubits } // TODO: Fix doc tests to make this work...
25+
/// ```
26+
#[macro_use]
27+
pub mod measurement;
328

429
/// The `Length` struct can be used to deal with lengths in a common way.
530
/// Common metric and imperial units are supported.
@@ -31,3 +56,7 @@ pub mod length;
3156
3257
#[allow(dead_code)]
3358
pub mod temperature;
59+
60+
#[cfg(test)]
61+
#[macro_use]
62+
mod tests;

src/measurement/mod.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
pub trait Measurement {
2+
fn get_base_units(&self) -> f64;
3+
fn from_base_units(units: f64) -> Self;
4+
}
5+
6+
#[macro_export]
7+
macro_rules! implement_measurement {
8+
($($t:ty)*) => ($(
9+
// TODO: Find a better way to reference these...
10+
use std::ops::{Add,Sub,Div,Mul};
11+
use std::cmp::{Eq, PartialEq};
12+
use std::cmp::{PartialOrd, Ordering};
13+
14+
impl Add for $t {
15+
type Output = Self;
16+
17+
fn add(self, rhs: Self) -> Self {
18+
Self::from_base_units(self.get_base_units() + rhs.get_base_units())
19+
}
20+
}
21+
22+
impl Sub for $t {
23+
type Output = Self;
24+
25+
fn sub(self, rhs: Self) -> Self {
26+
Self::from_base_units(self.get_base_units() - rhs.get_base_units())
27+
}
28+
}
29+
30+
///
31+
/// Dividing a `$t` by another `$` returns a ratio.
32+
///
33+
impl Div<$t> for $t {
34+
type Output = f64;
35+
36+
fn div(self, rhs: Self) -> f64 {
37+
self.get_base_units() / rhs.get_base_units()
38+
}
39+
}
40+
41+
///
42+
/// Dividing a `$` by a factor returns a new portion of the measurement.
43+
///
44+
impl Div<f64> for $t {
45+
type Output = Self;
46+
47+
fn div(self, rhs: f64) -> Self {
48+
Self::from_base_units(self.get_base_units() / rhs)
49+
}
50+
}
51+
52+
///
53+
/// Multiplying a `$t` by another `$t` returns the product of those measurements.
54+
///
55+
impl Mul<$t> for $t {
56+
type Output = Self;
57+
58+
fn mul(self, rhs: Self) -> Self {
59+
Self::from_base_units(self.get_base_units() * rhs.get_base_units())
60+
}
61+
}
62+
63+
///
64+
/// Multiplying a `$t` by a factor increases (or decreases) that measurement a number of times.
65+
///
66+
impl Mul<f64> for $t {
67+
type Output = Self;
68+
69+
fn mul(self, rhs: f64) -> Self {
70+
Self::from_base_units(self.get_base_units() * rhs)
71+
}
72+
}
73+
74+
impl Eq for $t { }
75+
impl PartialEq for $t {
76+
fn eq(&self, other: &Self) -> bool {
77+
self.get_base_units() == other.get_base_units()
78+
}
79+
}
80+
81+
impl PartialOrd for $t {
82+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
83+
self.get_base_units().partial_cmp(&other.get_base_units())
84+
}
85+
}
86+
)*)
87+
}

src/temperature/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
mod traits;
1+
use super::measurement::*;
22

33
/// The `Temperature` struct can be used to deal with temperatures in a common way.
44
#[derive(Copy, Clone, Debug)]
@@ -39,3 +39,15 @@ impl Temperature {
3939
(self.kelvin - 273.15) * 1.8 + 491.67
4040
}
4141
}
42+
43+
impl Measurement for Temperature {
44+
fn get_base_units(&self) -> f64 {
45+
self.kelvin
46+
}
47+
48+
fn from_base_units(units: f64) -> Self {
49+
Self::from_kelvin(units)
50+
}
51+
}
52+
53+
implement_measurement! { Temperature }

src/temperature/traits.rs

Lines changed: 0 additions & 77 deletions
This file was deleted.

0 commit comments

Comments
 (0)