use std::{cmp::Ordering, ops::Add, ops::Sub};
use api::{have_same_amount, have_same_currency, normalize_scale_tuple};
use error::DineroError;
use crate::currencies::Currency;
pub mod api;
pub mod currencies;
pub mod error;
pub mod format;
#[derive(Debug, Clone, Copy, Eq)]
pub struct Dinero {
pub amount: i128, pub currency: Currency,
pub scale: u32,
}
#[cfg(not(tarpaulin_include))]
impl Dinero {
pub fn new(amount: i128, currency: Currency, scale: Option<u32>) -> Dinero {
Dinero {
scale: scale.unwrap_or_else(|| currency.exponent.to_owned()),
amount,
currency,
}
}
}
#[cfg(not(tarpaulin_include))]
impl PartialEq for Dinero {
fn eq(&self, other: &Dinero) -> bool {
let a = self.to_owned();
let b = other.to_owned();
have_same_amount(&[a, b]) && have_same_currency(&[a, b])
}
}
#[cfg(not(tarpaulin_include))]
impl PartialOrd for Dinero {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg(not(tarpaulin_include))]
impl Ord for Dinero {
fn cmp(&self, other: &Self) -> Ordering {
let a = self.to_owned();
let b = other.to_owned();
let (an, bn) = normalize_scale_tuple(a, b);
an.amount.cmp(&bn.amount)
}
}
#[cfg(not(tarpaulin_include))]
impl Add for Dinero {
type Output = Result<Dinero, DineroError>;
fn add(self, other: Self) -> Self::Output {
if self.currency.code != other.currency.code {
Err(DineroError::UnequalCurrencyError {
a: Some(self.currency),
b: Some(other.currency),
})
} else {
let (an, bn) = normalize_scale_tuple(self, other);
Ok(Dinero {
currency: an.currency,
scale: an.scale,
amount: an.amount + bn.amount,
})
}
}
}
#[cfg(not(tarpaulin_include))]
impl Sub for Dinero {
type Output = Dinero;
fn sub(self, other: Self) -> Self::Output {
let (an, bn) = normalize_scale_tuple(self, other);
Dinero {
currency: an.currency,
scale: an.scale,
amount: an.amount - bn.amount,
}
}
}
#[cfg(test)]
#[cfg(not(tarpaulin_include))]
mod tests {
use super::*;
use crate::currencies::EUR;
use pretty_assertions::assert_eq;
#[test]
fn test_dinero_new() {
assert_eq!(
Dinero::new(42, EUR, Some(2)),
Dinero {
amount: 42,
currency: EUR,
scale: 2
}
);
}
#[test]
fn assert_dinero_eq() {
assert_eq!(
Dinero::new(42, EUR, Some(2)), Dinero::new(42, EUR, Some(2))
);
}
#[test]
fn assert_dinero_neq() {
assert_ne!(
Dinero::new(142, EUR, Some(2)), Dinero::new(42, EUR, Some(2))
);
}
#[test]
fn assert_dinero_gt() {
assert!(Dinero::new(142, EUR, Some(2)) > Dinero::new(42, EUR, Some(2)));
}
#[test]
fn assert_dinero_gt_eq() {
assert!(Dinero::new(142, EUR, Some(2)) >= Dinero::new(42, EUR, Some(2)));
}
#[test]
fn assert_dinero_lt() {
assert!(Dinero::new(1, EUR, Some(2)) < Dinero::new(42, EUR, Some(2)));
}
#[test]
fn assert_dinero_lt_eq() {
assert!(Dinero::new(1, EUR, Some(2)) <= Dinero::new(42, EUR, Some(2)));
}
}