#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rate {
x20: u32,
}
impl Rate {
pub fn from_f32(r: f32) -> Option<Self> {
if r < 0.0 || r > u32::MAX as f32 {
None
} else {
Some(Self {
x20: (r * 20.0).round() as u32,
})
}
}
pub fn from_string(string: &str) -> Option<Self> {
Self::from_f32(string.parse().ok()?)
}
pub fn from_x20(x20: u32) -> Self {
Self { x20 }
}
pub fn as_f32(self) -> f32 {
self.x20 as f32 / 20.0
}
pub fn as_x20(self) -> u32 {
self.x20
}
}
impl std::fmt::Display for Rate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}.{:02}x", (self.x20 * 5) / 100, (self.x20 * 5) % 100)
}
}
impl std::fmt::Debug for Rate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}
impl Default for Rate {
fn default() -> Self {
Self::from_x20(20)
}
}
impl From<f32> for Rate {
fn from(value: f32) -> Self {
Self::from_f32(value).expect("Invalid rate string")
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
pub struct RateParseError;
impl std::fmt::Display for RateParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid rate")
}
}
impl std::error::Error for RateParseError {}
impl std::str::FromStr for Rate {
type Err = RateParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_string(s).ok_or(RateParseError)
}
}
impl std::ops::Add for Rate {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::from_x20(self.x20 + rhs.x20)
}
}
impl std::ops::Sub for Rate {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::from_x20(self.x20 - rhs.x20)
}
}
impl std::ops::AddAssign for Rate {
fn add_assign(&mut self, other: Self) {
self.x20 += other.x20;
}
}
impl std::ops::SubAssign for Rate {
fn sub_assign(&mut self, other: Self) {
self.x20 -= other.x20;
}
}