klirr_core/models/
exchange_rates.rs1use std::ops::Mul;
2
3use crate::prelude::*;
4
5#[derive(Clone, Debug, Serialize, Builder, Getters)]
7pub struct ExchangeRates {
8 #[getset(get = "pub")]
10 target_currency: Currency,
11
12 #[getset(get = "pub")]
24 rates: ExchangeRatesMap,
25}
26
27impl ExchangeRates {
28 pub fn convert(
53 &self,
54 unit_price: impl Into<UnitPrice>,
55 currency: Currency,
56 ) -> Result<UnitPrice> {
57 let unit_price = unit_price.into();
58 if self.target_currency == currency {
59 return Ok(unit_price);
60 }
61 let rate = self.get_rate(currency)?;
62 let converted = rate.mul(*unit_price);
63 Ok(converted)
64 }
65
66 fn get_rate(&self, currency: Currency) -> Result<UnitPrice> {
67 self.rates
68 .get(¤cy)
69 .cloned()
70 .ok_or(Error::FoundNoExchangeRate {
71 target: self.target_currency,
72 base: currency,
73 })
74 }
75}
76
77impl ExchangeRates {
78 pub fn hard_coded() -> Self {
79 let rates = ExchangeRatesMap::from([
80 (Currency::EUR, UnitPrice::from(dec!(1.0))),
81 (Currency::USD, UnitPrice::from(dec!(1.2))),
82 (Currency::GBP, UnitPrice::from(dec!(0.85))),
83 (Currency::SEK, UnitPrice::from(dec!(11.0))),
84 ]);
85 Self {
86 target_currency: Currency::EUR,
87 rates,
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use test_log::test;
96
97 #[test]
98 fn test_hard_coded() {
99 let exchange_rates = ExchangeRates::hard_coded();
100 assert!(!exchange_rates.rates().is_empty());
101 }
102
103 #[test]
104 fn test_convert() {
105 let exchange_rates = ExchangeRates::hard_coded();
106 let converted = exchange_rates.convert(dec!(100.0), Currency::USD).unwrap();
107 assert_eq!(*converted, dec!(120.0));
108 }
109
110 #[test]
111 fn test_convert_not_found() {
112 let exchange_rates = ExchangeRates::builder()
113 .target_currency(Currency::EUR)
114 .rates(ExchangeRatesMap::new())
115 .build();
116 let result = exchange_rates.convert(dec!(100.0), Currency::JPY);
117 assert!(result.is_err());
118 }
119
120 #[test]
121 fn test_get_rate_not_found() {
122 let exchange_rates = ExchangeRates::builder()
123 .target_currency(Currency::EUR)
124 .rates(ExchangeRatesMap::new())
125 .build();
126 let result = exchange_rates.get_rate(Currency::JPY);
127 assert!(result.is_err());
128 }
129}