use std::fmt;
use crate::can_apply::CanApply;
#[derive(serde::Deserialize, serde::Serialize)]
#[derive(Debug, Clone, Copy, Eq)]
pub struct PercentU16 {
value: u16,
}
const MAX_VALUE: i32 = 2000;
const MAX_F32_VALUE: f32 = 2.0;
const MIN_VALUE: i32 = 0;
const MIN_F32_VALUE: f32 = 0.;
const HUNDRED_VALUE: u16 = 1000;
impl PercentU16 {
pub const MAX: PercentU16 = PercentU16 { value: MAX_VALUE as u16 };
pub const MIN: PercentU16 = PercentU16 { value: MIN_VALUE as u16 };
pub const ZERO: PercentU16 = PercentU16::MIN;
pub const HUNDRED: PercentU16 = Self::from_value(HUNDRED_VALUE);
pub const fn from_value(value: u16) -> PercentU16 {
PercentU16 {
value,
}
}
pub fn to_f32(self) -> f32 {
(self.value as f32) / 1000.0
}
}
impl CanApply<u32> for PercentU16 {
fn apply(self, value: u32) -> u32 {
let i: i64 = value as i64;
((i * self.value as i64) / HUNDRED_VALUE as i64) as u32
}
}
impl fmt::Display for PercentU16 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_f32())
}
}
impl From<f32> for PercentU16 {
fn from(rate: f32) -> Self {
if rate.is_nan() {
return PercentU16 { value: MIN_VALUE as u16 }
}
if rate < MIN_F32_VALUE {
PercentU16 { value: MIN_VALUE as u16 }
} else if MAX_F32_VALUE < rate {
PercentU16 { value: MAX_VALUE as u16 }
} else {
let i: i32 = (rate * 1000.0) as i32; PercentU16 { value: i as u16 }
}
}
}
impl PartialEq for PercentU16 {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
#[cfg(test)]
mod tests {
use crate::percent::PercentU16;
use crate::percent::CanApply;
#[test]
fn too_high() {
assert_eq!(PercentU16::MAX, PercentU16::from(201.0));
}
#[test]
fn too_low() {
assert_eq!(PercentU16::from(-0.1), PercentU16::from(0.0));
}
#[test]
fn to_f32() {
assert_eq!(PercentU16::from(1.5).to_f32(), 1.5);
}
#[test]
fn apply() {
assert_eq!(PercentU16::from(0.5).apply(60), 30);
}
#[test]
fn from_f32() {
let u: PercentU16 = From::from(f32::NAN);
assert_eq!(u, PercentU16::MIN);
let u: PercentU16 = From::from(2.0);
assert_eq!(u, PercentU16::MAX);
let u: PercentU16 = From::from(100.0);
assert_eq!(u, PercentU16::MAX);
let u: PercentU16 = From::from(0.);
assert_eq!(u, PercentU16::MIN);
let u: PercentU16 = From::from(-100.);
assert_eq!(u, PercentU16::MIN);
}
}