1use std::fmt::Display;
2
3use crate::utils::deserialize_currency_code;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Serialize, Deserialize)]
7pub struct Currency {
8 pub is_blockchain: bool,
9 pub is_stablecoin: bool,
10 pub is_fiat: bool,
11 pub name: String,
12 #[serde(deserialize_with = "deserialize_currency_code")]
13 pub code: CurrencyCode,
14 #[serde(skip_serializing_if = "Option::is_none")]
15 pub url: Option<String>,
16 pub decimals: u8,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
20#[serde(untagged)]
21pub enum CurrencyCode {
22 Crypto(CryptoCurrencyCode),
23 Fiat(FiatCurrencyCode),
24}
25
26#[cfg(not(tarpaulin))]
27impl Display for CurrencyCode {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 CurrencyCode::Crypto(code) => write!(f, "{code}"),
31 CurrencyCode::Fiat(code) => write!(f, "{code}"),
32 }
33 }
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
37#[serde(rename_all = "UPPERCASE")]
38pub enum CryptoCurrencyCode {
39 Usdt,
40 Ton,
41 Btc,
42 Eth,
43 Ltc,
44 Bnb,
45 Trx,
46 Usdc,
47 Doge,
48 Send,
49 Jet,
50 #[serde(other)]
51 Unknown,
52}
53
54#[cfg(not(tarpaulin))]
55impl Display for CryptoCurrencyCode {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 write!(f, "{self:?}")
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
62#[serde(rename_all = "UPPERCASE")]
63pub enum FiatCurrencyCode {
64 Usd,
65 Eur,
66 Rub,
67 Byn,
68 Uah,
69 Gbp,
70 Cny,
71 Kgs,
72 Kzt,
73 Uzs,
74 Gel,
75 Try,
76 Amd,
77 Thb,
78 Tjs,
79 Inr,
80 Brl,
81 Idr,
82 Azn,
83 Aed,
84 Pln,
85 Ils,
86 Lkr,
87 #[serde(other)]
88 Unknown,
89}
90
91#[cfg(not(tarpaulin))]
92impl Display for FiatCurrencyCode {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 write!(f, "{self:?}")
95 }
96}
97
98#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
99#[serde(rename_all = "lowercase")]
100pub enum CurrencyType {
101 Crypto,
102 Fiat,
103}
104
105#[cfg(not(tarpaulin))]
106impl Display for CurrencyType {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 write!(f, "{self:?}")
109 }
110}
111
112impl From<CryptoCurrencyCode> for CurrencyCode {
113 fn from(code: CryptoCurrencyCode) -> Self {
114 CurrencyCode::Crypto(code)
115 }
116}
117
118impl From<FiatCurrencyCode> for CurrencyCode {
119 fn from(code: FiatCurrencyCode) -> Self {
120 CurrencyCode::Fiat(code)
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_currency_type_serialization() {
130 let crypto = CurrencyType::Crypto;
131 let fiat = CurrencyType::Fiat;
132
133 assert_eq!(serde_json::to_string(&crypto).unwrap(), "\"crypto\"");
134 assert_eq!(serde_json::to_string(&fiat).unwrap(), "\"fiat\"");
135 }
136
137 #[test]
138 fn test_crypto_currency_code_serialization() {
139 let btc = CryptoCurrencyCode::Btc;
140 let ton = CryptoCurrencyCode::Ton;
141
142 assert_eq!(serde_json::to_string(&btc).unwrap(), "\"BTC\"");
143 assert_eq!(serde_json::to_string(&ton).unwrap(), "\"TON\"");
144 }
145
146 #[test]
147 fn test_fiat_currency_code_serialization() {
148 let usd = FiatCurrencyCode::Usd;
149 let eur = FiatCurrencyCode::Eur;
150
151 assert_eq!(serde_json::to_string(&usd).unwrap(), "\"USD\"");
152 assert_eq!(serde_json::to_string(&eur).unwrap(), "\"EUR\"");
153 }
154
155 #[test]
156 fn test_currency_code_deserialization() {
157 let crypto: CryptoCurrencyCode = serde_json::from_str("\"BTC\"").unwrap();
158 let fiat: FiatCurrencyCode = serde_json::from_str("\"USD\"").unwrap();
159
160 assert_eq!(crypto, CryptoCurrencyCode::Btc);
161 assert_eq!(fiat, FiatCurrencyCode::Usd);
162
163 assert_eq!(
164 serde_json::from_str::<CryptoCurrencyCode>("\"btc\"").unwrap(),
165 CryptoCurrencyCode::Unknown
166 );
167 assert_eq!(
168 serde_json::from_str::<FiatCurrencyCode>("\"usd\"").unwrap(),
169 FiatCurrencyCode::Unknown
170 );
171 }
172
173 #[test]
174 fn test_currency_code_conversion() {
175 let crypto = CryptoCurrencyCode::Btc;
176 let fiat = FiatCurrencyCode::Usd;
177
178 let currency_code_crypto: CurrencyCode = crypto.into();
179 let currency_code_fiat: CurrencyCode = fiat.into();
180
181 assert!(matches!(
182 currency_code_crypto,
183 CurrencyCode::Crypto(CryptoCurrencyCode::Btc)
184 ));
185 assert!(matches!(currency_code_fiat, CurrencyCode::Fiat(FiatCurrencyCode::Usd)));
186 }
187}