percent.rs (2199B)
1 use core::fmt; 2 use core::str::FromStr; 3 4 use crate::RadrootsCoreDecimal; 5 use crate::money::RadrootsCoreMoney; 6 7 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 8 #[derive(Clone, Debug, PartialEq, Eq)] 9 pub struct RadrootsCorePercent { 10 #[cfg_attr(feature = "serde", serde(with = "crate::serde_ext::decimal_str"))] 11 pub value: RadrootsCoreDecimal, 12 } 13 14 impl RadrootsCorePercent { 15 #[inline] 16 pub fn new(value: RadrootsCoreDecimal) -> Self { 17 Self { value } 18 } 19 20 #[inline] 21 pub fn from_ratio(ratio_0_to_1: RadrootsCoreDecimal) -> Self { 22 Self { 23 value: ratio_0_to_1 * RadrootsCoreDecimal::from(100u32), 24 } 25 } 26 27 #[inline] 28 pub fn to_ratio(&self) -> RadrootsCoreDecimal { 29 self.value / RadrootsCoreDecimal::from(100u32) 30 } 31 32 #[inline] 33 pub fn of_money(&self, base: &RadrootsCoreMoney) -> RadrootsCoreMoney { 34 base.mul_decimal(self.to_ratio()) 35 } 36 37 #[inline] 38 pub fn of_money_quantized(&self, base: &RadrootsCoreMoney) -> RadrootsCoreMoney { 39 base.mul_decimal(self.to_ratio()).quantize_to_currency() 40 } 41 } 42 43 impl fmt::Display for RadrootsCorePercent { 44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 45 write!(f, "{}%", self.value.normalize()) 46 } 47 } 48 49 impl FromStr for RadrootsCorePercent { 50 type Err = RadrootsCorePercentParseError; 51 52 fn from_str(s: &str) -> Result<Self, Self::Err> { 53 let trimmed = s.trim_end(); 54 let no_pct = trimmed.strip_suffix('%').unwrap_or(trimmed).trim(); 55 let dec = no_pct 56 .parse::<RadrootsCoreDecimal>() 57 .map_err(|_| RadrootsCorePercentParseError::InvalidNumber)?; 58 Ok(RadrootsCorePercent::new(dec)) 59 } 60 } 61 62 #[non_exhaustive] 63 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 64 pub enum RadrootsCorePercentParseError { 65 InvalidNumber, 66 } 67 68 impl fmt::Display for RadrootsCorePercentParseError { 69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 match self { 71 RadrootsCorePercentParseError::InvalidNumber => write!(f, "invalid percent string"), 72 } 73 } 74 } 75 76 #[cfg(feature = "std")] 77 impl std::error::Error for RadrootsCorePercentParseError {}