use num::One;
use heapsize::HeapSizeOf;
use num_traits::NumCast;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::ops::{Add, Mul, Sub, Div};
use std::marker::PhantomData;
#[derive(Copy, RustcDecodable, RustcEncodable, Debug)]
pub struct ScaleFactor<T, Src, Dst>(pub T, PhantomData<(Src, Dst)>);
impl<T: HeapSizeOf, Src, Dst> HeapSizeOf for ScaleFactor<T, Src, Dst> {
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children()
}
}
impl<T, Src, Dst> Deserialize for ScaleFactor<T, Src, Dst> where T: Deserialize {
fn deserialize<D>(deserializer: &mut D) -> Result<ScaleFactor<T, Src, Dst>, D::Error>
where D: Deserializer {
Ok(ScaleFactor(try!(Deserialize::deserialize(deserializer)), PhantomData))
}
}
impl<T, Src, Dst> Serialize for ScaleFactor<T, Src, Dst> where T: Serialize {
fn serialize<S>(&self, serializer: &mut S) -> Result<(),S::Error> where S: Serializer {
self.0.serialize(serializer)
}
}
impl<T, Src, Dst> ScaleFactor<T, Src, Dst> {
pub fn new(x: T) -> ScaleFactor<T, Src, Dst> {
ScaleFactor(x, PhantomData)
}
}
impl<T: Clone, Src, Dst> ScaleFactor<T, Src, Dst> {
pub fn get(&self) -> T {
self.0.clone()
}
}
impl<T: Clone + One + Div<T, Output=T>, Src, Dst> ScaleFactor<T, Src, Dst> {
pub fn inv(&self) -> ScaleFactor<T, Dst, Src> {
let one: T = One::one();
ScaleFactor::new(one / self.get())
}
}
impl<T: Clone + Mul<T, Output=T>, A, B, C>
Mul<ScaleFactor<T, B, C>> for ScaleFactor<T, A, B> {
type Output = ScaleFactor<T, A, C>;
#[inline]
fn mul(self, other: ScaleFactor<T, B, C>) -> ScaleFactor<T, A, C> {
ScaleFactor::new(self.get() * other.get())
}
}
impl<T: Clone + Add<T, Output=T>, Src, Dst> Add for ScaleFactor<T, Src, Dst> {
type Output = ScaleFactor<T, Src, Dst>;
#[inline]
fn add(self, other: ScaleFactor<T, Src, Dst>) -> ScaleFactor<T, Src, Dst> {
ScaleFactor::new(self.get() + other.get())
}
}
impl<T: Clone + Sub<T, Output=T>, Src, Dst> Sub for ScaleFactor<T, Src, Dst> {
type Output = ScaleFactor<T, Src, Dst>;
#[inline]
fn sub(self, other: ScaleFactor<T, Src, Dst>) -> ScaleFactor<T, Src, Dst> {
ScaleFactor::new(self.get() - other.get())
}
}
impl<T: NumCast + Clone, Src, Dst0> ScaleFactor<T, Src, Dst0> {
pub fn cast<T1: NumCast + Clone>(&self) -> Option<ScaleFactor<T1, Src, Dst0>> {
NumCast::from(self.get()).map(ScaleFactor::new)
}
}
impl<T: Clone + PartialEq, Src, Dst> PartialEq for ScaleFactor<T, Src, Dst> {
fn eq(&self, other: &ScaleFactor<T, Src, Dst>) -> bool {
self.get().eq(&other.get())
}
}
impl<T: Clone, Src, Dst> Clone for ScaleFactor<T, Src, Dst> {
fn clone(&self) -> ScaleFactor<T, Src, Dst> {
ScaleFactor::new(self.get())
}
}
#[cfg(test)]
mod tests {
use super::ScaleFactor;
#[derive(Debug)]
enum Inch {}
#[derive(Debug)]
enum Cm {}
#[derive(Debug)]
enum Mm {}
#[test]
fn test_scale_factor() {
let mm_per_inch: ScaleFactor<f32, Inch, Mm> = ScaleFactor::new(25.4);
let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
let mm_per_cm: ScaleFactor<f32, Cm, Mm> = cm_per_mm.inv();
assert_eq!(mm_per_cm.get(), 10.0);
let cm_per_inch: ScaleFactor<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
assert_eq!(cm_per_inch, ScaleFactor::new(2.54));
let a: ScaleFactor<isize, Inch, Inch> = ScaleFactor::new(2);
let b: ScaleFactor<isize, Inch, Inch> = ScaleFactor::new(3);
assert!(a != b);
assert_eq!(a, a.clone());
assert_eq!(a.clone() + b.clone(), ScaleFactor::new(5));
assert_eq!(a - b, ScaleFactor::new(-1));
}
}