1use {
2 serde::{Deserialize, Deserializer, Serialize, Serializer},
3 std::{
4 borrow::Borrow,
5 fmt::{Debug, Display, Formatter},
6 str::FromStr,
7 },
8};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum EthNetwork {
12 Main,
13 Test,
14}
15
16#[derive(Debug, Default, Clone, PartialEq, Eq)]
17pub enum Network {
18 #[default]
19 Main,
20 Test,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
43#[allow(clippy::upper_case_acronyms)]
44pub enum Asset {
45 BTC(Network),
46 SOL(Network),
47 Dodge(Network),
48 ETH(EthNetwork),
49 Unknown(String),
50}
51
52impl Asset {
53 #[allow(clippy::missing_panics_doc)]
56 pub fn new(a: &str) -> Self {
57 match Self::from_str(a) {
58 Ok(asset) => asset,
59 Err(e) => panic!("this should never happen! {e}"),
60 }
61 }
62}
63
64impl Default for Asset {
65 fn default() -> Self {
66 Self::BTC(Network::default())
67 }
68}
69
70impl<'de> Deserialize<'de> for Asset {
71 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72 where
73 D: Deserializer<'de>,
74 {
75 let a: String = String::deserialize(deserializer)?;
76 Self::from_str(&a).map_err(|_| serde::de::Error::custom("this should never happen"))
77 }
78}
79
80impl Serialize for Asset {
81 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82 where
83 S: Serializer,
84 {
85 let a = self.to_string();
86 a.serialize(serializer)
87 }
88}
89
90impl AsRef<str> for Asset {
91 #[allow(clippy::match_same_arms)]
92 fn as_ref(&self) -> &str {
93 match self {
94 Self::BTC(Network::Main) => "BTC",
95 Self::BTC(Network::Test) => "BTC_TEST",
96 Self::Dodge(Network::Main) => "DOGE",
97 Self::Dodge(Network::Test) => "DOGE_TEST",
98 Self::SOL(Network::Main) => "SOL",
99 Self::SOL(Network::Test) => "SOL_TEST",
100 Self::ETH(EthNetwork::Main) => "ETH",
101 Self::ETH(EthNetwork::Test) => "ETH_TEST5",
102 Self::Unknown(s) => s,
103 }
104 }
105}
106
107impl Borrow<str> for Asset {
108 fn borrow(&self) -> &str {
109 self.as_ref()
110 }
111}
112
113impl Display for Asset {
114 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
115 write!(f, "{}", self.as_ref())
116 }
117}
118
119impl From<Asset> for String {
120 fn from(value: Asset) -> Self {
121 format!("{value}")
122 }
123}
124
125impl FromStr for Asset {
128 type Err = std::string::ParseError;
129
130 fn from_str(s: &str) -> Result<Self, Self::Err> {
131 match s.to_uppercase().as_str() {
132 "BTC" => Ok(ASSET_BTC),
133 "BTC_TEST" => Ok(ASSET_BTC_TEST),
134 "SOL" => Ok(ASSET_SOL),
135 "SOL_TEST" => Ok(ASSET_SOL_TEST),
136 "DOGE" => Ok(ASSET_DOGE),
137 "DOGE_TEST" => Ok(ASSET_DOGE_TEST),
138 "ETH" => Ok(ASSET_ETH),
139 "ETH_TEST5" => Ok(ASSET_ETH_TEST),
140 _ => Ok(Self::Unknown(String::from(s))),
141 }
142 }
143}
144
145pub const ASSET_BTC: Asset = Asset::BTC(Network::Main);
146pub const ASSET_BTC_TEST: Asset = Asset::BTC(Network::Test);
147pub const ASSET_SOL: Asset = Asset::SOL(Network::Main);
148pub const ASSET_SOL_TEST: Asset = Asset::SOL(Network::Test);
149pub const ASSET_ETH: Asset = Asset::ETH(EthNetwork::Main);
150pub const ASSET_ETH_TEST: Asset = Asset::ETH(EthNetwork::Test);
151pub const ASSET_DOGE: Asset = Asset::Dodge(Network::Main);
152pub const ASSET_DOGE_TEST: Asset = Asset::Dodge(Network::Test);
153
154#[cfg(test)]
155mod tests {
156 use {
157 crate::{
158 ASSET_BTC,
159 ASSET_BTC_TEST,
160 ASSET_SOL,
161 ASSET_SOL_TEST,
162 assets::{ASSET_DOGE, ASSET_DOGE_TEST, ASSET_ETH, ASSET_ETH_TEST, Asset},
163 },
164 serde_json::json,
165 std::str::FromStr,
166 };
167
168 #[test]
169 fn asset_from_string() -> anyhow::Result<()> {
170 let a = Asset::from_str("BTC")?;
171 assert_eq!(a, ASSET_BTC);
172
173 let a = Asset::from_str("BTC_TEST")?;
174 assert_eq!(a, ASSET_BTC_TEST);
175
176 let a = Asset::from_str("SOL")?;
177 assert_eq!(a, ASSET_SOL);
178
179 let a = Asset::from_str("SOL_TEST")?;
180 assert_eq!(a, ASSET_SOL_TEST);
181
182 let a = Asset::from_str("DOGE")?;
183 assert_eq!(a, ASSET_DOGE);
184
185 let a = Asset::from_str("DOGE_TEST")?;
186 assert_eq!(a, ASSET_DOGE_TEST);
187
188 let a = Asset::from_str("ETH")?;
189 assert_eq!(a, ASSET_ETH);
190
191 let a = Asset::from_str("ETH_TEST5")?;
192 assert_eq!(a, ASSET_ETH_TEST);
193
194 let a = Asset::from_str("UNKNOWN")?;
195 assert_eq!(a, Asset::Unknown("UNKNOWN".to_string()));
196
197 assert_eq!(Asset::default(), ASSET_BTC);
198
199 assert_eq!("\"SOL\"", serde_json::to_string(&ASSET_SOL)?);
200
201 assert_eq!("BTC", ASSET_BTC.as_ref());
202 assert_eq!("DOGE", ASSET_DOGE.as_ref());
203 assert_eq!("DOGE_TEST", ASSET_DOGE_TEST.as_ref());
204 assert_eq!("ETH", ASSET_ETH.as_ref());
205 assert_eq!("ETH_TEST5", ASSET_ETH_TEST.as_ref());
206
207 assert_eq!(Asset::Unknown("blah".to_owned()).to_string(), "blah");
208 assert_eq!(ASSET_BTC.to_string(), "BTC");
209
210 assert_eq!("BLAH", Asset::new("BLAH").to_string());
211 let v = json!("SOL_TEST");
212 let a: Asset = serde_json::from_value(v)?;
213 assert_eq!("SOL_TEST", a.to_string().as_str());
214 Ok(())
215 }
216}