monet 0.1.1

Handle currency conversion and common operations (additions, ...)
Documentation
# Monet

[![Build Status](https://github.com/AxelMontini/monet/workflows/Rust/badge.svg)](https://github.com/AxelMontini/monet/actions)
[![MPL-2.0 Licensed](https://img.shields.io/crates/l/monet/0.1.0)](./LICENSE)
[![Crates.io](https://img.shields.io/crates/v/monet)](https://crates.io/crates/monet)
[![Docs](https://docs.rs/monet/badge.svg)](https://docs.rs/crate/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

```rust

use monet::{Money, CurrencyAmount, Rates, Operation};
use std::convert::TryInto;

// Custom rates.
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

```rust

use monet::{Money, CurrencyAmount, Rates, Operation};
use std::convert::TryInto;

// Custom rates.
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();

// Note: sum has currency code "CHF": when summing,
// the currency code of the first money is used
let sum = (money_one + money_two).execute(&rates);

assert_eq!(remaining, Money::with_str_code(2_000_000.into(), "CHF"));

```

### Chaining operations

```rust

use monet::{Money, CurrencyAmount, Rates, Operation};
use std::convert::TryInto;

// Custom rates.
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();

// Note: sum has currency code "CHF"
let sum = (money_one + money_two - money_three).execute(&rates);

assert_eq!(remaining, Money::with_str_code(0.into(), "CHF"));

```