moneylib/macros.rs
1/// Creates a [`Money`](crate::Money) instance using a currency type and a decimal amount.
2///
3/// **Short form (ISO currencies):** pass a bare ISO 4217 currency code — it is resolved from
4/// [`crate::iso`] automatically, so no separate `use` import is required.
5///
6/// **Long form (custom currencies):** pass any path that resolves to a type implementing
7/// [`Currency`](crate::Currency). The path is used directly, so the type must be in scope.
8///
9/// The amount is parsed as a decimal string at initialization time and then wrapped in a [`Money`](crate::Money) value,
10/// applying the currency's rounding rules.
11///
12/// # Examples
13///
14/// ```
15/// use moneylib::{BaseMoney, macros::{dec, money}};
16///
17/// // Short form: no `use moneylib::iso::USD;` needed
18/// let m = money!(USD, 40.237);
19/// assert_eq!(m.amount(), dec!(40.24)); // rounded to 2 decimal places for USD
20///
21/// // Negative amounts
22/// let m = money!(USD, -10.005);
23/// assert_eq!(m.amount(), dec!(-10.00)); // banker's rounding
24/// ```
25///
26/// ```
27/// use moneylib::{BaseMoney, Currency, macros::{dec, money}, iso::USD};
28///
29/// // Long form: path to a custom currency type (must be in scope)
30/// let m = money!(USD, 100.00);
31/// assert_eq!(m.amount(), dec!(100.00));
32/// ```
33#[macro_export]
34macro_rules! money {
35 // Short form: bare ISO currency identifier, auto-resolved from crate::iso
36 ($currency:ident, $($amount:tt)+) => {
37 $crate::Money::<$crate::iso::$currency>::from_decimal($crate::dec!($($amount)+))
38 };
39 // Long form: explicit path for custom currency types (must be in scope)
40 ($currency:path, $($amount:tt)+) => {
41 $crate::Money::<$currency>::from_decimal($crate::dec!($($amount)+))
42 };
43}
44
45/// Creates a [`RawMoney`](crate::RawMoney) instance using a currency type and a decimal amount.
46///
47/// **Short form (ISO currencies):** pass a bare ISO 4217 currency code — it is resolved from
48/// [`crate::iso`] automatically, so no separate `use` import is required.
49///
50/// **Long form (custom currencies):** pass any path that resolves to a type implementing
51/// [`Currency`](crate::Currency). The path is used directly, so the type must be in scope.
52///
53/// The amount is parsed as a decimal string at initialization time without any rounding, preserving
54/// the full decimal precision.
55///
56/// # Examples
57///
58/// ```
59/// use moneylib::{BaseMoney, macros::{dec, raw}};
60///
61/// // Short form: no `use moneylib::iso::USD;` needed
62/// let m = raw!(USD, 40.237);
63/// assert_eq!(m.amount(), dec!(40.237));
64///
65/// // Negative amounts
66/// let m = raw!(USD, -10.005);
67/// assert_eq!(m.amount(), dec!(-10.005));
68/// ```
69///
70/// ```
71/// use moneylib::{BaseMoney, Currency, macros::{dec, raw}, iso::USD};
72///
73/// // Long form: path to a custom currency type (must be in scope)
74/// let m = raw!(USD, 100.123);
75/// assert_eq!(m.amount(), dec!(100.123));
76/// ```
77#[cfg(feature = "raw_money")]
78#[macro_export]
79macro_rules! raw {
80 // Short form: bare ISO currency identifier, auto-resolved from crate::iso
81 ($currency:ident, $($amount:tt)+) => {
82 $crate::RawMoney::<$crate::iso::$currency>::from_decimal($crate::dec!($($amount)+))
83 };
84 // Long form: explicit path for custom currency types (must be in scope)
85 ($currency:path, $($amount:tt)+) => {
86 $crate::RawMoney::<$currency>::from_decimal($crate::dec!($($amount)+))
87 };
88}
89
90/// Re-export of [`rust_decimal_macros::dec`] with the `reexportable` feature enabled.
91///
92/// This is an implementation detail used by the `dec!` macro to emit compile-time
93/// `Decimal` construction without leaking `::rust_decimal` paths into the caller's crate.
94///
95/// This is so that users are not required to import rust_decimal or putting Decimal in scope.
96#[doc(hidden)]
97pub use rust_decimal_macros::dec as __dec_inner;
98
99/// Creates a [`Decimal`](crate::Decimal) value from a numeric literal.
100///
101/// This is a compile-time checked macro — invalid literals produce a compile error, not a panic.
102/// `rust_decimal` does not need to be a direct dependency of the caller's crate.
103///
104/// From [`rust_decimal_macros`](https://docs.rs/rust_decimal_macros/1.40.0/rust_decimal_macros/macro.dec.html):
105///
106/// Any Rust number format works, for example:
107///
108/// ```
109/// use moneylib::dec;
110///
111/// let _ = dec!(1); // plain positive integer
112/// let _ = dec!(-1); // plain negative integer
113/// let _ = dec!(1_999); // underscore as digit separator (readability)
114/// let _ = dec!(- 1_999); // negative with space before value
115///
116/// let _ = dec!(0b1); // binary literal (base 2)
117/// let _ = dec!(-0b1_1111); // negative binary with separator (= -31)
118/// let _ = dec!(0o1); // octal literal (base 8)
119/// let _ = dec!(-0o1_777); // negative octal with separator (= -1023)
120/// let _ = dec!(0x1); // hexadecimal literal (base 16)
121/// let _ = dec!(-0x1_Ffff); // negative hex with separator, mixed case digits (= -131071)
122///
123/// let _ = dec!(1.); // decimal point with no fractional digits
124/// let _ = dec!(-1.111_009); // negative decimal with underscore separator in fraction
125/// let _ = dec!(1e6); // scientific notation: 1 × 10⁶ = 1_000_000
126/// let _ = dec!(-1.2e+6); // negative scientific notation with explicit '+' exponent
127/// let _ = dec!(12e-6); // scientific notation with negative exponent: 0.000_012
128/// let _ = dec!(-1.2e-6); // negative value with negative exponent: -0.000_001_2
129/// ```
130///
131/// ### Option `radix`
132///
133/// You can give it integers (not float-like) in any radix from 2 to 36 inclusive, using the letters too:
134///
135/// ```
136/// use moneylib::dec;
137///
138/// assert_eq!(dec!(100, radix 2), dec!(4)); // "100" in base 2 = 1×4 = 4
139/// assert_eq!(dec!(-1_222, radix 3), dec!(-53)); // "1222" in base 3 = 27+18+6+2 = 53
140/// assert_eq!(dec!(z1, radix 36), dec!(1261)); // "z1" in base 36 = 35×36+1 = 1261
141/// assert_eq!(dec!(-1_xyz, radix 36), dec!(-90683)); // "1xyz" in base 36, letters count as digit values 10–35
142/// ```
143///
144/// ### Option `exp`
145///
146/// This is the same as the `e` 10's exponent in float syntax (except as a Rust expression it doesn't accept
147/// a unary `+`.) You need this for other radixes. Currently, it must be between -28 and +28 inclusive:
148///
149/// ```
150/// use moneylib::dec;
151///
152/// assert_eq!(dec!(10, radix 2, exp 5), dec!(200_000)); // "10" in base 2 = 2, then ×10⁵ = 200_000
153/// assert_eq!(dec!(-1_777, exp -3, radix 8), dec!(-1.023)); // "1777" in base 8 = 1023, then ×10⁻³ = -1.023
154/// ```
155///
156/// # Examples
157///
158/// ```
159/// use moneylib::macros::dec;
160///
161/// let d = dec!(2.51);
162/// assert_eq!(d.to_string(), "2.51");
163/// ```
164#[macro_export]
165macro_rules! dec {
166 ($($amount:tt)+) => {
167 {
168 use $crate::Decimal;
169 $crate::macros::__dec_inner!($($amount)+)
170 }
171 };
172}
173
174pub use crate::money;
175
176#[cfg(feature = "raw_money")]
177pub use crate::raw;
178
179pub use crate::dec;