Skip to content

Instantly share code, notes, and snippets.

@archer884
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save archer884/eafef3bca7003c67917d to your computer and use it in GitHub Desktop.
Save archer884/eafef3bca7003c67917d to your computer and use it in GitHub Desktop.
Distances and conversions (with macro)
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