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 #[serde(other)]
87 Unknown,
88}
89
90#[cfg(not(tarpaulin))]
91impl Display for FiatCurrencyCode {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 write!(f, "{:?}", self)
94 }
95}
96
97#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
98#[serde(rename_all = "lowercase")]
99pub enum CurrencyType {
100 Crypto,
101 Fiat,
102}
103
104#[cfg(not(tarpaulin))]
105impl Display for CurrencyType {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 write!(f, "{:?}", self)
108 }
109}
110
111impl From<CryptoCurrencyCode> for CurrencyCode {
112 fn from(code: CryptoCurrencyCode) -> Self {
113 CurrencyCode::Crypto(code)
114 }
115}
116
117impl From<FiatCurrencyCode> for CurrencyCode {
118 fn from(code: FiatCurrencyCode) -> Self {
119 CurrencyCode::Fiat(code)
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn test_currency_type_serialization() {
129 let crypto = CurrencyType::Crypto;
130 let fiat = CurrencyType::Fiat;
131
132 assert_eq!(serde_json::to_string(&crypto).unwrap(), "\"crypto\"");
133 assert_eq!(serde_json::to_string(&fiat).unwrap(), "\"fiat\"");
134 }
135
136 #[test]
137 fn test_crypto_currency_code_serialization() {
138 let btc = CryptoCurrencyCode::Btc;
139 let ton = CryptoCurrencyCode::Ton;
140
141 assert_eq!(serde_json::to_string(&btc).unwrap(), "\"BTC\"");
142 assert_eq!(serde_json::to_string(&ton).unwrap(), "\"TON\"");
143 }
144
145 #[test]
146 fn test_fiat_currency_code_serialization() {
147 let usd = FiatCurrencyCode::Usd;
148 let eur = FiatCurrencyCode::Eur;
149
150 assert_eq!(serde_json::to_string(&usd).unwrap(), "\"USD\"");
151 assert_eq!(serde_json::to_string(&eur).unwrap(), "\"EUR\"");
152 }
153
154 #[test]
155 fn test_currency_code_deserialization() {
156 let crypto: CryptoCurrencyCode = serde_json::from_str("\"BTC\"").unwrap();
157 let fiat: FiatCurrencyCode = serde_json::from_str("\"USD\"").unwrap();
158
159 assert_eq!(crypto, CryptoCurrencyCode::Btc);
160 assert_eq!(fiat, FiatCurrencyCode::Usd);
161
162 assert_eq!(
163 serde_json::from_str::<CryptoCurrencyCode>("\"btc\"").unwrap(),
164 CryptoCurrencyCode::Unknown
165 );
166 assert_eq!(
167 serde_json::from_str::<FiatCurrencyCode>("\"usd\"").unwrap(),
168 FiatCurrencyCode::Unknown
169 );
170 }
171
172 #[test]
173 fn test_currency_code_conversion() {
174 let crypto = CryptoCurrencyCode::Btc;
175 let fiat = FiatCurrencyCode::Usd;
176
177 let currency_code_crypto: CurrencyCode = crypto.into();
178 let currency_code_fiat: CurrencyCode = fiat.into();
179
180 assert!(matches!(
181 currency_code_crypto,
182 CurrencyCode::Crypto(CryptoCurrencyCode::Btc)
183 ));
184 assert!(matches!(currency_code_fiat, CurrencyCode::Fiat(FiatCurrencyCode::Usd)));
185 }
186}