units 0.1.0

Units of Measure for Rust. Easy to use, type-safe and customizable.
Documentation

#[derive(Copy,Clone,PartialEq,PartialOrd)]
pub struct Quantity<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> {
    // TODO: make number type generic (and also implement Eq)
    // TODO: implement (Partial)Ord
    // TODO: add more dimensions
    // TODO: implement One and Default
    amount: f64,
    p1: std::marker::PhantomData<E1>,
    p2: std::marker::PhantomData<E2>,
    p3: std::marker::PhantomData<E3>,
}

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> Quantity<E1,E2,E3> {
    // this is private!
    fn new(amount: f64)-> Quantity<E1,E2,E3> {
        Quantity::<E1,E2,E3> {
            amount: amount,
            p1: std::marker::PhantomData::<_>,
            p2: std::marker::PhantomData::<_>,
            p3: std::marker::PhantomData::<_>
        }
    }
    
    pub fn sqrt<RE1:NumType<RE1>,RE2:NumType<RE2>,RE3:NumType<RE3>>(self) -> Quantity<RE1,RE2,RE3> 
        where E1:THalve<E1,Out=RE1>, E2:THalve<E2,Out=RE2>, E3:THalve<E3,Out=RE3> {
        Quantity::new(self.amount.sqrt())
    }
}

impl Into<f64> for Quantity<Zero,Zero,Zero> {
    fn into(self) -> f64 { self.amount }
}

impl std::ops::Deref for Quantity<Zero,Zero,Zero> {
    type Target = f64;
    fn deref(&self) -> &Self::Target { &self.amount }
}

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> std::fmt::Debug for Quantity<E1,E2,E3> {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        try!(self.amount.fmt(formatter));
        let mut num: i32;
        num = E1::new().into();
        if num != 0 {
            try!(write!(formatter, " m^{}", num));
        }
        num = E2::new().into();
        if num != 0 {
            try!(write!(formatter, " kg^{}", num));
        }
        num = E3::new().into();
        if num != 0 {
            try!(write!(formatter, " s^{}", num));
        }
        Ok(())
    }
}

// TODO: add operators for references?

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> std::ops::Add for Quantity<E1,E2,E3> {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        Quantity::new(self.amount + rhs.amount)
    }
}

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> std::ops::Sub for Quantity<E1,E2,E3> {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self::Output {
        Quantity::new(self.amount - rhs.amount)
    }
}

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>,
     RE1:NumType<RE1>, RE2:NumType<RE2>, RE3:NumType<RE3>,
     Out1:NumType<Out1>, Out2:NumType<Out2>, Out3:NumType<Out3>>
    std::ops::Mul<Quantity<RE1,RE2,RE3>> for Quantity<E1,E2,E3>
        where E1:TAdd<E1,RE1,Out=Out1>, E2:TAdd<E2,RE2,Out=Out2>, E3:TAdd<E3,RE3,Out=Out3> {
        
    type Output = Quantity<Out1,Out2,Out3>;
    fn mul(self, rhs: Quantity<RE1,RE2,RE3>) -> Self::Output {
        Quantity::new(self.amount * rhs.amount)
    }
}

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>,
     RE1:NumType<RE1>, RE2:NumType<RE2>, RE3:NumType<RE3>,
     Out1:NumType<Out1>, Out2:NumType<Out2>, Out3:NumType<Out3>>
    std::ops::Div<Quantity<RE1,RE2,RE3>> for Quantity<E1,E2,E3>
        where E1:TSub<E1,RE1,Out=Out1>, E2:TSub<E2,RE2,Out=Out2>, E3:TSub<E3,RE3,Out=Out3> {
        
    type Output = Quantity<Out1,Out2,Out3>;
    fn div(self, rhs: Quantity<RE1,RE2,RE3>) -> Self::Output {
        Quantity::new(self.amount / rhs.amount)
    }
}

/*
// One operand is a (dimensionless) float
impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> std::ops::Mul<Quantity<E1,E2,E3>> for f64 {
    type Output = Quantity<E1,E2,E3>;
    fn mul(self, rhs: Quantity<E1,E2,E3>) -> Self::Output {
        Quantity::new(self * rhs.amount)
    }
}

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> std::ops::Div<Quantity<E1,E2,E3>> for f64 {
    type Output = Quantity<E1,E2,E3>;
    fn div(self, rhs: Quantity<E1,E2,E3>) -> Self::Output {
        Quantity::new(self / rhs.amount)
    }
}

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> std::ops::Mul<f64> for Quantity<E1,E2,E3> {
    type Output = Quantity<E1,E2,E3>;
    fn mul(self, rhs: f64) -> Self::Output {
        Quantity::new(self.amount * rhs)
    }
}

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> std::ops::Div<f64> for Quantity<E1,E2,E3> {
    type Output = Quantity<E1,E2,E3>;
    fn div(self, rhs: f64) -> Self::Output {
        Quantity::new(self.amount / rhs)
    }
}
*/

impl<E1:NumType<E1>, E2:NumType<E2>, E3:NumType<E3>> std::ops::FnOnce<(f64,)> for Quantity<E1,E2,E3> {
    type Output = Quantity<E1,E2,E3>;
    extern "rust-call" fn call_once(self, args: (f64,)) -> Self::Output {
        Quantity::new(self.amount * args.0)
    }
}

pub type One = Quantity<Zero, Zero, Zero>;
pub type Length = Quantity<P1, Zero, Zero>;
pub type Mass   = Quantity<Zero, P1, Zero>;
pub type Time   = Quantity<Zero, Zero, P1>;

pub const one: One = One {
    amount: 1.0,
    p1: std::marker::PhantomData::<_>,
    p2: std::marker::PhantomData::<_>,
    p3: std::marker::PhantomData::<_>
};

pub const m: Length = Quantity::<_,_,_> {
    amount: 1.0,
    p1: std::marker::PhantomData::<_>,
    p2: std::marker::PhantomData::<_>,
    p3: std::marker::PhantomData::<_>
};

pub const kg: Mass = Mass {
    amount: 1.0,
    p1: std::marker::PhantomData::<_>,
    p2: std::marker::PhantomData::<_>,
    p3: std::marker::PhantomData::<_>
};

pub const s: Time = Time {
    amount: 1.0,
    p1: std::marker::PhantomData::<_>,
    p2: std::marker::PhantomData::<_>,
    p3: std::marker::PhantomData::<_>
};