1use crate::{ErrorPayload, RpcRecv};
2use serde_json::value::RawValue;
3
4#[derive(Debug, thiserror::Error)]
6pub enum RpcError<E, ErrResp = Box<RawValue>> {
7    #[error("server returned an error response: {0}")]
9    ErrorResp(ErrorPayload<ErrResp>),
10
11    #[error("server returned a null response when a non-null response was expected")]
13    NullResp,
14
15    #[error("unsupported feature: {0}")]
17    UnsupportedFeature(&'static str),
18
19    #[error("local usage error: {0}")]
22    LocalUsageError(#[source] Box<dyn std::error::Error + Send + Sync>),
23
24    #[error("serialization error: {0}")]
26    SerError(
27        #[source]
31        serde_json::Error,
32    ),
33    #[error("deserialization error: {err}\n{text}")]
35    DeserError {
36        #[source]
40        err: serde_json::Error,
41        text: String,
43    },
44
45    #[error(transparent)]
49    Transport(
50        #[from]
52        E,
53    ),
54}
55
56impl<E, ErrResp> RpcError<E, ErrResp>
57where
58    ErrResp: RpcRecv,
59{
60    pub const fn err_resp(err: ErrorPayload<ErrResp>) -> Self {
62        Self::ErrorResp(err)
63    }
64
65    pub fn local_usage(err: impl std::error::Error + Send + Sync + 'static) -> Self {
67        Self::LocalUsageError(err.into())
68    }
69
70    pub fn local_usage_str(err: &str) -> Self {
72        Self::LocalUsageError(err.into())
73    }
74
75    pub fn deser_err(err: serde_json::Error, text: impl AsRef<str>) -> Self {
82        let text = text.as_ref();
83
84        if let Ok(err) = serde_json::from_str::<ErrorPayload<ErrResp>>(text) {
86            return Self::ErrorResp(err);
87        }
88
89        Self::DeserError { err, text: text.to_owned() }
90    }
91}
92
93impl<E, ErrResp> RpcError<E, ErrResp> {
94    pub const fn ser_err(err: serde_json::Error) -> Self {
97        Self::SerError(err)
98    }
99
100    pub const fn is_ser_error(&self) -> bool {
102        matches!(self, Self::SerError(_))
103    }
104
105    pub const fn is_deser_error(&self) -> bool {
107        matches!(self, Self::DeserError { .. })
108    }
109
110    pub const fn is_transport_error(&self) -> bool {
112        matches!(self, Self::Transport(_))
113    }
114
115    pub const fn is_error_resp(&self) -> bool {
117        matches!(self, Self::ErrorResp(_))
118    }
119
120    pub const fn is_null_resp(&self) -> bool {
122        matches!(self, Self::NullResp)
123    }
124
125    pub const fn is_unsupported_feature(&self) -> bool {
127        matches!(self, Self::UnsupportedFeature(_))
128    }
129
130    pub const fn is_local_usage_error(&self) -> bool {
132        matches!(self, Self::LocalUsageError(_))
133    }
134
135    pub const fn as_error_resp(&self) -> Option<&ErrorPayload<ErrResp>> {
137        match self {
138            Self::ErrorResp(err) => Some(err),
139            _ => None,
140        }
141    }
142
143    pub const fn as_transport_err(&self) -> Option<&E> {
145        match self {
146            Self::Transport(err) => Some(err),
147            _ => None,
148        }
149    }
150}