First commit

This commit is contained in:
Ben Bridle 2022-08-17 12:09:35 +12:00
commit 57e084f53a
7 changed files with 149 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
Cargo.lock

9
Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "proportion"
version = "1.0.0"
authors = ["Ben Bridle <bridle.benjamin@gmail.com>"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

9
src/constants.rs Normal file
View File

@ -0,0 +1,9 @@
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;
}

13
src/conversions.rs Normal file
View File

@ -0,0 +1,13 @@
use crate::Proportion;
impl From<f64> for Proportion {
fn from(value: f64) -> Self {
Self::new(value)
}
}
impl From<f32> for Proportion {
fn from(value: f32) -> Self {
Self::new(value)
}
}

6
src/lib.rs Normal file
View File

@ -0,0 +1,6 @@
mod constants;
mod conversions;
mod operator_overloads;
mod proportion;
pub use proportion::Proportion;

27
src/operator_overloads.rs Normal file
View File

@ -0,0 +1,27 @@
use crate::Proportion;
impl std::ops::Neg for Proportion {
type Output = Self;
fn neg(mut self) -> Self::Output {
self.value = 1.0 - self.value;
self
}
}
impl std::ops::Mul<f64> for Proportion {
type Output = f64;
fn mul(self, rhs: f64) -> f64 {
self.value * rhs
}
}
impl std::ops::Mul<Proportion> for usize {
type Output = usize;
fn mul(self, rhs: Proportion) -> usize {
let lhs = self as f64;
(lhs * rhs.value).round() as usize
}
}

83
src/proportion.rs Normal file
View File

@ -0,0 +1,83 @@
#[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()
}
}