4 releases
0.0.4 | Feb 9, 2021 |
---|---|
0.0.3 | Jan 31, 2021 |
0.0.2 | Jan 31, 2021 |
0.0.1 | Jan 30, 2021 |
#114 in Finance
115KB
3K
SLoC
Monies
Monies handles the messy parts of dealing with money like rounding, precision, parsing and internationalization.
It supports ISO-4217 currencies, common crypto currencies and lets you
define your own. The main items exported by the library are Money
and the iso
currency sets.
Usage
A Money
object is created by supplying an amount and a currency. Amounts can be specified in numeric or string types
but will be stored as precise decimals internally. You can select a bundled currency or make your own. Here's a
quick example of how you would make your own Currency
and then create some Money
with it:
use Monies::{Money, define_currency_set};
define_currency_set!(
video_game {
GIL: {
code: "GIL",
exponent: 2,
locale: Locale::EnUs,
minor_units: 100,
name: "GIL",
symbol: "G",
symbol_first: true,
}
}
);
Money::from_major(2_000, video_game::GIL); // 2000 GIL
Money::from_minor(200_000, video_game::GIL); // 2000 GIL
Money::from_str("2,000.00", video_game::GIL).unwrap(); // 2000 GIL
// Currencies can be looked up by code.
let gil = video_game::find("GIL").unwrap();
Money::from_major(2_000, gil); // 2000 GIL
The currency sets can then be used like this:
use Monies::{Money, iso};
Money::from_major(2_000, iso::USD); // 2000 U.S Dollars
Money::from_major(2_000, iso::GBP); // 2000 British Pounds
Money::from_major(2, crypto::BTC); // 2 Bitcoin
Money objects of the same currency can be compared:
use Monies::{Money, iso};
let hundred = Money::from_minor(10_000, iso::USD);
let thousand = Money::from_minor(100_000, iso::USD);
println!("{}", thousand > hundred); // false
println!("{}", thousand.is_positive()); // true
Precision, Rounding and Math
Money objects are immutable, and operations that change amounts create a new instance of Money. Amounts are stored
as 128 bit fixed-precision Decimals, and handle values as large as
296 / 1028. Operations on Money retain the maximum possible precision. When you want less
precision, you call the round
function, which supports three modes:
Money can be added, subtracted, multiplied and divided like this:
use Monies::{Money, Round, iso};
Money::from_minor(100, iso::USD) + Money::from_minor(100, iso::USD); // 2 USD
Money::from_minor(100, iso::USD) - Money::from_minor(100, iso::USD); // 0 USD
Money::from_minor(100, iso::USD) * 3; // 3 USD
Money::from_minor(100, iso::USD) / 3; // 0.333... USD
let usd = Money::from_str("-2000.005", iso::USD).unwrap(); // 2000.005 USD
usd.round(2, Round::HalfEven); // 2000.00 USD
usd.round(2, Round::HalfUp); // 2000.01 USD
usd.round(0, Round::HalfUp); // 2000 USD
Formatting
Calling format!
or println!
on Money returns a string with a rounded amount, using separators and symbols
according to the locale of the currency. If you need to customize this output, the Formatter
module
accepts a more detailed set of parameters.
use Monies::{Money, iso};
let usd = Money::from_str("-2000.009", iso::USD).unwrap();
let eur = Money::from_str("-2000.009", iso::EUR).unwrap();
println!("{}", usd); // -$2,000.01
println!("{}", eur); // -€2.000,01;
Exchange
The library also provides two additional types - Exchange
and ExchangeRates
to convert Money from one currency
to another.
use Monies::{Money, Exchange, ExchangeRate, iso};
use rust_decimal_macros::*;
// Convert 1000 USD to EUR at a 2:1 exchange rate.
let rate = ExchangeRate::new(iso::USD, iso::EUR, dec!(0.5)).unwrap();
rate.convert(Money::from_minor(100_000, iso::USD)); // 500 EUR
// An Exchange can be used to store ExchangeRates for later use
let mut exchange = Exchange::new();
exchange.set_rate(&rate);
exchange.get_rate(iso::USD, iso::EUR);
Dependencies
~0.9–1.5MB
~32K SLoC