Monet
Handle currency conversion and common operations (addition, subtraction, multiplication, division).
How it works
It defines some base types:
CurrencyAmount
is i128
and, as the name says, is used to store amounts.
CurrencyCode
is a wrapper for [u8; 3]
that can be created from / converted into &str
s.
Money
is the most important type. Money holds both a currency_code
and an amount
. It's used
to store money and to perform operations. It can be converted into another currency code by providing
Rates
.
Rates
is a wrapper for a HashMap
. It can be constructed from such pre-defined map or populated from
an external source such as websites (Not yet, TODO: Implement).
Exponent
exists because there are no float
s involved here. It has two fields: amount
and exponent
. Its decimal value is amount / (10).pow(exponent)
.
Dangers
Even this library isn't safe from precision losses. For example, an Exponent
's amount could be cut out by its exponent. Also errors when converting money could occurr.
Examples
Summing two Money
s of the same type
use monet::{Money, CurrencyAmount, Rates, Operation};
use std::convert::TryInto;
let map = vec![("USD", 1_000_000)].into_iter()
.map(|(code, worth)| (code.try_into().unwrap(), worth.into())
.collect();
let rates = Rates::with_rates(map);
let money_owned = Money::with_str_code(CurrencyAmount::with_unit(2), "USD").unwrap();
let money_paid = Money::with_str_code(CurrencyAmount::with_unit(1), "USD").unwrap();
let remaining = (money_owned - money_paid).execute(&rates);
assert_eq!(remaining, Money::with_str_code(CurrencyAmount::with_unit(1), "USD"));
assert_eq!(remaining, Money::with_str_code(1_000_000.into(), "USD"));
Summing two Money
s of different type
use monet::{Money, CurrencyAmount, Rates, Operation};
use std::convert::TryInto;
let map = vec![
("USD", 1_000_000),
("CHF", 1_100_000),
].into_iter()
.map(|(code, worth)| (code.try_into().unwrap(), worth.into())
.collect();
let rates = Rates::with_rates(map);
let money_one = Money::with_str_code(1_000_000.into(), "CHF").unwrap();
let money_two = Money::with_str_code(1_100_000.into(), "USD").unwrap();
let sum = (money_one + money_two).execute(&rates);
assert_eq!(remaining, Money::with_str_code(2_000_000.into(), "CHF"));
Chaining operations
use monet::{Money, CurrencyAmount, Rates, Operation};
use std::convert::TryInto;
let map = vec![
("USD", 1_000_000),
("CHF", 1_100_000),
].into_iter()
.map(|(code, worth)| (code.try_into().unwrap(), worth.into())
.collect();
let rates = Rates::with_rates(map);
let money_one = Money::with_str_code(1_000_000.into(), "CHF").unwrap();
let money_two = Money::with_str_code(1_100_000.into(), "USD").unwrap();
let money_three = Money::with_str_code(2_000_000.into(), "CHF").unwrap();
let sum = (money_one + money_two - money_three).execute(&rates);
assert_eq!(remaining, Money::with_str_code(0.into(), "CHF"));