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) -> char;
}
#[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,
}
}
}
#[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) -> char {
'€'
}
}
#[test]
fn add_currency() {
let mut curr1 = Currency::new(false, 24_000, 22, CurrencyL::De);
let curr2 = Currency::new(false, 24_000, 99, CurrencyL::De);
let expected = curr1 + curr2;
assert_eq!(expected, Currency::new(false, 48_001, 21, CurrencyL::De));
let expected = curr1 + 24_000.99_f32;
assert_eq!(expected, Currency::new(false, 48_001, 21, CurrencyL::De));
curr1 += 1;
assert_eq!(curr1, Currency::new(false, 24_001, 22, CurrencyL::De));
curr1 += curr2;
assert_eq!(curr1, Currency::new(false, 48_002, 22, CurrencyL::De));
}
#[test]
fn sub_currency() {
let mut curr1 = Currency::new(false, 24_000, 22, CurrencyL::De);
let mut curr2 = Currency::new(false, 24_000, 99, CurrencyL::De);
let expected = curr1 - curr2;
assert_eq!(expected, Currency::new(true, 0, 77, CurrencyL::De));
let expected = curr1 - 24_000.98_f32;
assert_eq!(expected, Currency::new(true, 0, 76, CurrencyL::De));
let expected = curr1 - 23_999.22_f32;
assert_eq!(expected, Currency::new(false, 1, 0, CurrencyL::De));
curr1 -= 1;
assert_eq!(curr1, Currency::new(false, 23_999, 22, CurrencyL::De));
curr1 -= curr2;
assert_eq!(curr1, Currency::new(true, 0, 77, CurrencyL::De));
curr2 -= 22_000.12_f32;
assert_eq!(curr2, Currency::new(false, 2_000, 87, CurrencyL::De));
}
#[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 mul_currency() {
let curr = Currency::new(false, 2, 22, CurrencyL::De);
let mut expected = curr * 2usize;
assert_eq!(expected, Currency::new(false, 4, 44, CurrencyL::De));
expected = curr * 2.0f32;
assert_eq!(expected, Currency::new(false, 4, 44, CurrencyL::De));
expected = curr * 2.0f64;
assert_eq!(expected, Currency::new(false, 4, 44, CurrencyL::De));
}
#[test]
fn mul_currency_negative() {
let curr = Currency::new(false, 2, 22, CurrencyL::De);
let mut expected = curr * -2.0f32;
assert_eq!(expected, Currency::new(true, 4, 44, CurrencyL::De));
expected = curr * -0.5f32;
assert_eq!(expected, Currency::new(true, 1, 11, CurrencyL::De));
expected = curr * -2.0f64;
assert_eq!(expected, Currency::new(true, 4, 44, CurrencyL::De));
expected = curr * -0.5f64;
assert_eq!(expected, Currency::new(true, 1, 11, CurrencyL::De));
}
#[test]
fn div_currency() {
let curr = Currency::new(false, 2, 22, CurrencyL::De);
let mut expected = curr / 2usize;
assert_eq!(expected, Currency::new(false, 1, 11, CurrencyL::De));
expected = curr / 2.0f32;
assert_eq!(expected, Currency::new(false, 1, 11, CurrencyL::De));
expected = curr / 2.0f64;
assert_eq!(expected, Currency::new(false, 1, 11, CurrencyL::De));
expected = curr / 0.5f32;
assert_eq!(expected, Currency::new(false, 4, 44, CurrencyL::De));
expected = curr / 0.5f64;
assert_eq!(expected, Currency::new(false, 4, 44, CurrencyL::De));
expected = curr / -0.5f64;
assert_eq!(expected, Currency::new(true, 4, 44, CurrencyL::De));
}
#[test]
fn div_currency_negative() {
let curr = Currency::new(false, 2, 22, CurrencyL::De);
let mut expected = curr / -2.0f32;
assert_eq!(expected, Currency::new(true, 1, 11, CurrencyL::De));
expected = curr / -2.0f64;
assert_eq!(expected, Currency::new(true, 1, 11, CurrencyL::De));
expected = curr / -0.5f32;
assert_eq!(expected, Currency::new(true, 4, 44, CurrencyL::De));
expected = curr / -0.5f64;
assert_eq!(expected, Currency::new(true, 4, 44, CurrencyL::De));
}
#[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));
}
}