pub mod calculation;
pub mod constructor;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub trait CurrencyLocale {
fn separator(&self) -> char;
fn thousand_separator(&self) -> char;
fn currency_symbol(&self) -> &'static str;
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct Currency<L: CurrencyLocale + Default> {
negative: bool,
full: usize,
part: u8,
locale: L,
}
impl<L> std::fmt::Display for Currency<L>
where
L: CurrencyLocale + Default,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut buffer = self.full.to_string();
if buffer.len() > 3 {
let len = buffer.len() - 2;
for idx in (1..len).rev().step_by(3) {
buffer.insert(idx, self.locale.thousand_separator());
}
}
if self.negative {
write!(f, "-")?;
}
write!(
f,
"{}{}{:02} {}",
buffer,
self.locale.separator(),
self.part,
self.locale.currency_symbol()
)
}
}
impl<L: CurrencyLocale + Default> Currency<L> {
#[must_use]
pub fn new(negative: bool, full: usize, part: u8, locale: L) -> Self {
Self {
negative,
full,
part,
locale,
}
}
#[must_use]
pub fn with_locale(mut self, locale: L) -> Self {
self.locale = locale;
self
}
}
#[cfg(test)]
mod test {
use super::*;
#[derive(Clone, Copy, Default, Debug, PartialEq)]
enum CurrencyL {
#[default]
De,
}
impl CurrencyLocale for CurrencyL {
fn separator(&self) -> char {
','
}
fn thousand_separator(&self) -> char {
'.'
}
fn currency_symbol(&self) -> &'static str {
"€"
}
}
#[test]
fn print_currency() {
let mut curr = Currency::new(false, 2, 22, CurrencyL::De);
for (full, full_string) in [
(2, "2"),
(20, "20"),
(200, "200"),
(2_000, "2.000"),
(20_000, "20.000"),
(200_000, "200.000"),
(2_000_000, "2.000.000"),
(20_000_000, "20.000.000"),
(200_000_000, "200.000.000"),
] {
curr.full = full;
assert_eq!(format!("{full_string},22 €"), curr.to_string());
}
let curr = Currency::new(false, 2, 2, CurrencyL::De);
assert_eq!("2,02 €", &curr.to_string());
}
#[test]
fn construct_f32() {
let first_val = 100.8_f32;
let second_val = 191.0_f32;
let expected = Currency::<CurrencyL>::from(first_val + second_val);
assert_eq!(expected, Currency::new(false, 291, 80, CurrencyL::De));
}
}