Expand description
§Oxydized Money 💵 ↔ 💶
This crate aims at providing data types to manipulate amounts of money in specific currencies, convert amounts between currencies and make sure that any computation is performed on amounts of the same currency.
§Motivations
This crate was introduced because all the existing known alternatives have some signigicant drawbacks:
- using native floating point type like
f32orf64suffer from their lack of precision. - using
rust_decimal::Decimalsolves this issue but does not prevent from adding amounts in different currency. - using
rusty_money::Money, although slightly better, does not really solve the conversion issue because performing arithmetic operations on amounts of different currencies panics.
Rust being dedicated to proper error handling, all these options feel like compromises. This crate aims to improve this by providing three distinct data types:
Amountfor storing amounts in a given currency.CurrencyErrorfor representing any errors (currency mismatch, …) during arithmetic operations onAmounts.AmountResultfor storing the result of arithmetic operations (either anAmountorCurrencyError).
Arithmetic operations are defined in such a way that these three types
inte-roperate almost seemlessly. However, when performing an operation,
the type of output always reflect whether an error could have occured.
Operation that cannot fail will output Amounts and operations that
can fail will outout AmountResults. Before getting at the underlying
Amount, AmountResults need to be properly checked for errors.
No more 🦶-guns
§Examples
use oxydized_money_macros::{eur, usd, dec};
use oxydized_money::{
Currency::{EUR,USD},
CurrencyError,
Decimal,
};
// Amount(USD)
let capital = usd!(10_000);
// Decimal
let exchange_rate = dec!(0.928);
// Amount(EUR)
let converted = capital.converted_to(EUR, exchange_rate);
// Amount(EUR)
let fees = eur!(15.2);
// Amount(EUR) + Amount(EUR) => AmountResult(EUR)
let subtotal = converted + fees;
// Amount(EUR) * Decimal => Amount(EUR)
let extras = eur!(50) * dec!(2);
// AmountResult(EUR) + Amount(EUR) => AmountResult(EUR)
let total = subtotal + extras;
// Comparing AmountResult with Amounts
assert_eq!(total, eur!(9_395.200));
// AmountResult(EUR) + Amount(USD) => AmountResult(Mismatch(EUR,USD))
let oops = total + usd!(20);
// Comparing AmountResult with CurrencyError
assert_eq!(oops, CurrencyError::Mismatch(EUR,USD));
// AmountResult(Mismatch(EUR,USD)) + Amount(USD) => AmountResult(Mismatch(EUR,USD))
let oh_my = oops + usd!(200);
assert_eq!(oh_my, CurrencyError::Mismatch(EUR,USD));
// "Everything, everywhere, all at once."
assert_eq!(
usd!(10_000).converted_to(EUR, dec!(0.928)) + eur!(15.2) + eur!(50)*dec!(2),
eur!(9_395.200)
);§Supported Operations
§Binary Operations
§Amount
| Left Operand | Operator | Right Operand | Output |
|---|---|---|---|
Amount | * | Decimal | Amount |
Amount | / | Decimal | AmountResult |
Amount | {+,-} | Amount | AmountResult |
Amount | {+,-} | AmountResult | AmountResult |
Amount | {==,!=} | Amount | bool |
Amount | {==,!=} | AmountResult | bool |
Amount | {<,>,>=,<= } | Amount | bool |
§AmountResult
| Left Operand | Operator | Right Operand | Output |
|---|---|---|---|
AmountResult | * | Decimal | AmountResult |
AmountResult | / | Decimal | AmountResult |
AmountResult | {+,-} | Amount | AmountResult |
AmountResult | {+,-} | AmountResult | AmountResult |
AmountResult | {==,!=} | Amount | bool |
AmountResult | {==,!=} | AmountResult | bool |
AmountResult | {==,!=} | CurrencyError | bool |
§CurrencyError
| Left Operand | Operator | Right Operand | Output |
|---|---|---|---|
CurrencyError | {==,!=} | AmountResult | bool |
CurrencyError | {==,!=} | CurrencyError | bool |
§Unary Operations
§Amount
| Operator | Operand | Output |
|---|---|---|
- | Amount | Amount |
§AmountResult
| Operator | Operand | Output |
|---|---|---|
- | AmountResult | AmountResult |
Structs§
- Amount
Amountrepresents an amount of money in a specific currency. The quantity part is stored as a 128-bit fixed precisionDecimal. The currency part is stored as aCurrency.- Amount
Result AmountResultrepresents the result of a computation involving amounts of money. It can therefore either be anAmountif the computation was successful, or aCurrencyErrorif the computation was not successful.- Decimal
Decimalrepresents a 128 bit representation of a fixed-precision decimal number. The finite set of values of typeDecimalare of the form m / 10e, where m is an integer such that -296 < m < 296, and e is an integer between 0 and 28 inclusive.
Enums§
- Currency
- Currency
Error CurrencyErrorrepresents all currency error that can occur during arithmetic operations withAmountorAmounrResult.
Type Aliases§
- Result
- Type alias for a
Resultwhere the error isCurrencyError