use crate::{Currency, CurrencyLocale};
use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
impl<L, T> Add<T> for Currency<L>
where
T: Into<Currency<L>>,
L: CurrencyLocale + Default,
{
type Output = Self;
fn add(self, rhs: T) -> Self::Output {
let rhs = rhs.into();
if rhs.negative {
self.sub(Self::new(false, rhs.full, rhs.part, rhs.locale))
} else if self.negative {
rhs.sub(Self::new(false, self.full, self.part, self.locale))
} else {
let new_part = self.part + rhs.part;
let new_full = self.full + rhs.full + usize::from(new_part >= 100);
Self::new(false, new_full, new_part % 100, self.locale)
}
}
}
impl<L, T> AddAssign<T> for Currency<L>
where
T: Into<Currency<L>>,
L: CurrencyLocale + Default + Clone,
{
fn add_assign(&mut self, rhs: T) {
let rhs = rhs.into();
if rhs.negative {
let new = self
.clone()
.sub(Self::new(false, rhs.full, rhs.part, rhs.locale));
self.negative = new.negative;
self.full = new.full;
self.part = new.part;
} else if self.negative {
let new = rhs.sub(Self::new(false, self.full, self.part, L::default()));
self.negative = new.negative;
self.full = new.full;
self.part = new.part;
} else {
let new_part = self.part + rhs.part;
self.full += rhs.full + usize::from(new_part >= 100);
self.part %= 100;
}
}
}
impl<L, T> Sub<T> for Currency<L>
where
T: Into<Currency<L>>,
L: CurrencyLocale + Default,
{
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
let rhs = rhs.into();
match (self.negative, rhs.negative) {
(true | false, true) => self.add(Self::new(false, rhs.full, rhs.part, rhs.locale)),
(true, false) => {
let new_part = self.part + rhs.part;
let new_full = self.full + rhs.full + usize::from(new_part >= 100);
Self::new(false, new_full, new_part % 100, self.locale)
}
(false, false) => {
let decrease_full = self.part.checked_sub(rhs.part).is_none();
let decrement = rhs.full + usize::from(decrease_full);
let mut negative = false;
let (new_full, new_part) = if decrement > self.full {
negative = true;
(rhs.full - self.full, rhs.part - self.part)
} else {
(self.full - decrement, self.part - rhs.part)
};
Self::new(negative, new_full, new_part, self.locale)
}
}
}
}
impl<L, T> SubAssign<T> for Currency<L>
where
T: Into<Currency<L>>,
L: CurrencyLocale + Default + Clone,
{
fn sub_assign(&mut self, rhs: T) {
let rhs = rhs.into();
match (self.negative, rhs.negative) {
(true | false, true) => {
let new = rhs
.clone()
.add(Self::new(false, rhs.full, rhs.part, L::default()));
self.negative = new.negative;
self.full = new.full;
self.part = new.part;
}
(true, false) => {
let new_part = self.part + rhs.part;
let new_full = self.full + rhs.full + usize::from(new_part >= 100);
self.part = new_part % 100;
self.full = new_full;
}
(false, false) => {
let decrease_full = self.part.checked_sub(rhs.part).is_none();
let decrement = rhs.full + usize::from(decrease_full);
let mut negative = false;
let (new_full, new_part) = if decrement > self.full {
negative = true;
(
rhs.full - self.full - usize::from(decrease_full),
rhs.part - self.part,
)
} else {
(self.full - decrement, self.part - rhs.part)
};
let new = Self::new(negative, new_full, new_part, self.locale.clone());
self.negative = new.negative;
self.full = new.full;
self.part = new.part;
}
}
}
}
impl<L: CurrencyLocale + Default> Mul<usize> for Currency<L> {
type Output = Self;
fn mul(self, rhs: usize) -> Self::Output {
let rhs = rhs as f32;
let tmp = (self.full as f32 + self.part as f32 / 100.0) * rhs;
let mut result: Currency<L> = tmp.into();
result.locale = self.locale;
result
}
}
impl<L: CurrencyLocale + Default> Mul<f32> for Currency<L> {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
let tmp = (self.full as f32 + self.part as f32 / 100.0) * rhs;
let mut result = Self::from(tmp);
result.negative = self.negative ^ rhs.is_sign_negative();
result.locale = self.locale;
result
}
}
impl<L: CurrencyLocale + Default> Mul<f64> for Currency<L> {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
let tmp = (self.full as f64 + self.part as f64 / 100.0) * rhs;
let mut result = Self::from(tmp);
result.negative = self.negative ^ rhs.is_sign_negative();
result.locale = self.locale;
result
}
}
impl<L: CurrencyLocale + Default> Div<usize> for Currency<L> {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
let mut tmp = self.full * 100 + self.part as usize;
tmp /= rhs;
let part = (tmp % 100) as u8;
let full = tmp / 100;
Self::new(self.negative, full, part, self.locale)
}
}
impl<L: CurrencyLocale + Default> Div<f32> for Currency<L> {
type Output = Self;
fn div(self, rhs: f32) -> Self::Output {
let mut tmp = self.full as f32 + self.part as f32 / 100.0;
tmp /= rhs;
let mut result = Self::from(tmp);
result.negative = self.negative ^ rhs.is_sign_negative();
result.locale = self.locale;
result
}
}
impl<L: CurrencyLocale + Default> Div<f64> for Currency<L> {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
let mut tmp = self.full as f64 + self.part as f64 / 100.0;
tmp /= rhs;
let mut result = Self::from(tmp);
result.negative = self.negative ^ rhs.is_sign_negative();
result.locale = self.locale;
result
}
}