# 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")); ```