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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! # Finmoney
//!
//! A precise money library for Rust. Provides currency-aware arithmetic, exchange-grade
//! tick handling, configurable rounding, and fair allocation. Built on `rust_decimal`
//! for exact decimal calculations. Designed for trading systems, bots, and financial
//! apps where correctness and determinism matter.
//!
//! ## Architecture
//!
//! The crate is organized into four modules, each with a clear responsibility:
//!
//! - [`FinMoney`] — the core type representing a monetary value bound to a currency.
//! Supports arithmetic, allocation, currency conversion, formatting, and
//! tick-based rounding.
//! - [`FinMoneyCurrency`] — represents a currency with a code, optional name, and
//! decimal precision. No predefined currencies — create your own via
//! `FinMoneyCurrency::new()`.
//! - [`FinMoneyRoundingStrategy`] — an enum of rounding strategies used by arithmetic
//! and conversion operations.
//! - [`FinMoneyError`] — error enum covering currency mismatches, division by zero,
//! and invalid inputs.
//!
//! ## Design Principles
//!
//! - **Ergonomic by default.** Comparisons (`<`, `>`, `<=`, `>=`), scalar arithmetic
//! (`+ Decimal`, `* Decimal`), and in-place operations (`+=`, `-=`, `*=`) return
//! direct values.
//! - **Result where it matters.** Only operations with real runtime failure modes
//! (currency mismatch between two `FinMoney` values, division by zero) return `Result`.
//! - **Checked variants available.** Every panicking method has a `Result`-returning
//! counterpart (`unchecked_plus` ↔ `plus_money`, `*` ↔ `multiplied_by_decimal`).
//! - **Precise.** `rust_decimal` 128-bit decimals — no floating-point surprises.
//! - **Currency-agnostic.** No predefined currencies — define any currency with any
//! precision for any domain (fiat, crypto, game tokens, loyalty points).
//! - **Serde support** — optional serialization/deserialization (feature `serde`).
//! Amounts are serialized as strings to preserve precision.
//!
//! ## Quick Start
//!
//! ```rust
//! use finmoney::{FinMoney, FinMoneyCurrency, FinMoneyRoundingStrategy};
//! use rust_decimal_macros::dec;
//!
//! // Create a currency
//! let usd = FinMoneyCurrency::new(1, "USD", Some("US Dollar"), 2)?;
//!
//! // Create money values
//! let price = FinMoney::new(dec!(10.50), usd);
//! let quantity = FinMoney::new(dec!(3), usd);
//!
//! // Perform arithmetic
//! let total = (price + quantity)?;
//! println!("{}", total); // 13.50 USD
//!
//! // Round to tick size
//! let _rounded = price.to_tick_nearest(dec!(0.25))?;
//! # Ok::<(), finmoney::FinMoneyError>(())
//! ```
//!
//! ## Allocation
//!
//! Split a sum into weighted parts with zero remainder loss:
//!
//! ```rust
//! use finmoney::{FinMoney, FinMoneyCurrency, dec};
//!
//! let usd = FinMoneyCurrency::new(1, "USD", None::<&str>, 2)?;
//! let total = FinMoney::new(dec!(100), usd);
//! let parts = total.allocate(&[dec!(1), dec!(1), dec!(1)])?;
//! // parts: [33.34, 33.33, 33.33] — sum is exactly 100.00
//! # Ok::<(), finmoney::FinMoneyError>(())
//! ```
//!
//! ## Currency Conversion
//!
//! ```rust
//! use finmoney::{FinMoney, FinMoneyCurrency, FinMoneyRoundingStrategy, dec};
//!
//! let usd_cur = FinMoneyCurrency::new(1, "USD", None::<&str>, 2)?;
//! let eur_cur = FinMoneyCurrency::new(3, "EUR", None::<&str>, 2)?;
//! let usd_amount = FinMoney::new(dec!(100), usd_cur);
//! let eur_amount = usd_amount.convert_to(eur_cur, dec!(0.92), FinMoneyRoundingStrategy::MidpointNearestEven)?;
//! // 92.00 EUR
//! # Ok::<(), finmoney::FinMoneyError>(())
//! ```
//!
//! ## Summing Iterators
//!
//! ```rust
//! use finmoney::{FinMoney, FinMoneyCurrency, dec};
//!
//! let usd = FinMoneyCurrency::new(1, "USD", None::<&str>, 2)?;
//! let values = vec![
//! FinMoney::new(dec!(10), usd),
//! FinMoney::new(dec!(20), usd),
//! FinMoney::new(dec!(30), usd),
//! ];
//!
//! // Safe version (returns Result)
//! let total = FinMoney::try_sum(values.into_iter())?;
//! // 60.00 USD
//! # Ok::<(), finmoney::FinMoneyError>(())
//! ```
//!
//! ## Formatting
//!
//! ```rust
//! use finmoney::{FinMoney, FinMoneyCurrency, dec};
//!
//! let usd = FinMoneyCurrency::new(1, "USD", None::<&str>, 2).unwrap();
//! let m = FinMoney::new(dec!(1234567.89), usd);
//! assert_eq!(m.format_with_separator(',', '.'), "1,234,567.89 USD");
//! assert_eq!(m.format_padded(4), "1234567.8900 USD");
//! ```
pub use FinMoneyCurrency;
pub use FinMoneyError;
pub use FinMoney;
pub use FinMoneyRoundingStrategy;
// Re-export commonly used types from dependencies
pub use Decimal;
pub use dec;