three_commas_types/
pair.rs1use std::{borrow::Cow, fmt};
2
3use serde::{de::Error, Deserialize, Serialize};
4use smol_str::SmolStr;
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub struct Pair {
8 quote: SmolStr,
9 base: SmolStr,
10}
11
12impl fmt::Display for Pair {
13 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 write!(f, "{}/{}", &*self.base, &*self.quote)
15 }
16}
17
18impl Pair {
19 pub fn new(base: impl AsRef<str>, quote: impl AsRef<str>) -> Self {
20 Pair {
21 quote: SmolStr::new(quote),
22 base: SmolStr::new(base),
23 }
24 }
25
26 #[inline]
27 pub fn quote(&self) -> &str {
28 &*self.quote
29 }
30
31 #[inline]
32 pub fn base(&self) -> &str {
33 &*self.base
34 }
35}
36
37impl Serialize for Pair {
38 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
39 where
40 S: serde::Serializer,
41 {
42 let mut s = String::with_capacity(self.base.len() + self.quote.len() + 1);
43 s.push_str(&self.quote);
44 s.push('_');
45 s.push_str(&self.base);
46
47 s.serialize(serializer)
48 }
49}
50
51impl<'de> Deserialize<'de> for Pair {
52 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
53 where
54 D: serde::Deserializer<'de>,
55 {
56 let pair = <Cow<str> as Deserialize>::deserialize(deserializer)?;
57 match pair.split_once('_') {
58 Some((quote, base)) => Ok(Pair {
59 quote: quote.into(),
60 base: base.into(),
61 }),
62 None => Err(<D::Error as Error>::custom(format!(
63 "Expected 3commas pair string on the format of QUOTE_BASE, but got '{}'",
64 pair
65 ))),
66 }
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn roundtrip() {
76 let json = "\"USDT_ETH\"";
77 let pair: Pair = serde_json::from_str(json).expect("parsed successfully");
78
79 assert_eq!(pair.base(), "ETH", "base");
80 assert_eq!(pair.quote(), "USDT", "quote");
81 assert_eq!(format!("{}", pair), "ETH/USDT");
82
83 let serialized = serde_json::to_string(&pair).expect("serialized successfully");
84 assert_eq!(serialized, json);
85 }
86}