84 lines
1.8 KiB
Rust
84 lines
1.8 KiB
Rust
#[derive(Copy, Clone, Debug)]
|
|
pub struct Proportion {
|
|
pub(crate) value: f64,
|
|
}
|
|
|
|
impl Proportion {
|
|
pub fn new<T: Into<f64>>(value: T) -> Self {
|
|
let mut new = Self {
|
|
value: value.into(),
|
|
};
|
|
new.clamp_to_bounds();
|
|
new
|
|
}
|
|
|
|
pub fn from_fraction<T: Into<f64>>(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<T: Into<f64>>(&mut self, new_value: T) {
|
|
self.value = new_value.into();
|
|
self.clamp_to_bounds();
|
|
}
|
|
|
|
pub fn is_zero(&self) -> bool {
|
|
self.value.abs() < f64::EPSILON
|
|
}
|
|
|
|
pub fn is_one(&self) -> bool {
|
|
(self.value - 1.0).abs() < f64::EPSILON
|
|
}
|
|
|
|
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<f64> for Proportion {
|
|
fn as_ref(&self) -> &f64 {
|
|
&self.value
|
|
}
|
|
}
|
|
|
|
impl std::ops::Deref for Proportion {
|
|
type Target = f64;
|
|
fn deref(&self) -> &f64 {
|
|
&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<std::cmp::Ordering> {
|
|
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()
|
|
}
|
|
}
|