1use std::fmt;
5use std::str::FromStr;
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Deserialize)]
15pub(crate) struct OkxResponse<D> {
16 pub code: String,
17 pub msg: String,
18 pub data: D,
19}
20
21#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
38#[serde(transparent)]
39pub struct NumberString(String);
40
41impl NumberString {
42 pub fn as_str(&self) -> &str {
44 &self.0
45 }
46
47 pub fn is_empty(&self) -> bool {
50 self.0.is_empty()
51 }
52
53 pub fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
56 self.0.parse()
57 }
58
59 pub fn into_string(self) -> String {
61 self.0
62 }
63
64 #[cfg(feature = "rust-decimal")]
66 pub fn to_decimal(&self) -> Result<rust_decimal::Decimal, rust_decimal::Error> {
67 self.0.parse()
68 }
69}
70
71impl From<String> for NumberString {
72 fn from(s: String) -> Self {
73 NumberString(s)
74 }
75}
76
77impl From<&str> for NumberString {
78 fn from(s: &str) -> Self {
79 NumberString(s.to_owned())
80 }
81}
82
83impl AsRef<str> for NumberString {
84 fn as_ref(&self) -> &str {
85 &self.0
86 }
87}
88
89impl fmt::Display for NumberString {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 f.write_str(&self.0)
92 }
93}
94
95macro_rules! string_enum {
99 (
100 $(#[$meta:meta])*
101 $vis:vis enum $name:ident {
102 $( $(#[$vmeta:meta])* $variant:ident = $wire:literal ),* $(,)?
103 }
104 ) => {
105 $(#[$meta])*
106 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
107 #[non_exhaustive]
108 $vis enum $name {
109 $( $(#[$vmeta])* $variant, )*
110 Unknown(String),
113 }
114
115 impl $name {
116 pub fn as_str(&self) -> &str {
118 match self {
119 $( $name::$variant => $wire, )*
120 $name::Unknown(s) => s.as_str(),
121 }
122 }
123 }
124
125 impl ::core::convert::From<&str> for $name {
126 fn from(s: &str) -> Self {
127 match s {
128 $( $wire => $name::$variant, )*
129 other => $name::Unknown(other.to_owned()),
130 }
131 }
132 }
133
134 impl ::core::fmt::Display for $name {
135 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
136 f.write_str(self.as_str())
137 }
138 }
139
140 impl ::serde::Serialize for $name {
141 fn serialize<S: ::serde::Serializer>(&self, ser: S) -> ::core::result::Result<S::Ok, S::Error> {
142 ser.serialize_str(self.as_str())
143 }
144 }
145
146 impl<'de> ::serde::Deserialize<'de> for $name {
147 fn deserialize<D: ::serde::Deserializer<'de>>(de: D) -> ::core::result::Result<Self, D::Error> {
148 let s = <::std::string::String as ::serde::Deserialize>::deserialize(de)?;
149 ::core::result::Result::Ok($name::from(s.as_str()))
150 }
151 }
152 };
153}
154
155string_enum! {
156 pub enum InstType {
158 Spot = "SPOT",
160 Margin = "MARGIN",
162 Swap = "SWAP",
164 Futures = "FUTURES",
166 Option = "OPTION",
168 }
169}
170
171string_enum! {
172 pub enum OrderSide {
174 Buy = "buy",
176 Sell = "sell",
178 }
179}
180
181string_enum! {
182 pub enum OrderType {
184 Market = "market",
186 Limit = "limit",
188 PostOnly = "post_only",
190 Fok = "fok",
192 Ioc = "ioc",
194 OptimalLimitIoc = "optimal_limit_ioc",
196 }
197}
198
199string_enum! {
200 pub enum TradeMode {
202 Cash = "cash",
204 Cross = "cross",
206 Isolated = "isolated",
208 }
209}
210
211string_enum! {
212 pub enum PositionSide {
214 Long = "long",
216 Short = "short",
218 Net = "net",
220 }
221}
222
223string_enum! {
224 pub enum OrderState {
226 Live = "live",
228 PartiallyFilled = "partially_filled",
230 Filled = "filled",
232 Canceled = "canceled",
234 MmpCanceled = "mmp_canceled",
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn number_string_parses_and_preserves() {
245 let n = NumberString::from("1.005");
246 assert_eq!(n.as_str(), "1.005");
247 assert_eq!(n.parse::<f64>().unwrap(), 1.005);
248 assert_eq!(n.into_string(), "1.005");
249 }
250
251 #[test]
252 fn known_enum_value_round_trips() {
253 let v: InstType = serde_json::from_str("\"SWAP\"").unwrap();
254 assert_eq!(v, InstType::Swap);
255 assert_eq!(serde_json::to_string(&v).unwrap(), "\"SWAP\"");
256 }
257
258 #[test]
259 fn unknown_enum_value_is_preserved_not_an_error() {
260 let v: InstType = serde_json::from_str("\"FUTURE_THING\"").unwrap();
261 assert_eq!(v, InstType::Unknown("FUTURE_THING".to_owned()));
262 assert_eq!(serde_json::to_string(&v).unwrap(), "\"FUTURE_THING\"");
264 }
265}