use std::{
fmt::{Debug, Display},
iter::Sum,
marker::PhantomData,
str::FromStr,
};
use crate::{
BaseMoney, BaseOps, Decimal, Money, MoneyError, MoneyOps,
base::{Amount, MoneyParser},
macros::dec,
};
use crate::{Currency, MoneyFormatter};
use rust_decimal::{MathematicalOps, prelude::ToPrimitive};
#[derive(Copy, PartialEq, Eq)]
pub struct RawMoney<C: Currency> {
amount: Decimal,
_currency: PhantomData<C>,
}
impl<C> RawMoney<C>
where
C: Currency,
{
#[inline]
pub fn finish(self) -> Money<C> {
Money::from_decimal(self.amount)
}
}
impl<C: Currency> Default for RawMoney<C> {
fn default() -> Self {
Self {
amount: Decimal::default(),
_currency: PhantomData,
}
}
}
impl<C: Currency> Ord for RawMoney<C>
where
C: Currency + PartialEq + Eq,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.amount.cmp(&other.amount)
}
}
impl<C> PartialOrd for RawMoney<C>
where
C: Currency + PartialEq + Eq,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<C> Amount<C> for RawMoney<C>
where
C: Currency,
{
#[inline(always)]
fn get_decimal(&self) -> Option<Decimal> {
Some(self.amount())
}
}
impl<C> FromStr for RawMoney<C>
where
C: Currency,
{
type Err = MoneyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim();
let dec_num = Decimal::from_str(s).map_err(|err| {
MoneyError::ParseStrError(format!("failed parsing money from string: {}", err).into())
})?;
Ok(Self::from_decimal(dec_num))
}
}
impl<C: Currency> Clone for RawMoney<C> {
fn clone(&self) -> Self {
Self {
amount: self.amount,
_currency: PhantomData,
}
}
}
impl<C> Display for RawMoney<C>
where
C: Currency,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.display())
}
}
impl<C> Debug for RawMoney<C>
where
C: Currency,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RawMoney({}, {})", C::CODE, self.amount)
}
}
impl<C: Currency> Sum for RawMoney<C> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(RawMoney::default(), |acc, b| acc + b)
}
}
impl<'a, C: Currency> Sum<&'a RawMoney<C>> for RawMoney<C> {
fn sum<I: Iterator<Item = &'a RawMoney<C>>>(iter: I) -> Self {
iter.fold(RawMoney::default(), |acc, b| acc + b.clone())
}
}
impl<C> BaseMoney<C> for RawMoney<C>
where
C: Currency,
{
#[inline(always)]
fn from_decimal(amount: Decimal) -> Self {
Self {
amount,
_currency: PhantomData,
}
}
#[inline(always)]
fn amount(&self) -> Decimal {
self.amount
}
#[inline(always)]
fn minor_amount(&self) -> Option<i128> {
self.amount()
.round_dp(C::MINOR_UNIT.into())
.checked_mul(dec!(10).checked_powu(C::MINOR_UNIT.into())?)?
.to_i128()
}
}
impl<C: Currency> From<crate::Money<C>> for RawMoney<C> {
fn from(value: Money<C>) -> Self {
Self::from_decimal(value.amount())
}
}
impl<C: Currency> From<RawMoney<C>> for crate::Money<C> {
fn from(value: crate::RawMoney<C>) -> Self {
Self::from_decimal(value.amount())
}
}
impl<C> BaseOps<C> for RawMoney<C> where C: Currency {}
impl<C> MoneyParser<C> for RawMoney<C> where C: Currency {}
impl<C> MoneyFormatter<C> for RawMoney<C> where C: Currency {}
impl<C> MoneyOps<C> for RawMoney<C> where C: Currency {}