typed_money/lib.rs
1//! # Introduction
2//!
3//! A type-safe money library for Rust that prevents currency mixing bugs at compile time.
4//!
5//! # Features
6//!
7//! - **Type-safe** - Currency mixing prevented at compile time
8//! - **Zero-cost abstractions** - O(1) operations, no runtime overhead
9//! - **100% Safe Rust** - No unsafe code
10//! - **Deterministic** - Uses `rust_decimal` for precise arithmetic
11//! - **Comprehensive** - Full arithmetic, conversions, rounding, and formatting
12//! - **Flexible** - Optional serde support and conversion tracking
13//! - **Internationalization** - 69 currencies with locale-specific formatting
14//! - **Rich metadata** - Country, region, volatility, liquidity ratings
15//! - **Precious metals** - Gold, Silver, Platinum, Palladium, Diamond
16//! - **Base metals** - Copper, Aluminum, Zinc, Nickel
17//! - **Cryptocurrencies** - Major cryptos, stablecoins, DeFi tokens
18//!
19//! # Quick Start
20//!
21//! ```
22//! use typed_money::{Amount, USD, EUR, BTC, ETH, LTC, ADA, USDT, USDC, CAD, CNY, THB, NGN, Rate, RoundingMode};
23//!
24//! // Create amounts
25//! let price = Amount::<USD>::from_major(100); // $100.00
26//! let tax = Amount::<USD>::from_minor(850); // $8.50
27//!
28//! // Arithmetic operations
29//! let total = price + tax; // $108.50
30//! assert_eq!(total.to_minor(), 10850);
31//!
32//! // Currency conversion
33//! let rate = Rate::<USD, EUR>::new(0.85);
34//! let eur_price = price.convert(&rate); // €85.00
35//!
36//! // Cryptocurrency amounts
37//! let bitcoin = Amount::<BTC>::from_minor(100_000_000); // 1.00000000 BTC
38//! let ethereum = Amount::<ETH>::from_major(1); // 1.000000000000000000 ETH
39//! let litecoin = Amount::<LTC>::from_major(10); // 10.00000000 LTC
40//! let cardano = Amount::<ADA>::from_major(1000); // 1000.000000 ADA
41//!
42//! // Stablecoin amounts
43//! let tether = Amount::<USDT>::from_major(100); // 100.000000 USDT
44//! let usd_coin = Amount::<USDC>::from_major(50); // 50.000000 USDC
45//!
46//! // Multi-currency operations
47//! let cad_amount = Amount::<CAD>::from_major(150); // C$150.00
48//! let cny_amount = Amount::<CNY>::from_major(700); // ¥700.00
49//!
50//! // Rounding
51//! let divided = Amount::<USD>::from_major(10) / 3; // $3.333...
52//! let rounded = divided.round(RoundingMode::HalfUp); // $3.33
53//! ```
54//!
55//! # Internationalization & Metadata
56//!
57//! ```
58//! use typed_money::{Amount, USD, EUR, BRL, CurrencyMetadata};
59//!
60//! // Access rich currency metadata
61//! let usd_amount = Amount::<USD>::from_major(1234);
62//! println!("Currency: {}", usd_amount.currency_name()); // "US Dollar"
63//! println!("Country: {}", usd_amount.currency_country()); // "United States"
64//! println!("Region: {}", usd_amount.currency_region()); // "North America"
65//! println!("Type: {}", usd_amount.currency_type()); // "Fiat"
66//! println!("Volatility: {}", usd_amount.volatility_rating()); // "Low"
67//! println!("Liquidity: {}", usd_amount.liquidity_rating()); // "High"
68//!
69//! // Locale-specific formatting
70//! let eur_amount = Amount::<EUR>::from_major(1234);
71//! println!("European format: {}", eur_amount); // "€1.234,00 EUR"
72//!
73//! let brl_amount = Amount::<BRL>::from_major(1234);
74//! println!("Brazilian format: {}", brl_amount); // "R$1.234,00 BRL"
75//! ```
76//!
77//! # Precious Metals & Commodities
78//!
79//! ```
80//! use typed_money::{Amount, XAU, XAG, XPT, XPD, XDI, XCU, XAL, CurrencyMetadata};
81//!
82//! // Precious metals with 4 decimal precision
83//! let gold = Amount::<XAU>::from_major(1); // Au1.0000 XAU
84//! let silver = Amount::<XAG>::from_major(100); // Ag100.0000 XAG
85//! let platinum = Amount::<XPT>::from_major(1); // Pt1.0000 XPT
86//! let palladium = Amount::<XPD>::from_major(1); // Pd1.0000 XPD
87//! let diamond = Amount::<XDI>::from_major(1); // Di1.0000 XDI
88//!
89//! // Base metals
90//! let copper = Amount::<XCU>::from_major(1000); // Cu1000.0000 XCU
91//! let aluminum = Amount::<XAL>::from_major(1000); // Al1000.0000 XAL
92//!
93//! // Access commodity metadata
94//! println!("Gold region: {}", gold.currency_region()); // "Worldwide"
95//! println!("Gold type: {}", gold.currency_type()); // "Commodity"
96//! println!("Gold volatility: {}", gold.volatility_rating()); // "Medium"
97//! ```
98//!
99//! # Type Safety
100//!
101//! The library prevents currency mixing at compile time:
102//!
103//! ```compile_fail
104//! use typed_money::{Amount, USD, EUR};
105//!
106//! let usd = Amount::<USD>::from_major(100);
107//! let eur = Amount::<EUR>::from_major(85);
108//!
109//! // This won't compile - type mismatch!
110//! let invalid = usd + eur;
111//! ```
112//!
113//! # Supported Currencies
114//!
115//! Built-in currencies include:
116//!
117//! ## Major Fiat Currencies
118//! - **USD** - United States Dollar (2 decimals)
119//! - **EUR** - Euro (2 decimals)
120//! - **GBP** - British Pound Sterling (2 decimals)
121//! - **JPY** - Japanese Yen (0 decimals)
122//! - **CAD** - Canadian Dollar (2 decimals)
123//! - **CHF** - Swiss Franc (2 decimals)
124//! - **AUD** - Australian Dollar (2 decimals)
125//! - **NZD** - New Zealand Dollar (2 decimals)
126//!
127//! ## Asian Currencies
128//! - **CNY** - Chinese Yuan (2 decimals)
129//! - **KRW** - South Korean Won (0 decimals)
130//! - **SGD** - Singapore Dollar (2 decimals)
131//! - **HKD** - Hong Kong Dollar (2 decimals)
132//! - **TWD** - New Taiwan Dollar (2 decimals)
133//! - **INR** - Indian Rupee (2 decimals)
134//!
135//! ## European Currencies
136//! - **SEK** - Swedish Krona (2 decimals)
137//! - **NOK** - Norwegian Krone (2 decimals)
138//! - **DKK** - Danish Krone (2 decimals)
139//! - **PLN** - Polish Złoty (2 decimals)
140//! - **CZK** - Czech Koruna (2 decimals)
141//! - **HUF** - Hungarian Forint (0 decimals)
142//!
143//! ## American Currencies
144//! - **BRL** - Brazilian Real (2 decimals)
145//! - **MXN** - Mexican Peso (2 decimals)
146//! - **ARS** - Argentine Peso (2 decimals)
147//! - **CLP** - Chilean Peso (0 decimals)
148//!
149//! ## African/Middle Eastern Currencies
150//! - **ZAR** - South African Rand (2 decimals)
151//! - **EGP** - Egyptian Pound (2 decimals)
152//! - **AED** - United Arab Emirates Dirham (2 decimals)
153//! - **SAR** - Saudi Riyal (2 decimals)
154//! - **ILS** - Israeli Shekel (2 decimals)
155//! - **TRY** - Turkish Lira (2 decimals)
156//!
157//! ## Regional Currencies
158//!
159//! ### European Regional
160//! - **RON** - Romanian Leu (2 decimals)
161//! - **BGN** - Bulgarian Lev (2 decimals)
162//! - **HRK** - Croatian Kuna (2 decimals)
163//! - **RSD** - Serbian Dinar (2 decimals)
164//! - **UAH** - Ukrainian Hryvnia (2 decimals)
165//!
166//! ### Asian Regional
167//! - **THB** - Thai Baht (2 decimals)
168//! - **MYR** - Malaysian Ringgit (2 decimals)
169//! - **IDR** - Indonesian Rupiah (0 decimals)
170//! - **PHP** - Philippine Peso (2 decimals)
171//! - **VND** - Vietnamese Dong (0 decimals)
172//!
173//! ### American Regional
174//! - **COP** - Colombian Peso (2 decimals)
175//! - **PEN** - Peruvian Sol (2 decimals)
176//! - **UYU** - Uruguayan Peso (2 decimals)
177//! - **BOB** - Bolivian Boliviano (2 decimals)
178//! - **PYG** - Paraguayan Guarani (0 decimals)
179//!
180//! ### African Regional
181//! - **NGN** - Nigerian Naira (2 decimals)
182//! - **KES** - Kenyan Shilling (2 decimals)
183//! - **GHS** - Ghanaian Cedi (2 decimals)
184//! - **MAD** - Moroccan Dirham (2 decimals)
185//! - **TND** - Tunisian Dinar (3 decimals)
186//!
187//! ### Middle Eastern Regional
188//! - **QAR** - Qatari Riyal (2 decimals)
189//! - **KWD** - Kuwaiti Dinar (3 decimals)
190//! - **BHD** - Bahraini Dinar (3 decimals)
191//! - **OMR** - Omani Rial (3 decimals)
192//! - **JOD** - Jordanian Dinar (3 decimals)
193//!
194//! ## Cryptocurrencies
195//! - **BTC** - Bitcoin (8 decimals)
196//! - **ETH** - Ethereum (18 decimals)
197//!
198//! ## Precious Metals
199//! - **XAU** - Gold (4 decimals - troy ounces)
200//! - **XAG** - Silver (4 decimals - troy ounces)
201//! - **XPT** - Platinum (4 decimals - troy ounces)
202//! - **XPD** - Palladium (4 decimals - troy ounces)
203//! - **XDI** - Diamond (4 decimals - carats)
204//!
205//! ## Base Metals
206//! - **XCU** - Copper (4 decimals - metric tons)
207//! - **XAL** - Aluminum (4 decimals - metric tons)
208//! - **XZN** - Zinc (4 decimals - metric tons)
209//! - **XNI** - Nickel (4 decimals - metric tons)
210//!
211//! # Feature Flags
212//!
213//! - `use_rust_decimal` (default) - Use rust_decimal backend
214//! - `use_bigdecimal` - Use bigdecimal backend (alternative)
215//! - `serde_support` - Enable serde serialization
216//! - `conversion_tracking` - Enable conversion tracking/logging
217//!
218//! # Examples
219//!
220//! The library includes comprehensive examples demonstrating various use cases.
221//! Run any example with `cargo run --example <name>`:
222//!
223//! ### [`basic_usage`](https://github.com/ricardoferreirades/typed-money/blob/main/examples/basic_usage.rs)
224//! Fundamental operations including:
225//! - Creating amounts from major/minor units
226//! - Arithmetic operations (add, subtract, multiply, divide)
227//! - Comparisons between amounts
228//! - Working with different currencies
229//! - Real-world shopping cart example
230//!
231//! ```bash
232//! cargo run --example basic_usage
233//! ```
234//!
235//! ### [`conversions`](https://github.com/ricardoferreirades/typed-money/blob/main/examples/conversions.rs)
236//! Currency conversion examples:
237//! - Basic conversion with exchange rates
238//! - Inverse rates
239//! - Chained conversions (USD → EUR → GBP)
240//! - Rate metadata for auditability
241//! - International payment processing
242//!
243//! ```bash
244//! cargo run --example conversions
245//! ```
246//!
247//! ### [`rounding`](https://github.com/ricardoferreirades/typed-money/blob/main/examples/rounding.rs)
248//! Demonstrates all 7 rounding modes:
249//! - HalfUp, HalfDown, HalfEven (Banker's)
250//! - Up, Down, Floor, Ceiling
251//! - Edge cases with negative numbers
252//! - Tax and interest calculations
253//! - When to use each mode
254//!
255//! ```bash
256//! cargo run --example rounding
257//! ```
258//!
259//! ### [`custom_currency`](https://github.com/ricardoferreirades/typed-money/blob/main/examples/custom_currency.rs)
260//! Defining custom currencies:
261//! - Custom fiat currencies (CAD, CHF, AUD)
262//! - Cryptocurrencies (DOGE)
263//! - Game currencies (GOLD, GEMS)
264//! - Loyalty points systems
265//! - Multi-currency wallets
266//!
267//! ```bash
268//! cargo run --example custom_currency
269//! ```
270//!
271//! ### [`error_handling`](https://github.com/ricardoferreirades/typed-money/blob/main/examples/error_handling.rs)
272//! Comprehensive error handling:
273//! - Parse errors with recovery
274//! - Precision errors and normalization
275//! - Invalid rate validation
276//! - Error propagation with `?`
277//! - User input validation
278//!
279//! ```bash
280//! cargo run --example error_handling
281//! ```
282//!
283//! ### [`serialization`](https://github.com/ricardoferreirades/typed-money/blob/main/examples/serialization.rs)
284//! Serde integration (requires `serde_support` feature):
285//! - JSON serialization/deserialization
286//! - Struct serialization with amounts
287//! - Collections and multi-currency data
288//! - API response handling
289//! - Persistence examples
290//!
291//! ```bash
292//! cargo run --example serialization --features serde_support
293//! ```
294
295#![forbid(unsafe_code)]
296#![warn(missing_docs)]
297#![warn(clippy::all)]
298
299// Ensure exactly one decimal backend is enabled
300#[cfg(not(any(feature = "use_rust_decimal", feature = "use_bigdecimal")))]
301compile_error!("Either 'use_rust_decimal' or 'use_bigdecimal' feature must be enabled");
302
303#[cfg(all(feature = "use_rust_decimal", feature = "use_bigdecimal"))]
304compile_error!("Only one decimal backend can be enabled at a time");
305
306mod amount;
307mod currency;
308mod error;
309mod rate;
310mod rounding;
311
312#[cfg(feature = "conversion_tracking")]
313pub mod conversion_tracking;
314
315pub use amount::{Amount, CurrencyMetadata};
316pub use currency::{
317 // Core currencies
318 Currency,
319 // Currency metadata types
320 CurrencyType,
321 LiquidityRating,
322 SymbolPosition,
323 VolatilityRating,
324 AAVE,
325 // Major Cryptocurrencies
326 ADA,
327 AED,
328 ARS,
329 AUD,
330 BCH,
331 // European Regional Currencies
332 BGN,
333 // Middle Eastern Regional Currencies
334 BHD,
335 // American Regional Currencies
336 BOB,
337 // American Currencies
338 BRL,
339 BTC,
340 // Stablecoins
341 BUSD,
342 // Major Fiat Currencies
343 CAD,
344 CHF,
345 CLP,
346 // Asian Currencies
347 CNY,
348 // DeFi Tokens
349 COMP,
350 COP,
351 CZK,
352 DAI,
353 DKK,
354 DOT,
355 EGP,
356 ETH,
357 EUR,
358 GBP,
359 // African Regional Currencies
360 GHS,
361 HKD,
362 HRK,
363 HUF,
364 // Asian Regional Currencies
365 IDR,
366 ILS,
367 INR,
368 JOD,
369 JPY,
370 KES,
371 KRW,
372 KWD,
373 LINK,
374 LTC,
375 MAD,
376 MKR,
377 MXN,
378 MYR,
379 NGN,
380 NOK,
381 NZD,
382 OMR,
383 PEN,
384 PHP,
385 PLN,
386 PYG,
387 QAR,
388 RON,
389 RSD,
390 SAR,
391 // European Currencies
392 SEK,
393 SGD,
394 SUSHI,
395 THB,
396 TND,
397 TRY,
398 TWD,
399 UAH,
400 UNI,
401 USD,
402 USDC,
403 USDT,
404 UYU,
405 VND,
406 XAG,
407 XAL,
408 // Precious Metals
409 XAU,
410 // Base Metals
411 XCU,
412 XDI,
413 XNI,
414 XPD,
415 XPT,
416 XRP,
417 XZN,
418 YFI,
419 // African/Middle Eastern Currencies
420 ZAR,
421};
422pub use error::{MoneyError, MoneyResult};
423pub use rate::Rate;
424pub use rounding::RoundingMode;