Last active
August 29, 2015 14:19
-
-
Save archer884/eafef3bca7003c67917d to your computer and use it in GitHub Desktop.
Distances and conversions (with macro)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fmt; | |
use std::ops; | |
trait Distance { | |
type Value; | |
fn to_normal(&self) -> f64; | |
fn from_normal(f64) -> Self::Value; | |
} | |
/// Creates a distance type. | |
/// | |
/// This macro accepts a type name and a conversion factor. These will be used to create a newtype | |
/// struct and a set of traits defining behaviors of basic mathematical operators. | |
/// | |
/// Distance types interoperate by first converting both the left and right operands to meters and | |
/// then converting the resulting value back into the original left hand side type. At present, all | |
/// distance types are Copy + Clone. | |
macro_rules! distance { | |
($t:ident, $c:expr) => { | |
#[derive(Copy, Clone)] | |
struct $t(f64); | |
impl Distance for $t { | |
type Value = $t; | |
fn to_normal(&self) -> f64 { self.0 * $c } | |
fn from_normal(f: f64) -> Self::Value { $t(f / $c) } | |
} | |
impl<D: Distance> ops::Add<D> for $t { | |
type Output = <Self as Distance>::Value; | |
fn add(self, rhs: D) -> Self::Output { | |
Self::Output::from_normal(self.to_normal() + rhs.to_normal()) | |
} | |
} | |
impl<D: Distance> ops::Sub<D> for $t { | |
type Output = <Self as Distance>::Value; | |
fn sub(self, rhs: D) -> Self::Output { | |
Self::Output::from_normal(self.to_normal() - rhs.to_normal()) | |
} | |
} | |
impl ops::Mul<f64> for $t { | |
type Output = <Self as Distance>::Value; | |
fn mul(self, rhs: f64) -> Self::Output { | |
$t(self.0 * rhs) | |
} | |
} | |
impl ops::Div<f64> for $t { | |
type Output = <Self as Distance>::Value; | |
fn div(self, rhs: f64) -> Self::Output { | |
$t(self.0 / rhs) | |
} | |
} | |
impl fmt::Display for $t { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
write!(f, "{}", self.0) | |
} | |
} | |
} | |
} | |
distance!(Inches, 2.54 / 100.0); | |
distance!(Centimeters, 1.0 / 100.0); | |
fn main() { | |
let foot_long = Inches(12.0); | |
let inch_long = Centimeters(2.54); | |
println!("{}", foot_long + foot_long); // 24 | |
println!("{}", inch_long + foot_long); // 33.02 | |
println!("{}", foot_long - inch_long); // 11 | |
println!("{}", foot_long * 2.0); // 24 | |
println!("{}", foot_long / 3.0); // 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment