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 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}