serenity/
error.rs

1use std::error::Error as StdError;
2use std::fmt::{self, Error as FormatError};
3use std::io::Error as IoError;
4
5#[cfg(feature = "http")]
6use reqwest::{header::InvalidHeaderValue, Error as ReqwestError};
7#[cfg(feature = "gateway")]
8use tokio_tungstenite::tungstenite::error::Error as TungsteniteError;
9use tracing::instrument;
10
11#[cfg(feature = "client")]
12use crate::client::ClientError;
13#[cfg(feature = "gateway")]
14use crate::gateway::GatewayError;
15#[cfg(feature = "http")]
16use crate::http::HttpError;
17use crate::internal::prelude::*;
18use crate::json::JsonError;
19use crate::model::ModelError;
20
21/// The common result type between most library functions.
22///
23/// The library exposes functions which, for a result type, exposes only one type, rather than the
24/// usual 2 (`Result<T, Error>`). This is because all functions that return a result return
25/// serenity's [`Error`], so this is implied, and a "simpler" result is used.
26pub type Result<T, E = Error> = StdResult<T, E>;
27
28/// A common error enum returned by most of the library's functionality within a custom [`Result`].
29///
30/// The most common error types, the [`ClientError`] and [`GatewayError`] enums, are both wrapped
31/// around this in the form of the [`Self::Client`] and [`Self::Gateway`] variants.
32#[derive(Debug)]
33#[non_exhaustive]
34pub enum Error {
35    /// An error while decoding a payload.
36    Decode(&'static str, Value),
37    /// There was an error with a format.
38    Format(FormatError),
39    /// An [`std::io`] error.
40    Io(IoError),
41    #[cfg_attr(not(feature = "simd_json"), doc = "An error from the [`serde_json`] crate.")]
42    #[cfg_attr(feature = "simd_json", doc = "An error from the [`simd_json`] crate.")]
43    Json(JsonError),
44    /// An error from the [`model`] module.
45    ///
46    /// [`model`]: crate::model
47    Model(ModelError),
48    /// Input exceeded a limit. Providing the input and the limit that's not supposed to be
49    /// exceeded.
50    ///
51    /// *This only exists for the [`GuildId::ban`] and [`Member::ban`] functions. For their cases,
52    /// it's the "reason".*
53    ///
54    /// [`GuildId::ban`]: crate::model::id::GuildId::ban
55    /// [`Member::ban`]: crate::model::guild::Member::ban
56    ExceededLimit(String, u32),
57    /// The input is not in the specified range. Returned by [`GuildId::members`],
58    /// [`Guild::members`] and [`PartialGuild::members`]
59    ///
60    /// (param_name, value, range_min, range_max)
61    ///
62    /// [`GuildId::members`]: crate::model::id::GuildId::members
63    /// [`Guild::members`]: crate::model::guild::Guild::members
64    /// [`PartialGuild::members`]: crate::model::guild::PartialGuild::members
65    NotInRange(&'static str, u64, u64, u64),
66    /// Some other error. This is only used for "Expected value \<TYPE\>" errors, when a more
67    /// detailed error can not be easily provided via the [`Error::Decode`] variant.
68    Other(&'static str),
69    /// An error from the [`url`] crate.
70    Url(String),
71    /// A [client] error.
72    ///
73    /// [client]: crate::client
74    #[cfg(feature = "client")]
75    Client(ClientError),
76    /// An error from the [`gateway`] module.
77    ///
78    /// [`gateway`]: crate::gateway
79    #[cfg(feature = "gateway")]
80    Gateway(GatewayError),
81    /// An error from the [`http`] module.
82    ///
83    /// [`http`]: crate::http
84    #[cfg(feature = "http")]
85    Http(HttpError),
86    /// An error from the `tungstenite` crate.
87    #[cfg(feature = "gateway")]
88    Tungstenite(TungsteniteError),
89}
90
91impl From<FormatError> for Error {
92    fn from(e: FormatError) -> Error {
93        Error::Format(e)
94    }
95}
96
97#[cfg(feature = "gateway")]
98impl From<GatewayError> for Error {
99    fn from(e: GatewayError) -> Error {
100        Error::Gateway(e)
101    }
102}
103
104impl From<IoError> for Error {
105    fn from(e: IoError) -> Error {
106        Error::Io(e)
107    }
108}
109
110impl From<JsonError> for Error {
111    fn from(e: JsonError) -> Error {
112        Error::Json(e)
113    }
114}
115
116impl From<ModelError> for Error {
117    fn from(e: ModelError) -> Error {
118        Error::Model(e)
119    }
120}
121
122#[cfg(feature = "gateway")]
123impl From<TungsteniteError> for Error {
124    fn from(e: TungsteniteError) -> Error {
125        Error::Tungstenite(e)
126    }
127}
128
129#[cfg(feature = "http")]
130impl From<HttpError> for Error {
131    fn from(e: HttpError) -> Error {
132        Error::Http(e)
133    }
134}
135
136#[cfg(feature = "http")]
137impl From<InvalidHeaderValue> for Error {
138    fn from(e: InvalidHeaderValue) -> Error {
139        HttpError::InvalidHeader(e).into()
140    }
141}
142
143#[cfg(feature = "http")]
144impl From<ReqwestError> for Error {
145    fn from(e: ReqwestError) -> Error {
146        HttpError::Request(e).into()
147    }
148}
149
150impl fmt::Display for Error {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        match self {
153            Self::Decode(msg, _) | Self::Other(msg) => f.write_str(msg),
154            Self::ExceededLimit(..) => f.write_str("Input exceeded a limit"),
155            Self::NotInRange(..) => f.write_str("Input is not in the specified range"),
156            Self::Format(inner) => fmt::Display::fmt(&inner, f),
157            Self::Io(inner) => fmt::Display::fmt(&inner, f),
158            Self::Json(inner) => fmt::Display::fmt(&inner, f),
159            Self::Model(inner) => fmt::Display::fmt(&inner, f),
160            Self::Url(msg) => f.write_str(msg),
161            #[cfg(feature = "client")]
162            Self::Client(inner) => fmt::Display::fmt(&inner, f),
163            #[cfg(feature = "gateway")]
164            Self::Gateway(inner) => fmt::Display::fmt(&inner, f),
165            #[cfg(feature = "http")]
166            Self::Http(inner) => fmt::Display::fmt(&inner, f),
167            #[cfg(feature = "gateway")]
168            Self::Tungstenite(inner) => fmt::Display::fmt(&inner, f),
169        }
170    }
171}
172
173impl StdError for Error {
174    #[instrument]
175    fn source(&self) -> Option<&(dyn StdError + 'static)> {
176        match self {
177            Self::Format(inner) => Some(inner),
178            Self::Io(inner) => Some(inner),
179            Self::Json(inner) => Some(inner),
180            Self::Model(inner) => Some(inner),
181            #[cfg(feature = "client")]
182            Self::Client(inner) => Some(inner),
183            #[cfg(feature = "http")]
184            Self::Http(inner) => Some(inner),
185            #[cfg(feature = "gateway")]
186            Self::Tungstenite(inner) => Some(inner),
187            _ => None,
188        }
189    }
190}