mod fmt;
use std::any::Any;
use crate::{
BaseMoney,
fmt::{CODE_FORMAT, CODE_FORMAT_MINOR, SYMBOL_FORMAT, SYMBOL_FORMAT_MINOR},
};
use fmt::format_obj_money;
use crate::{Currency, Decimal, MoneyError};
pub trait ObjMoney: Send + Sync {
fn amount(&self) -> Decimal;
fn code(&self) -> &str;
fn symbol(&self) -> &str;
fn name(&self) -> &str;
fn minor_unit(&self) -> u16;
fn thousand_separator(&self) -> &str;
fn decimal_separator(&self) -> &str;
fn minor_unit_symbol(&self) -> &str;
fn minor_amount(&self) -> Option<i128>;
fn as_any(&self) -> &dyn Any;
#[cfg(feature = "exchange")]
fn convert(
&self,
to_code: &str,
rate: &dyn crate::exchange::ObjRate,
) -> Result<Box<dyn ObjMoney>, MoneyError>;
#[inline]
fn is_zero(&self) -> bool {
self.amount().is_zero()
}
#[inline]
fn is_positive(&self) -> bool {
if self.is_zero() {
return false;
}
self.amount().is_sign_positive()
}
#[inline]
fn is_negative(&self) -> bool {
if self.is_zero() {
return false;
}
self.amount().is_sign_negative()
}
#[inline]
fn scale(&self) -> u32 {
self.amount().scale()
}
#[inline]
fn fraction(&self) -> Decimal {
self.amount().fract()
}
#[inline]
fn mantissa(&self) -> i128 {
self.amount().mantissa()
}
fn format_code(&self) -> String {
format_obj_money(
self.amount(),
self.code(),
self.symbol(),
self.minor_unit_symbol(),
self.minor_unit(),
self.thousand_separator(),
self.decimal_separator(),
CODE_FORMAT,
)
}
fn format_symbol(&self) -> String {
format_obj_money(
self.amount(),
self.code(),
self.symbol(),
self.minor_unit_symbol(),
self.minor_unit(),
self.thousand_separator(),
self.decimal_separator(),
SYMBOL_FORMAT,
)
}
fn format_code_minor(&self) -> String {
format_obj_money(
self.amount(),
self.code(),
self.symbol(),
self.minor_unit_symbol(),
self.minor_unit(),
self.thousand_separator(),
self.decimal_separator(),
CODE_FORMAT_MINOR,
)
}
fn format_symbol_minor(&self) -> String {
format_obj_money(
self.amount(),
self.code(),
self.symbol(),
self.minor_unit_symbol(),
self.minor_unit(),
self.thousand_separator(),
self.decimal_separator(),
SYMBOL_FORMAT_MINOR,
)
}
}
pub trait ObjIterOps {
#[cfg(feature = "exchange")]
fn checked_sum<M, To>(&self, rates: impl crate::exchange::ObjRate) -> Result<M, MoneyError>
where
M: BaseMoney<To>,
To: Currency;
}
impl ObjMoney for Box<dyn ObjMoney> {
#[inline]
fn amount(&self) -> Decimal {
(**self).amount()
}
#[inline]
fn code(&self) -> &str {
(**self).code()
}
#[inline]
fn symbol(&self) -> &str {
(**self).symbol()
}
#[inline]
fn name(&self) -> &str {
(**self).name()
}
#[inline]
fn minor_unit(&self) -> u16 {
(**self).minor_unit()
}
#[inline]
fn thousand_separator(&self) -> &str {
(**self).thousand_separator()
}
#[inline]
fn decimal_separator(&self) -> &str {
(**self).decimal_separator()
}
#[inline]
fn minor_unit_symbol(&self) -> &str {
(**self).minor_unit_symbol()
}
#[inline]
fn minor_amount(&self) -> Option<i128> {
(**self).minor_amount()
}
#[inline]
fn as_any(&self) -> &dyn std::any::Any {
(**self).as_any()
}
#[cfg(feature = "exchange")]
fn convert(
&self,
to_code: &str,
rate: &dyn crate::exchange::ObjRate,
) -> Result<Box<dyn ObjMoney>, MoneyError> {
(**self).convert(to_code, rate)
}
}
mod money_impl;
#[cfg(feature = "raw_money")]
mod raw_money_impl;
#[cfg(test)]
mod obj_money_test;
impl<I, T> ObjIterOps for I
where
for<'a> &'a I: IntoIterator<Item = &'a T>,
T: ObjMoney,
{
#[cfg(feature = "exchange")]
fn checked_sum<M, To>(&self, rates: impl crate::exchange::ObjRate) -> Result<M, MoneyError>
where
M: BaseMoney<To>,
To: Currency,
{
let mut total = Decimal::ZERO;
for m in self {
total = total
.checked_add(
m.amount()
.checked_mul(
rates
.get_rate(m.code(), To::CODE)
.ok_or(MoneyError::ExchangeError(
format!(
"failed getting rate from: {} to: {}, please check the rates",
m.code(),
To::CODE
)
.into(),
))?,
)
.ok_or(MoneyError::OverflowError)?,
)
.ok_or(MoneyError::OverflowError)?;
}
M::new(total)
}
}