Skip to content

Commit

Permalink
Make Currency owned (varunsrin#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
alopatindev committed Aug 19, 2023
1 parent bbc0150 commit b75382b
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 60 deletions.
4 changes: 2 additions & 2 deletions src/currency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ macro_rules! define_currency_set {
}

$(
pub const $currency: &'static self::Currency = &self::Currency {
pub const $currency: self::Currency = self::Currency {
code: $code,
exponent: $exp,
locale: $loc,
Expand All @@ -101,7 +101,7 @@ macro_rules! define_currency_set {
};
)+

pub fn find(code: &str) -> Option<&'static self::Currency> {
pub fn find(code: &str) -> Option<self::Currency> {
match code {
$($code => (Some($currency)),)+
_ => None,
Expand Down
6 changes: 3 additions & 3 deletions src/currency/iso_currencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub mod iso {
),+
) => {
$(
pub const $currency: &'static Currency = &Currency {
pub const $currency: Currency = Currency {
iso_alpha_code: $alpha_code,
iso_numeric_code: $num_code,
exponent: $exp,
Expand All @@ -76,14 +76,14 @@ pub mod iso {
};
)+

pub fn find(code: &str) -> Option<&'static Currency> {
pub fn find(code: &str) -> Option<Currency> {
match code {
$($alpha_code => (Some($currency)),)+
_ => None,
}
}

pub fn find_by_num_code(code: &str) -> Option<&'static Currency> {
pub fn find_by_num_code(code: &str) -> Option<Currency> {
match code {
$($num_code => (Some($currency)),)+
_ => None,
Expand Down
26 changes: 13 additions & 13 deletions src/exchange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,52 @@ use std::collections::HashMap;

/// Stores `ExchangeRate`s for easier access.
#[derive(Debug, Default)]
pub struct Exchange<'a, T: FormattableCurrency> {
map: HashMap<String, ExchangeRate<'a, T>>,
pub struct Exchange<T: FormattableCurrency> {
map: HashMap<String, ExchangeRate<T>>,
}

impl<'a, T: FormattableCurrency> Exchange<'a, T> {
pub fn new() -> Exchange<'a, T> {
impl<T: FormattableCurrency> Exchange<T> {
pub fn new() -> Exchange<T> {
Exchange {
map: HashMap::new(),
}
}

/// Update an ExchangeRate or add it if does not exist.
pub fn set_rate(&mut self, rate: &ExchangeRate<'a, T>) {
pub fn set_rate(&mut self, rate: &ExchangeRate<T>) {
let key = Exchange::generate_key(rate.from, rate.to);
self.map.insert(key, *rate);
}

/// Return the ExchangeRate given the currency pair.
pub fn get_rate(&self, from: &T, to: &T) -> Option<ExchangeRate<'a, T>> {
pub fn get_rate(&self, from: T, to: T) -> Option<ExchangeRate<T>> {
let key = Exchange::generate_key(from, to);
self.map.get(&key).copied()
}

fn generate_key(from: &T, to: &T) -> String {
fn generate_key(from: T, to: T) -> String {
from.to_string() + "-" + &to.to_string()
}
}

/// Stores rates of conversion between two currencies.
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct ExchangeRate<'a, T: FormattableCurrency> {
pub from: &'a T,
pub to: &'a T,
pub struct ExchangeRate<T: FormattableCurrency> {
pub from: T,
pub to: T,
rate: Decimal,
}

impl<'a, T: FormattableCurrency> ExchangeRate<'a, T> {
pub fn new(from: &'a T, to: &'a T, rate: Decimal) -> Result<ExchangeRate<'a, T>, MoneyError> {
impl<T: FormattableCurrency> ExchangeRate<T> {
pub fn new(from: T, to: T, rate: Decimal) -> Result<ExchangeRate<T>, MoneyError> {
if from == to {
return Err(MoneyError::InvalidCurrency);
}
Ok(ExchangeRate { from, to, rate })
}

/// Converts a Money from one Currency to another using the exchange rate.
pub fn convert(&self, amount: &Money<'a, T>) -> Result<Money<'a, T>, MoneyError> {
pub fn convert(&self, amount: &Money<T>) -> Result<Money<T>, MoneyError> {
if amount.currency() != self.from {
return Err(MoneyError::InvalidCurrency);
}
Expand Down
2 changes: 1 addition & 1 deletion src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub struct Formatter;

impl<'a> Formatter {
/// Returns a formatted Money String given parameters and a Money object.
pub fn money<T: FormattableCurrency>(money: &Money<'a, T>, params: Params) -> String {
pub fn money<T: FormattableCurrency>(money: &Money<T>, params: Params) -> String {
let mut decimal = *money.amount();

// Round the decimal
Expand Down
82 changes: 41 additions & 41 deletions src/money.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ use rust_decimal::Decimal;
/// Operations on Money objects always create new instances of Money, with the exception
/// of `round()`.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Money<'a, T: FormattableCurrency> {
pub struct Money<T: FormattableCurrency> {
amount: Decimal,
currency: &'a T,
currency: T,
}

impl<'a, T: FormattableCurrency> Add for Money<'a, T> {
type Output = Money<'a, T>;
fn add(self, other: Money<'a, T>) -> Money<'a, T> {
impl<T: FormattableCurrency> Add for Money<T> {
type Output = Money<T>;
fn add(self, other: Money<T>) -> Money<T> {
if self.currency != other.currency {
panic!();
}
Money::from_decimal(self.amount + other.amount, self.currency)
}
}

impl<'a, T: FormattableCurrency> AddAssign for Money<'a, T> {
impl<T: FormattableCurrency> AddAssign for Money<T> {
fn add_assign(&mut self, other: Self) {
if self.currency != other.currency {
panic!();
Expand All @@ -43,17 +43,17 @@ impl<'a, T: FormattableCurrency> AddAssign for Money<'a, T> {
}
}

impl<'a, T: FormattableCurrency> Sub for Money<'a, T> {
type Output = Money<'a, T>;
fn sub(self, other: Money<'a, T>) -> Money<'a, T> {
impl<T: FormattableCurrency> Sub for Money<T> {
type Output = Money<T>;
fn sub(self, other: Money<T>) -> Money<T> {
if self.currency != other.currency {
panic!();
}
Money::from_decimal(self.amount - other.amount, self.currency)
}
}

impl<'a, T: FormattableCurrency> SubAssign for Money<'a, T> {
impl<T: FormattableCurrency> SubAssign for Money<T> {
fn sub_assign(&mut self, other: Self) {
if self.currency != other.currency {
panic!();
Expand All @@ -66,8 +66,8 @@ impl<'a, T: FormattableCurrency> SubAssign for Money<'a, T> {
}
}

impl<'a, T: FormattableCurrency> Neg for Money<'a, T> {
type Output = Money<'a, T>;
impl<T: FormattableCurrency> Neg for Money<T> {
type Output = Money<T>;

fn neg(self) -> Self::Output {
Money {
Expand All @@ -79,25 +79,25 @@ impl<'a, T: FormattableCurrency> Neg for Money<'a, T> {

macro_rules! impl_mul_div {
($type:ty) => {
impl<'a, T: FormattableCurrency> Mul<$type> for Money<'a, T> {
type Output = Money<'a, T>;
impl<T: FormattableCurrency> Mul<$type> for Money<T> {
type Output = Money<T>;

fn mul(self, rhs: $type) -> Money<'a, T> {
fn mul(self, rhs: $type) -> Money<T> {
let rhs = Decimal::from_str(&rhs.to_string()).unwrap();
Money::from_decimal(self.amount * rhs, self.currency)
}
}

impl<'a, T: FormattableCurrency> Mul<Money<'a, T>> for $type {
type Output = Money<'a, T>;
impl<T: FormattableCurrency> Mul<Money<T>> for $type {
type Output = Money<T>;

fn mul(self, rhs: Money<'a, T>) -> Money<'a, T> {
fn mul(self, rhs: Money<T>) -> Money<T> {
let lhs = Decimal::from_str(&self.to_string()).unwrap();
Money::from_decimal(rhs.amount * lhs, rhs.currency)
}
}

impl<'a, T: FormattableCurrency> MulAssign<$type> for Money<'a, T> {
impl<T: FormattableCurrency> MulAssign<$type> for Money<T> {
fn mul_assign(&mut self, rhs: $type) {
*self = Self {
amount: self.amount * Decimal::from(rhs),
Expand All @@ -106,25 +106,25 @@ macro_rules! impl_mul_div {
}
}

impl<'a, T: FormattableCurrency> Div<$type> for Money<'a, T> {
type Output = Money<'a, T>;
impl<T: FormattableCurrency> Div<$type> for Money<T> {
type Output = Money<T>;

fn div(self, rhs: $type) -> Money<'a, T> {
fn div(self, rhs: $type) -> Money<T> {
let rhs = Decimal::from_str(&rhs.to_string()).unwrap();
Money::from_decimal(self.amount / rhs, self.currency)
}
}

impl<'a, T: FormattableCurrency> Div<Money<'a, T>> for $type {
type Output = Money<'a, T>;
impl<T: FormattableCurrency> Div<Money<T>> for $type {
type Output = Money<T>;

fn div(self, rhs: Money<'a, T>) -> Money<'a, T> {
fn div(self, rhs: Money<T>) -> Money<T> {
let lhs = Decimal::from_str(&self.to_string()).unwrap();
Money::from_decimal(lhs / rhs.amount, rhs.currency)
}
}

impl<'a, T: FormattableCurrency> DivAssign<$type> for Money<'a, T> {
impl<T: FormattableCurrency> DivAssign<$type> for Money<T> {
fn div_assign(&mut self, rhs: $type) {
*self = Self {
amount: self.amount / Decimal::from(rhs),
Expand All @@ -147,26 +147,26 @@ impl_mul_div!(u32);
impl_mul_div!(u64);
impl_mul_div!(Decimal);

impl<'a, T: FormattableCurrency> PartialOrd for Money<'a, T> {
fn partial_cmp(&self, other: &Money<'a, T>) -> Option<Ordering> {
impl<T: FormattableCurrency> PartialOrd for Money<T> {
fn partial_cmp(&self, other: &Money<T>) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl<'a, T: FormattableCurrency> Ord for Money<'a, T> {
fn cmp(&self, other: &Money<'a, T>) -> Ordering {
impl<T: FormattableCurrency> Ord for Money<T> {
fn cmp(&self, other: &Money<T>) -> Ordering {
if self.currency != other.currency {
panic!();
}
self.amount.cmp(&other.amount)
}
}

impl<'a, T: FormattableCurrency> Money<'a, T> {
impl<T: FormattableCurrency> Money<T> {
/// Creates a Money object given an amount string and a currency str.
///
/// Supports fuzzy amount strings like "100", "100.00" and "-100.00"
pub fn from_str(amount: &str, currency: &'a T) -> Result<Money<'a, T>, MoneyError> {
pub fn from_str(amount: &str, currency: T) -> Result<Money<T>, MoneyError> {
let format = LocalFormat::from_locale(currency.locale());
let amount_parts: Vec<&str> = amount.split(format.exponent_separator).collect();

Expand Down Expand Up @@ -203,21 +203,21 @@ impl<'a, T: FormattableCurrency> Money<'a, T> {
/// Creates a Money object given an integer and a currency reference.
///
/// The integer represents minor units of the currency (e.g. 1000 -> 10.00 in USD )
pub fn from_minor(amount: i64, currency: &'a T) -> Money<'a, T> {
pub fn from_minor(amount: i64, currency: T) -> Money<T> {
let amount = Decimal::new(amount, currency.exponent());
Money { amount, currency }
}

/// Creates a Money object given an integer and a currency reference.
///
/// The integer represents major units of the currency (e.g. 1000 -> 1,000 in USD )
pub fn from_major(amount: i64, currency: &'a T) -> Money<'a, T> {
pub fn from_major(amount: i64, currency: T) -> Money<T> {
let amount = Decimal::new(amount, 0);
Money { amount, currency }
}

/// Creates a Money object given a decimal amount and a currency reference.
pub fn from_decimal(amount: Decimal, currency: &'a T) -> Money<'a, T> {
pub fn from_decimal(amount: Decimal, currency: T) -> Money<T> {
Money { amount, currency }
}

Expand All @@ -227,7 +227,7 @@ impl<'a, T: FormattableCurrency> Money<'a, T> {
}

/// Returns the Currency type.
pub fn currency(&self) -> &'a T {
pub fn currency(&self) -> T {
self.currency
}

Expand All @@ -250,7 +250,7 @@ impl<'a, T: FormattableCurrency> Money<'a, T> {
///
/// If the division cannot be applied perfectly, it allocates the remainder
/// to some of the shares.
pub fn allocate_to(&self, number: i32) -> Result<Vec<Money<'a, T>>, MoneyError> {
pub fn allocate_to(&self, number: i32) -> Result<Vec<Money<T>>, MoneyError> {
let ratios: Vec<i32> = (0..number).map(|_| 1).collect();
self.allocate(ratios)
}
Expand All @@ -259,7 +259,7 @@ impl<'a, T: FormattableCurrency> Money<'a, T> {
///
/// If the division cannot be applied perfectly, it allocates the remainder
/// to some of the shares.
pub fn allocate(&self, ratios: Vec<i32>) -> Result<Vec<Money<'a, T>>, MoneyError> {
pub fn allocate(&self, ratios: Vec<i32>) -> Result<Vec<Money<T>>, MoneyError> {
if ratios.is_empty() {
return Err(MoneyError::InvalidRatio);
}
Expand All @@ -272,7 +272,7 @@ impl<'a, T: FormattableCurrency> Money<'a, T> {
let mut remainder = self.amount;
let ratio_total: Decimal = ratios.iter().fold(Decimal::ZERO, |acc, x| acc + x);

let mut allocations: Vec<Money<'a, T>> = Vec::new();
let mut allocations: Vec<Money<T>> = Vec::new();

for ratio in ratios {
if ratio <= Decimal::ZERO {
Expand Down Expand Up @@ -303,7 +303,7 @@ impl<'a, T: FormattableCurrency> Money<'a, T> {
}

/// Returns a `Money` rounded to the specified number of minor units using the rounding strategy.
pub fn round(&self, digits: u32, strategy: Round) -> Money<'a, T> {
pub fn round(&self, digits: u32, strategy: Round) -> Money<T> {
let mut money = *self;

money.amount = match strategy {
Expand Down Expand Up @@ -333,7 +333,7 @@ pub enum Round {
HalfEven,
}

impl<'a, T: FormattableCurrency + FormattableCurrency> fmt::Display for Money<'a, T> {
impl<T: FormattableCurrency + FormattableCurrency> fmt::Display for Money<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let currency = self.currency;
let format = LocalFormat::from_locale(currency.locale());
Expand Down

0 comments on commit b75382b

Please sign in to comment.