trading_types/
side.rs

1use std::cmp::{Eq, PartialEq};
2use std::fmt;
3
4use serde::{Deserialize, Serialize};
5
6#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
7pub enum Side {
8    #[serde(rename(serialize = "buy", deserialize = "buy"))]
9    #[serde(alias = "Buy")]
10    Buy,
11    #[serde(rename(serialize = "sell", deserialize = "sell"))]
12    #[serde(alias = "Sell")]
13    Sell,
14}
15
16impl fmt::Display for Side {
17    // https://stackoverflow.com/questions/32710187/get-enum-as-string
18    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19        write!(f, "{:?}", self)
20    }
21}
22
23#[derive(thiserror::Error, Debug)]
24pub enum SideError {
25    #[error("bad side {0}")]
26    BadSide(String),
27}
28
29impl Side {
30    pub fn is_buy(&self) -> bool {
31        matches!(*self, Side::Buy)
32    }
33
34    pub fn is_sell(&self) -> bool {
35        matches!(*self, Side::Sell)
36    }
37
38    pub fn try_from_str(s: &str) -> Result<Self, SideError> {
39        match s.to_lowercase().as_str() {
40            "buy" => Ok(Side::Buy),
41            "bid" => Ok(Side::Buy),
42            "sell" => Ok(Side::Sell),
43            "ask" => Ok(Side::Sell),
44            _ => Err(SideError::BadSide(s.to_string())),
45        }
46    }
47
48    pub fn invert(&self) -> Side {
49        match self {
50            Side::Buy => Side::Sell,
51            Side::Sell => Side::Buy,
52        }
53    }
54}
55
56impl TryFrom<&str> for Side {
57    type Error = SideError;
58
59    fn try_from(s: &str) -> Result<Self, SideError> {
60        Self::try_from_str(s)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use serde_json::json;
67
68    use super::*;
69    use std::collections::HashMap;
70
71    #[test]
72    fn test_side_to_json() {
73        let mut m: HashMap<&str, Side> = HashMap::new();
74        m.insert("side", Side::Buy);
75        let v = json!(m);
76        assert_eq!(v.to_string(), r#"{"side":"buy"}"#);
77    }
78
79    #[test]
80    fn test_side_buy_from_json() {
81        let m: HashMap<&str, Side> = serde_json::from_str(r#"{"side":"buy"}"#).unwrap();
82        if let Some(v) = m.get(&"side") {
83            assert!(v.is_buy())
84        } else {
85            panic!("{:?}", m);
86        }
87    }
88
89    #[test]
90    fn test_side_sell_from_json() {
91        let m: HashMap<&str, Side> = serde_json::from_str(r#"{"side":"sell"}"#).unwrap();
92        if let Some(v) = m.get(&"side") {
93            assert_eq!(v.is_buy(), false)
94        } else {
95            panic!("{:?}", m);
96        }
97    }
98
99    #[test]
100    fn test_side_sell_from_upper_json() {
101        let m: HashMap<&str, Side> = serde_json::from_str(r#"{"side":"Sell"}"#).unwrap();
102        if let Some(v) = m.get(&"side") {
103            assert!(v.is_sell())
104        } else {
105            panic!("{:?}", m);
106        }
107    }
108
109    #[test]
110    #[should_panic]
111    fn test_side_unknown_from_json() {
112        let _m: HashMap<&str, Side> = serde_json::from_str(r#"{"side":"WTF"}"#).unwrap();
113    }
114}