# Monies &emsp; [![Build Status]][travis] [![Latest Version]][crates.io] [![Docs]][docs.rs]

[Build Status]: https://travis-ci.com/apibillme/monies.svg?branch=master
[travis]: https://travis-ci.com/apibillme/monies
[Latest Version]: https://img.shields.io/crates/v/monies.svg
[crates.io]: https://crates.io/crates/monies
[Docs]: https://docs.rs/monies/badge.svg
[docs.rs]: https://docs.rs/monies

Monies handles the messy parts of dealing with money like rounding, precision, parsing and internationalization.
It supports [ISO-4217](https://en.wikipedia.org/wiki/ISO_4217) currencies, common crypto currencies and lets you
define your own. The main items exported by the library are `Money` and the `iso` and `crypto` 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:

```rust
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:

```rust
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:

 ```rust
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](https://github.com/paupino/rust-decimal), and handle values as large as
2<sup>96</sup> / 10<sup>28</sup>. Operations on Money retain the maximum possible precision. When you want less
precision, you call the `round` function, which  supports three modes:

* [Half Up](https://en.wikipedia.org/wiki/Rounding#Round_half_up)
* [Half Down](https://en.wikipedia.org/wiki/Rounding#Round_half_down)
* [Half Even](https://en.wikipedia.org/wiki/Rounding#Round_half_even) (default)

Money can be added, subtracted, multiplied and divided like this:

```rust
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.

```rust
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.

```rust
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);
```
