conversions/
conversions.rs

1//! Currency conversion examples.
2//!
3//! This example demonstrates how to convert between currencies using exchange rates,
4//! including rate creation, inverse rates, and rate metadata for auditability.
5//!
6//! Run with: `cargo run --example conversions`
7
8use typed_money::{Amount, Rate, EUR, GBP, JPY, USD};
9
10fn main() {
11    println!("=== Currency Conversion Examples ===\n");
12
13    // ========================================
14    // Basic Conversion
15    // ========================================
16    println!("1. BASIC CONVERSION");
17    println!("-------------------");
18
19    let usd_amount = Amount::<USD>::from_major(100);
20    println!("Starting amount: {}", usd_amount);
21
22    // Create an exchange rate: 1 USD = 0.85 EUR
23    let usd_to_eur = Rate::<USD, EUR>::new(0.85);
24    println!("Exchange rate: 1 USD = 0.85 EUR");
25
26    // Convert
27    let eur_amount = usd_amount.convert(&usd_to_eur);
28    println!("Converted amount: {}", eur_amount);
29    println!("(${} × 0.85 = €{})\n", 100, eur_amount.to_major_floor());
30
31    // ========================================
32    // Inverse Rates
33    // ========================================
34    println!("2. INVERSE RATES");
35    println!("----------------");
36
37    let usd_to_eur = Rate::<USD, EUR>::new(0.85);
38    println!("USD → EUR rate: {}", usd_to_eur.value());
39
40    // Get the inverse rate automatically
41    let eur_to_usd = usd_to_eur.inverse();
42    println!("EUR → USD rate (inverse): {}", eur_to_usd.value());
43    println!("(1 / 0.85 = ~1.176)\n");
44
45    // Converting back
46    let original_usd = Amount::<USD>::from_major(100);
47    let eur = original_usd.convert(&usd_to_eur);
48    let back_to_usd = eur.convert(&eur_to_usd);
49
50    println!("Original: {}", original_usd);
51    println!("To EUR:   {}", eur);
52    println!("Back to USD: {}", back_to_usd);
53    println!("(Should be approximately the same)\n");
54
55    // ========================================
56    // Multiple Conversions
57    // ========================================
58    println!("3. MULTIPLE CONVERSIONS");
59    println!("-----------------------");
60
61    let usd = Amount::<USD>::from_major(1000);
62    println!("Starting with: {}", usd);
63
64    // Define multiple rates
65    let usd_to_eur = Rate::<USD, EUR>::new(0.85);
66    let usd_to_gbp = Rate::<USD, GBP>::new(0.73);
67    let usd_to_jpy = Rate::<USD, JPY>::new(110.0);
68
69    println!("\nExchange rates:");
70    println!("  1 USD = {} EUR", usd_to_eur.value());
71    println!("  1 USD = {} GBP", usd_to_gbp.value());
72    println!("  1 USD = {} JPY", usd_to_jpy.value());
73
74    println!("\nConversions:");
75    let eur = usd.convert(&usd_to_eur);
76    let gbp = usd.convert(&usd_to_gbp);
77    let jpy = usd.convert(&usd_to_jpy);
78
79    println!("  {} → {}", usd, eur);
80    println!("  {} → {}", usd, gbp);
81    println!("  {} → {}", usd, jpy);
82
83    // ========================================
84    // Chained Conversions
85    // ========================================
86    println!("\n4. CHAINED CONVERSIONS");
87    println!("----------------------");
88
89    println!("Converting USD → EUR → GBP");
90
91    let usd = Amount::<USD>::from_major(100);
92    let usd_to_eur = Rate::<USD, EUR>::new(0.85);
93    let eur_to_gbp = Rate::<EUR, GBP>::new(0.86);
94
95    println!("Starting: {}", usd);
96    let eur = usd.convert(&usd_to_eur);
97    println!("After USD→EUR: {}", eur);
98    let gbp = eur.convert(&eur_to_gbp);
99    println!("After EUR→GBP: {}", gbp);
100    println!("(${} × 0.85 × 0.86 = £{})\n", 100, gbp.to_major_floor());
101
102    // ========================================
103    // Rate Metadata for Auditability
104    // ========================================
105    println!("5. RATE METADATA FOR AUDITABILITY");
106    println!("----------------------------------");
107
108    // Create a rate with metadata
109    let rate = Rate::<USD, EUR>::new(0.85)
110        .with_timestamp_unix_secs(1700000000)
111        .with_source("ECB"); // European Central Bank
112
113    println!("Rate: {}", rate.value());
114    println!("Timestamp: {:?}", rate.timestamp_unix_secs());
115    println!("Source: {:?}", rate.source());
116
117    let amount = Amount::<USD>::from_major(1000);
118    let converted = amount.convert(&rate);
119    println!(
120        "\nConverted {} to {} using rate from {:?}",
121        amount,
122        converted,
123        rate.source().unwrap_or("unknown")
124    );
125
126    // ========================================
127    // Real-World Example: International Payment
128    // ========================================
129    println!("\n6. REAL-WORLD EXAMPLE: INTERNATIONAL PAYMENT");
130    println!("---------------------------------------------");
131
132    // Customer pays in USD
133    let payment_usd = Amount::<USD>::from_major(250);
134    println!("Customer payment: {}", payment_usd);
135
136    // Current exchange rate (would come from an API in production)
137    let current_rate = Rate::<USD, EUR>::new(0.92)
138        .with_timestamp_unix_secs(1700000000)
139        .with_source("API");
140
141    // Convert to EUR
142    let payment_eur = payment_usd.convert(&current_rate);
143    println!("Converted to EUR: {}", payment_eur);
144
145    // Calculate fees
146    let fee_percentage = 3; // 3% transaction fee
147    let fee = (payment_eur * fee_percentage) / 100;
148    println!("Transaction fee ({}%): {}", fee_percentage, fee);
149
150    let final_amount = payment_eur - fee;
151    println!("Final amount to recipient: {}", final_amount);
152
153    println!("\nTransaction summary:");
154    println!("  Original: {}", payment_usd);
155    println!(
156        "  Rate: {} (from {:?})",
157        current_rate.value(),
158        current_rate.source().unwrap_or("N/A")
159    );
160    println!("  Converted: {}", payment_eur);
161    println!("  Fee: -{}", fee);
162    println!("  Final: {}", final_amount);
163
164    // ========================================
165    // Type Safety with Conversions
166    // ========================================
167    println!("\n7. TYPE SAFETY");
168    println!("--------------");
169
170    println!("✓ Can only convert with matching rate types");
171    println!("✓ USD amount requires Rate<USD, X>");
172    println!("✗ Cannot use Rate<EUR, GBP> on USD amount (compile error!)");
173    println!("\nThe type system ensures you always use the correct exchange rate!");
174
175    // This would NOT compile:
176    // let usd = Amount::<USD>::from_major(100);
177    // let wrong_rate = Rate::<EUR, GBP>::new(0.86);
178    // let invalid = usd.convert(&wrong_rate);  // Compile error!
179
180    println!("\n=== All conversion examples completed! ===");
181}