null-kane 3.0.0

currency crate with the option to add your own currency localization logic
Documentation
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));
    }
}