use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Currency {
Toman,
Rial,
}
impl fmt::Display for Currency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Currency::Toman => "Toman",
Currency::Rial => "Rial",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Amount {
rials: i64,
}
impl Amount {
#[must_use]
pub const fn toman(value: i64) -> Self {
Self {
rials: value.saturating_mul(10),
}
}
#[must_use]
pub const fn rial(value: i64) -> Self {
Self { rials: value }
}
#[must_use]
pub const fn new(value: i64, currency: Currency) -> Self {
match currency {
Currency::Toman => Self::toman(value),
Currency::Rial => Self::rial(value),
}
}
#[must_use]
pub const fn as_rials(&self) -> i64 {
self.rials
}
#[must_use]
pub const fn as_tomans(&self) -> i64 {
self.rials / 10
}
#[must_use]
pub const fn is_zero(&self) -> bool {
self.rials == 0
}
}
impl fmt::Display for Amount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = String::new();
let abs = self.rials.unsigned_abs().to_string();
let bytes = abs.as_bytes();
if self.rials < 0 {
s.push('-');
}
for (i, b) in bytes.iter().enumerate() {
if i > 0 && (bytes.len() - i) % 3 == 0 {
s.push(',');
}
s.push(*b as char);
}
write!(f, "{s} Rial")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_conversion() {
assert_eq!(Amount::toman(50_000).as_rials(), 500_000);
assert_eq!(Amount::rial(500_000).as_tomans(), 50_000);
}
#[test]
fn comparison() {
assert!(Amount::toman(100) < Amount::toman(200));
assert_eq!(Amount::toman(100), Amount::rial(1_000));
}
#[test]
fn display_with_separators() {
assert_eq!(Amount::rial(1_234_567).to_string(), "1,234,567 Rial");
assert_eq!(Amount::rial(0).to_string(), "0 Rial");
}
#[test]
fn negative_amount_displays() {
assert_eq!(Amount::rial(-500).to_string(), "-500 Rial");
}
#[test]
fn const_constructors() {
const FEE: Amount = Amount::toman(1_000);
assert_eq!(FEE.as_rials(), 10_000);
}
}