From 8a6c67519af1ad65f2d1f54f394d0139fee6d90b Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Wed, 17 Aug 2022 13:30:45 +1200 Subject: [PATCH] Change backing type from f64 to generic T --- src/bounds.rs | 30 +++++++++++++ src/constants.rs | 9 ---- src/conversions.rs | 13 ------ src/lib.rs | 6 ++- src/operator_overloads.rs | 25 +++-------- src/proportion.rs | 95 +++++++++++++++------------------------ 6 files changed, 77 insertions(+), 101 deletions(-) create mode 100644 src/bounds.rs delete mode 100644 src/constants.rs delete mode 100644 src/conversions.rs diff --git a/src/bounds.rs b/src/bounds.rs new file mode 100644 index 0000000..783b4dc --- /dev/null +++ b/src/bounds.rs @@ -0,0 +1,30 @@ +use crate::Internal; +use crate::Proportion; + +pub trait Bounded { + const MIN: Self; + const MAX: Self; +} + +macro_rules! impl_bounded { + ($type:ty) => { + impl Bounded for $type { + const MIN: Self = <$type>::MIN; + const MAX: Self = <$type>::MAX; + } + + }; +} + +impl_bounded!(u8); +impl_bounded!(u16); +impl_bounded!(u32); +impl_bounded!(u64); +impl_bounded!(u128); + +impl Proportion { + pub const MIN: Self = Proportion { value: T::MIN }; + pub const MAX: Self = Proportion { value: T::MAX }; + pub const ZERO: Self = Self::MIN; + pub const ONE: Self = Self::MAX; +} diff --git a/src/constants.rs b/src/constants.rs deleted file mode 100644 index d5fd229..0000000 --- a/src/constants.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::Proportion; - -impl Proportion { - pub const MIN: Self = Proportion { value: 0.0 }; - pub const MAX: Self = Proportion { value: 1.0 }; - - pub const ZERO: Self = Self::MIN; - pub const ONE: Self = Self::MAX; -} diff --git a/src/conversions.rs b/src/conversions.rs deleted file mode 100644 index a95d3dc..0000000 --- a/src/conversions.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::Proportion; - -impl From for Proportion { - fn from(value: f64) -> Self { - Self::new(value) - } -} - -impl From for Proportion { - fn from(value: f32) -> Self { - Self::new(value) - } -} diff --git a/src/lib.rs b/src/lib.rs index cf77a52..4b16455 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ -mod constants; -mod conversions; +mod bounds; mod operator_overloads; mod proportion; +pub use bounds::Bounded; pub use proportion::Proportion; + +pub trait Internal: Bounded + PartialEq + PartialOrd + Eq + Ord + Copy + Clone + std::fmt::Debug {} diff --git a/src/operator_overloads.rs b/src/operator_overloads.rs index 4b5c442..d4e33bd 100644 --- a/src/operator_overloads.rs +++ b/src/operator_overloads.rs @@ -1,27 +1,16 @@ -use crate::Proportion; - -impl std::ops::Neg for Proportion { +use crate::*; +use std::ops::*; +impl> Neg for Proportion { type Output = Self; - fn neg(mut self) -> Self::Output { - self.value = 1.0 - self.value; + self.value = T::MAX - self.value; self } } -impl std::ops::Mul for Proportion { - type Output = f64; - - fn mul(self, rhs: f64) -> f64 { +impl> Mul for Proportion { + type Output = T; + fn mul(self, rhs: T) -> T { self.value * rhs } } - -impl std::ops::Mul for usize { - type Output = usize; - - fn mul(self, rhs: Proportion) -> usize { - let lhs = self as f64; - (lhs * rhs.value).round() as usize - } -} diff --git a/src/proportion.rs b/src/proportion.rs index ad64e61..be308d0 100644 --- a/src/proportion.rs +++ b/src/proportion.rs @@ -1,83 +1,60 @@ -#[derive(Copy, Clone, Debug)] -pub struct Proportion { - pub(crate) value: f64, +use crate::Internal; +use std::{cmp::*, ops::*}; + + +#[derive(Copy, Clone)] +pub struct Proportion { + pub(crate) value: T, } -impl Proportion { - pub fn new>(value: T) -> Self { - let mut new = Self { - value: value.into(), - }; - new.clamp_to_bounds(); - new +impl Proportion { + pub fn new(value: T) -> Self { + Self { value } } - pub fn from_fraction>(numerator: T, denominator: T) -> Self { - let denominator = denominator.into(); - if denominator == 0.0 { - return Self::MAX; - } - let numerator = numerator.into(); - Self::new(numerator / denominator) - } - - pub fn value(&self) -> f64 { - self.value - } - - pub fn set>(&mut self, new_value: T) { - self.value = new_value.into(); - self.clamp_to_bounds(); + pub fn set(&mut self, new_value: T) { + self.value = new_value; } pub fn is_zero(&self) -> bool { - self.value.abs() < f64::EPSILON + self.value == T::MIN } pub fn is_one(&self) -> bool { - (self.value - 1.0).abs() < f64::EPSILON - } + self.value == T::MAX } - fn clamp_to_bounds(&mut self) { - self.value = if self.value > 1.0 { - 1.0 - } else if self.value < 0.0 { - 0.0 - } else { - self.value - } - } } -impl AsRef for Proportion { - fn as_ref(&self) -> &f64 { +impl AsRef for Proportion { + fn as_ref(&self) -> &T { &self.value } } - -impl std::ops::Deref for Proportion { - type Target = f64; - fn deref(&self) -> &f64 { +impl Deref for Proportion { + type Target = T; + fn deref(&self) -> &T { &self.value } } - -impl std::cmp::PartialEq for Proportion { - fn eq(&self, other: &Proportion) -> bool { - self.value == other.value - } -} - -impl std::cmp::PartialOrd for Proportion { - fn partial_cmp(&self, other: &Proportion) -> Option { +impl PartialOrd for Proportion { + fn partial_cmp(&self, other: &Proportion) -> Option { self.value.partial_cmp(&other.value) } } - -impl std::cmp::Eq for Proportion {} - -impl std::cmp::Ord for Proportion { - fn cmp(&self, other: &Proportion) -> std::cmp::Ordering { - self.partial_cmp(&other).unwrap() +impl Ord for Proportion { + fn cmp(&self, other: &Proportion) -> Ordering { + self.value.cmp(&other.value) } } +impl PartialEq for Proportion { + fn eq(&self, other: &Proportion) -> bool { + self.value.eq(&other.value) + } +} +impl Eq for Proportion {} + +impl std::fmt::Debug for Proportion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "Proportion {{ {:?} / {:?} }}", self.value, Self::MAX) + } +}