Skip to main content

binance/spot/
error.rs

1use serde::Deserialize;
2
3// Numeric error codes are universal across Binance products; the type lives
4// at the crate root. Re-exported here so `binance::spot::ErrorCode` resolves.
5pub use crate::ErrorCode;
6
7#[derive(Debug)]
8pub enum Error {
9    Api(ApiError),
10    Io(std::io::Error),
11    Msg(String),
12    Reqwest(reqwest::Error),
13    SerdeJson(serde_json::Error),
14    SerdeUrlEncoded(serde_urlencoded::ser::Error),
15    SerdePathToError(serde_path_to_error::Error<serde_json::Error>),
16}
17
18impl std::fmt::Display for Error {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        match self {
21            Error::Api(error) => write!(f, "API error: code: {}, msg: {}", error.code, error.msg),
22            Error::Io(error) => write!(f, "I/O error: {error}"),
23            Error::Msg(msg) => write!(f, "{msg}"),
24            Error::Reqwest(error) => write!(f, "reqwest error: {error}"),
25            Error::SerdeJson(error) => write!(f, "serde_json error: {error}"),
26            Error::SerdeUrlEncoded(error) => write!(f, "serde_urlencoded error: {error}"),
27            Error::SerdePathToError(error) => write!(
28                f,
29                "serde_path_to_error error: path: {}, msg: {}",
30                error.path(),
31                error.inner()
32            ),
33        }
34    }
35}
36
37impl std::error::Error for Error {}
38
39#[derive(Debug, Deserialize, PartialEq)]
40pub struct ApiError {
41    pub code: ErrorCode,
42    pub msg: String,
43}
44
45impl From<ApiError> for Error {
46    fn from(err: ApiError) -> Self {
47        Error::Api(err)
48    }
49}
50
51impl From<std::io::Error> for Error {
52    fn from(err: std::io::Error) -> Self {
53        Error::Io(err)
54    }
55}
56
57impl From<String> for Error {
58    fn from(msg: String) -> Self {
59        Error::Msg(msg)
60    }
61}
62
63impl From<&str> for Error {
64    fn from(msg: &str) -> Self {
65        Error::Msg(msg.to_string())
66    }
67}
68
69impl From<reqwest::Error> for Error {
70    fn from(err: reqwest::Error) -> Self {
71        Error::Reqwest(err)
72    }
73}
74
75impl From<serde_json::Error> for Error {
76    fn from(err: serde_json::Error) -> Self {
77        Error::SerdeJson(err)
78    }
79}
80
81impl From<serde_urlencoded::ser::Error> for Error {
82    fn from(err: serde_urlencoded::ser::Error) -> Self {
83        Error::SerdeUrlEncoded(err)
84    }
85}
86
87impl From<serde_path_to_error::Error<serde_json::Error>> for Error {
88    fn from(err: serde_path_to_error::Error<serde_json::Error>) -> Self {
89        Error::SerdePathToError(err)
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use crate::serde::deserialize_json;
96
97    use super::*;
98
99    #[test]
100    fn deserialize_api_error_from_wire_format() {
101        let json = r#"{"code":-1102,"msg":"Param 'origClientOrderId' or 'orderId' must be sent, but both were empty/null!"}"#;
102        let parsed: ApiError = deserialize_json(json).unwrap();
103        assert_eq!(parsed.code, ErrorCode::MANDATORY_PARAM_EMPTY_OR_MALFORMED);
104        assert!(parsed.code.is_bad_request());
105    }
106}