use crate::{Currency, CurrencyLocale};
use std::ops::{Sub, SubAssign};
impl<L, T> Sub<T> for Currency<L>
where
T: Into<Currency<L>>,
L: CurrencyLocale,
{
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
let rhs = rhs.into();
match (self.negative, rhs.negative) {
(false, true) | (true, false) => {
Self::new(self.negative, self.amount + rhs.amount, self.locale)
}
(false, false) | (true, true) => {
let negative = self.amount.checked_sub(rhs.amount).is_none();
let amount = if negative {
rhs.amount - self.amount
} else {
self.amount - rhs.amount
};
Self::new(self.negative ^ negative, amount, self.locale)
}
}
}
}
impl<L, T> SubAssign<T> for Currency<L>
where
T: Into<Currency<L>>,
L: CurrencyLocale,
{
fn sub_assign(&mut self, rhs: T) {
let rhs = rhs.into();
match (self.negative, rhs.negative) {
(false, true) | (true, false) => self.amount += rhs.amount,
(false, false) | (true, true) => {
let negative = self.amount.checked_sub(rhs.amount).is_none();
self.amount = if negative {
rhs.amount - self.amount
} else {
self.amount - rhs.amount
};
self.negative ^= negative;
}
}
}
}
#[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 sub_currency() {
let 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(true, 77, CurrencyL::De));
}
#[test]
fn sub_usize() {
let curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
let expected = curr1 - 22usize;
assert_eq!(expected, Currency::new(false, 24_000_00, CurrencyL::De));
}
#[test]
fn sub_f32() {
let curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
let expected = curr1 - 24_000.98_f32;
assert_eq!(expected, Currency::new(true, 76, CurrencyL::De));
}
#[test]
fn sub_negative_f32() {
let curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
let expected = curr1 - -24_000.98_f32;
assert_eq!(expected, Currency::new(false, 48_001_20, CurrencyL::De));
}
#[test]
fn negative_sub_f32() {
let curr1 = Currency::new(true, 24_000_22, CurrencyL::De);
let expected = curr1 - 24_000.98_f32;
assert_eq!(expected, Currency::new(true, 48_001_20, CurrencyL::De));
}
#[test]
fn negative_sub_negative_f32() {
let curr1 = Currency::new(true, 24_000_22, CurrencyL::De);
let expected = curr1 - -24_000.98_f32;
assert_eq!(expected, Currency::new(false, 76, CurrencyL::De));
}
#[test]
fn subassign_usize() {
let mut curr = Currency::new(false, 24_000_22, CurrencyL::De);
curr -= 1usize;
assert_eq!(curr, Currency::new(false, 24_000_21, CurrencyL::De));
}
#[test]
fn subassign_currency() {
let mut curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
let curr2 = Currency::new(false, 24_000_99, CurrencyL::De);
curr1 -= curr2;
assert_eq!(curr1, Currency::new(true, 77, CurrencyL::De));
}
#[test]
fn subassign_negative_currency() {
let mut curr1 = Currency::new(false, 24_00022, CurrencyL::De);
let curr2 = Currency::new(true, 24_000_99, CurrencyL::De);
curr1 -= curr2;
assert_eq!(curr1, Currency::new(false, 48_001_21, CurrencyL::De));
}
#[test]
fn negative_subassign_negative_currency() {
let mut curr1 = Currency::new(true, 24_000_22, CurrencyL::De);
let curr2 = Currency::new(true, 24_000_99, CurrencyL::De);
curr1 -= curr2;
assert_eq!(curr1, Currency::new(false, 77, CurrencyL::De));
}
}