use std::fmt::Display; use rust_decimal::Decimal; #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] pub struct InterestRate { rate_as_fraction: Decimal, } impl InterestRate { pub const ZERO: Self = InterestRate { rate_as_fraction: Decimal::ZERO, }; pub fn from_percentage(rate_in_percent: Decimal) -> Self { InterestRate { rate_as_fraction: rate_in_percent / Decimal::ONE_HUNDRED, } } pub const fn from_fraction(rate_as_fraction: Decimal) -> Self { InterestRate { rate_as_fraction } } pub const fn as_fraction(self) -> Decimal { self.rate_as_fraction } pub fn as_percentage(self) -> Decimal { (self.rate_as_fraction * Decimal::ONE_HUNDRED).normalize() } } impl Display for InterestRate { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{} %", self.as_percentage()) } } #[cfg(test)] mod tests { use super::*; #[test] fn create_from_percentage_yields_correct_rate() { assert_eq!( InterestRate::from_percentage(Decimal::new(415, 2)).as_fraction(), Decimal::new(415, 4) ); } #[test] fn create_from_fraction_yields_correct_rate() { assert_eq!( InterestRate::from_fraction(Decimal::new(415, 4)).as_fraction(), Decimal::new(415, 4) ); } #[test] fn create_from_fraction_is_properly_output_as_percentage() { assert_eq!( InterestRate::from_fraction(Decimal::new(314, 4)).as_percentage(), Decimal::new(314, 2) ) } #[test] fn display_works_as_expected_with_no_trailing_zeros() { let interest_rate = InterestRate::from_fraction(Decimal::new(3145, 5)); assert_eq!(format!("{}", interest_rate), "3.145 %"); } }