1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
// Copyright 2016 John D. Hume
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Currency and money values for Rust, plus customizable formatting of money values and reference
//! data for real-world currencies.
//!
//! # Examples
//!
//! ```
//! use steel_cent::Money;
//! use steel_cent::currency::USD;
//! use steel_cent::formatting::{us_style, uk_style, france_style};
//!
//! let price = Money::of_major_minor(USD, 19, 95);
//! let shipping_and_handling = Money::of_major(USD, 10);
//! let convenience_charge = Money::of_major(USD, 6);
//! let fees = shipping_and_handling + convenience_charge;
//! let discount: f64 = 1.0 - 0.2; // 20% off
//! let discounted_price = price * discount;
//! let total = discounted_price + fees;
//!
//! assert_eq!(Money::of_major_minor(USD, 15, 96), discounted_price);
//! assert_eq!(Money::of_major_minor(USD, 31, 96), total);
//! assert_eq!((price * discount) + shipping_and_handling + convenience_charge, total);
//!
//! assert_eq!("total: $31.96",
//!            format!("total: {}", us_style().display_for(&total)));
//! assert_eq!("total: USD31.96",
//!            format!("total: {}", uk_style().display_for(&total)));
//! assert_eq!("total: 31,96\u{a0}USD",
//!            format!("total: {}", france_style().display_for(&total)));
//! ```
//!
//! # Money and SmallMoney
//!
//! The crate provides two representations of an amount of money in a certain currency, both of
//! which have similar implementations and feature similar behavior. They internally represent their
//! amounts as an integer of the "minor" unit of their currency. For example a US-Dollar amount is
//! stored as an integer number of cents.
//!
//! The starting point for most uses should probably be `Money`. The range of values it can
//! represent should be large enough for almost all uses.
//!
//! `SmallMoney` is only 64 bits in size, which might be nice from a performance perspective, but
//! the range of values it can represent is quite limited. See the doc tests of `min` and `max`
//! for details.

#[macro_use]
extern crate lazy_static;

pub mod currency;
pub mod formatting;
mod base26;

// Borrowed w/ modifications from https://doc.rust-lang.org/src/core/up/src/libcore/ops.rs.html
// implements binary operators "&T op U", "T op &U", "&T op &U"
// based on "T op U" where T and U are expected to be `Copy`able
macro_rules! forward_ref_binop {
    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
        impl<'a> $imp<$u> for &'a $t {
            type Output = <$t as $imp<$u>>::Output;
            fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(*self, other)
            }
        }
        impl<'a> $imp<&'a $u> for $t {
            type Output = <$t as $imp<$u>>::Output;
            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(self, *other)
            }
        }
        impl<'a, 'b> $imp<&'a $u> for &'b $t {
            type Output = <$t as $imp<$u>>::Output;
            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(*self, *other)
            }
        }
    }
}

mod money;
mod small_money;

pub use currency::Currency;
pub use money::Money;
pub use small_money::SmallMoney;

/// Converts a `SmallMoney` to a `Money`.
///
/// ```
/// # use steel_cent::SmallMoney;
/// # use steel_cent::Money;
/// # use steel_cent::currency::*;
/// assert_eq!(Money::of_major(USD, 2),
///            Money::from(SmallMoney::of_major(USD, 2)));
/// ```
impl From<SmallMoney> for Money {
    fn from(small: SmallMoney) -> Self {
        Money::of_minor(small.currency, small.minor_amount() as i64)
    }
}