use std::ops::*;
use std::num::{ToPrimitive, NumCast, Float};
use std::cmp::*;
use std::fmt;
pub trait Dimension {}
pub trait Dimensionless: Dimension {}
pub trait AddDim<RHS = Self>: Dimension {
type Output;
}
pub trait SubDim<RHS = Self>: Dimension {
type Output;
}
pub trait MulDim<RHS = Self>: Dimension {
type Output;
}
pub trait DivDim<RHS = Self>: Dimension {
type Output;
}
pub trait DimToString: Dimension {
fn to_string() -> String;
}
pub trait Scalar {}
impl Scalar for f64 {}
impl Scalar for f32 {}
pub struct Dim<T: Dimension, V>(pub V);
pub trait Wrap<B> {
type Output;
fn wrap(&self, b: B) -> <Self as Wrap<B>>::Output;
}
impl<T, A, B> Wrap<B> for Dim<T, A>
where T: Dimension {
type Output = Dim<T, B>;
fn wrap(&self, b: B) -> Dim<T, B> {
Dim(b)
}
}
impl<T: Dimension, V: Copy> Copy for Dim<T, V> {}
impl<T, V> Clone for Dim<T, V> where T: Dimension, V: Clone {
fn clone(&self) -> Self {
Dim((self.0).clone())
}
fn clone_from(&mut self, source: &Self) {
(self.0).clone_from(&source.0);
}
}
impl<T, V> fmt::Display for Dim<T, V> where T: DimToString, V: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{} {}", self.0, <T as DimToString>::to_string())
}
}
impl<Tl, Tr, Vl, Vr> Mul<Dim<Tr, Vr>> for Dim<Tl, Vl>
where Tl: Dimension + AddDim<Tr>, Tr: Dimension, Vl: Mul<Vr>, <Tl as AddDim<Tr>>::Output: Dimension {
type Output = Dim<<Tl as AddDim<Tr>>::Output, <Vl as Mul<Vr>>::Output>;
fn mul(self, rhs: Dim<Tr, Vr>) -> Dim<<Tl as AddDim<Tr>>::Output, <Vl as Mul<Vr>>::Output> {
Dim(self.0 * rhs.0)
}
}
impl<T, V, RHS> Mul<RHS> for Dim<T, V>
where T: Dimension, V: Mul<RHS>, RHS: Scalar {
type Output = Dim<T, <V as Mul<RHS>>::Output>;
fn mul(self, rhs: RHS) -> Dim<T, <V as Mul<RHS>>::Output> {
Dim(self.0 * rhs)
}
}
impl<Tl, Tr, Vl, Vr> Div<Dim<Tr, Vr>> for Dim<Tl, Vl>
where Tl: Dimension + SubDim<Tr>, Tr: Dimension, Vl: Div<Vr>, <Tl as SubDim<Tr>>::Output: Dimension {
type Output = Dim<<Tl as SubDim<Tr>>::Output, <Vl as Div<Vr>>::Output>;
fn div(self, rhs: Dim<Tr, Vr>) -> Dim<<Tl as SubDim<Tr>>::Output, <Vl as Div<Vr>>::Output> {
Dim(self.0 / rhs.0)
}
}
impl<T, V, RHS> Div<RHS> for Dim<T, V>
where T: Dimension, V: Div<RHS>, RHS: Scalar {
type Output = Dim<T, <V as Div<RHS>>::Output>;
fn div(self, rhs: RHS) -> Dim<T, <V as Div<RHS>>::Output> {
Dim(self.0 / rhs)
}
}
macro_rules! define_unary_op {
($Trait:ident, $fun:ident) => (
impl<T, V> $Trait for Dim<T, V>
where T: Dimension, V: $Trait {
type Output = Dim<T, <V as $Trait>::Output>;
fn $fun(self) -> Dim<T, <V as $Trait>::Output> {
Dim( (self.0).$fun() )
}
}
)
}
define_unary_op!(Neg, neg);
define_unary_op!(Not, not);
macro_rules! define_binary_op {
($Trait:ident, $fun:ident) => (
impl<T, Vl, Vr> $Trait<Dim<T, Vr>> for Dim<T, Vl>
where T: Dimension, Vl: $Trait<Vr> {
type Output = Dim<T, <Vl as $Trait<Vr>>::Output>;
fn $fun(self, rhs: Dim<T, Vr>) -> Dim<T, <Vl as $Trait<Vr>>::Output> {
Dim( (self.0).$fun(rhs.0) )
}
}
)
}
define_binary_op!(Add, add);
define_binary_op!(BitAnd, bitand);
define_binary_op!(BitOr, bitor);
define_binary_op!(BitXor, bitxor);
define_binary_op!(Rem, rem);
define_binary_op!(Shl, shl);
define_binary_op!(Shr, shr);
define_binary_op!(Sub, sub);
impl<T, V> Deref for Dim<T, V> {
type Target = V;
fn deref<'a>(&'a self) -> &'a V { &self.0 }
}
impl<T, V> DerefMut for Dim<T, V> {
fn deref_mut<'a>(&'a mut self) -> &'a mut V { &mut self.0 }
}
impl<T, Vl, Vr> PartialEq<Dim<T, Vr>> for Dim<T, Vl>
where T: Dimension, Vl: PartialEq<Vr> {
fn eq(&self, rhs: &Dim<T, Vr>) -> bool { self.0 == rhs.0 }
fn ne(&self, rhs: &Dim<T, Vr>) -> bool { self.0 != rhs.0 }
}
impl<T, V> Eq for Dim<T, V> where T: Dimension, V: Eq { }
impl<T, Vl, Vr> PartialOrd<Dim<T, Vr>> for Dim<T, Vl>
where T: Dimension, Vl: PartialOrd<Vr> {
fn partial_cmp(&self, rhs: &Dim<T, Vr>) -> Option<Ordering> { (self.0).partial_cmp(&rhs.0) }
fn lt(&self, rhs: &Dim<T, Vr>) -> bool { self.0 < rhs.0 }
fn le(&self, rhs: &Dim<T, Vr>) -> bool { self.0 <= rhs.0 }
fn gt(&self, rhs: &Dim<T, Vr>) -> bool { self.0 > rhs.0 }
fn ge(&self, rhs: &Dim<T, Vr>) -> bool { self.0 >= rhs.0 }
}
impl<T, V> Ord for Dim<T, V> where T: Dimension, V: Ord {
fn cmp(&self, rhs: &Dim<T, V>) -> Ordering { (self.0).cmp(&rhs.0) }
}
macro_rules! define_cast_fun {
($fun:ident, $prim:ident) => (
fn $fun(&self) -> Option<$prim> {
(self.0).$fun()
}
)
}
impl<T, V> ToPrimitive for Dim<T, V> where T: Dimensionless, V: ToPrimitive {
define_cast_fun!(to_i64, i64);
define_cast_fun!(to_u64, u64);
define_cast_fun!(to_int, isize);
define_cast_fun!(to_i8, i8);
define_cast_fun!(to_i16, i16);
define_cast_fun!(to_i32, i32);
define_cast_fun!(to_uint, usize);
define_cast_fun!(to_u8, u8);
define_cast_fun!(to_u16, u16);
define_cast_fun!(to_u32, u32);
define_cast_fun!(to_f32, f32);
define_cast_fun!(to_f64, f64);
}
impl<T, V> NumCast for Dim<T, V> where T: Dimensionless, V: NumCast {
fn from<N>(n: N) -> Option<Self> where N: ToPrimitive {
match NumCast::from(n) {
Some(v) => Some(Dim(v)),
None => None
}
}
}
macro_rules! define_unary_float {
($fun:ident, $returns:ty) => (
fn $fun(self) -> $returns { Dim( (self.0).$fun()) }
)
}