async_proto/
error.rs

1use std::{
2    borrow::Cow,
3    convert::Infallible,
4    io,
5};
6#[cfg(feature = "tokio-tungstenite021")] use tokio_tungstenite021::tungstenite as tungstenite021;
7#[cfg(feature = "tokio-tungstenite024")] use tokio_tungstenite024::tungstenite as tungstenite024;
8#[cfg(feature = "tokio-tungstenite027")] use tokio_tungstenite027::tungstenite as tungstenite027;
9
10/// Specifies what went wrong while reading (receiving) a value.
11#[derive(Debug, thiserror::Error)]
12#[allow(missing_docs)]
13pub enum ReadErrorKind {
14    /// Received a buffer with more than [`usize::MAX`] elements
15    #[error("received a buffer with more than usize::MAX elements: {0}")]
16    BufSize(#[from] std::num::TryFromIntError),
17    /// An error variant you can use when manually implementing [`Protocol`](crate::Protocol)
18    #[error("{0}")]
19    Custom(String),
20    /// The end of the stream was encountered before a complete value was read.
21    ///
22    /// Note that this error condition may also be represented as a [`ReadErrorKind::Io`] with [`kind`](io::Error::kind) [`UnexpectedEof`](io::ErrorKind::UnexpectedEof).
23    #[error("reached end of stream")]
24    EndOfStream,
25    #[error("received an infinite or NaN number")]
26    FloatNotFinite,
27    #[error("received length ({len}) exceeds specified maximum length ({max_len})")]
28    MaxLen {
29        len: u64,
30        max_len: u64,
31    },
32    #[cfg(feature = "tokio-tungstenite021")]
33    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-tungstenite021")))]
34    /// Received a non-`Binary` WebSocket message (e.g. `Text` or `Ping`).
35    #[error("unexpected type of WebSocket message")]
36    MessageKind021(tungstenite021::Message),
37    #[cfg(feature = "tokio-tungstenite024")]
38    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-tungstenite024")))]
39    /// Received a non-`Binary` WebSocket message (e.g. `Text` or `Ping`).
40    #[error("unexpected type of WebSocket message")]
41    MessageKind024(tungstenite024::Message),
42    #[cfg(feature = "tokio-tungstenite027")]
43    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-tungstenite027")))]
44    /// Received a non-`Binary` WebSocket message (e.g. `Text` or `Ping`).
45    #[error("unexpected type of WebSocket message")]
46    MessageKind027(tungstenite027::Message),
47    /// Attempted to read an empty type
48    #[error("attempted to read an empty type")]
49    ReadNever,
50    #[error("{0:?}")] // fallible_collections::TryReserveError does not implement Error, see https://github.com/vcombey/fallible_collections/pull/44
51    TryReserve(fallible_collections::TryReserveError),
52    #[error("unknown enum variant: {0}")]
53    UnknownVariant8(u8),
54    #[error("unknown enum variant: {0}")]
55    UnknownVariant16(u16),
56    #[error("unknown enum variant: {0}")]
57    UnknownVariant32(u32),
58    #[error("unknown enum variant: {0}")]
59    UnknownVariant64(u64),
60    #[error("unknown enum variant: {0}")]
61    UnknownVariant128(u128),
62    #[cfg(any(any(feature = "tokio-tungstenite021", feature = "tokio-tungstenite024")))]
63    #[cfg_attr(docsrs, doc(cfg(any(any(feature = "tokio-tungstenite021", feature = "tokio-tungstenite024")))))]
64    #[error("unexpected text message received from WebSocket: {0}")]
65    WebSocketTextMessage024(String),
66    #[cfg(any(feature = "tokio-tungstenite027"))]
67    #[cfg_attr(docsrs, doc(cfg(any(feature = "tokio-tungstenite027"))))]
68    #[error("unexpected text message received from WebSocket: {0}")]
69    WebSocketTextMessage027(tungstenite027::Utf8Bytes),
70    #[error(transparent)] Io(#[from] io::Error),
71    #[cfg(any(any(feature = "tokio-tungstenite021", feature = "tokio-tungstenite024", feature = "tokio-tungstenite027")))]
72    #[cfg_attr(docsrs, doc(cfg(any(any(feature = "tokio-tungstenite021", feature = "tokio-tungstenite024", feature = "tokio-tungstenite027")))))]
73    #[error(transparent)] ParseInt(#[from] std::num::ParseIntError),
74    #[cfg(any(feature = "tokio-tungstenite021"))]
75    #[cfg_attr(docsrs, doc(cfg(any(feature = "tokio-tungstenite021"))))]
76    #[error(transparent)] Tungstenite021(#[from] tungstenite021::Error),
77    #[cfg(any(feature = "tokio-tungstenite024"))]
78    #[cfg_attr(docsrs, doc(cfg(any(feature = "tokio-tungstenite024"))))]
79    #[error(transparent)] Tungstenite024(#[from] tungstenite024::Error),
80    #[cfg(any(feature = "tokio-tungstenite027"))]
81    #[cfg_attr(docsrs, doc(cfg(any(feature = "tokio-tungstenite027"))))]
82    #[error(transparent)] Tungstenite027(#[from] tungstenite027::Error),
83    #[error(transparent)] Utf8(#[from] std::string::FromUtf8Error),
84}
85
86impl From<Infallible> for ReadErrorKind {
87    fn from(never: Infallible) -> Self {
88        match never {}
89    }
90}
91
92impl From<String> for ReadErrorKind {
93    fn from(s: String) -> Self {
94        Self::Custom(s)
95    }
96}
97
98impl<'a> From<&'a str> for ReadErrorKind {
99    fn from(s: &str) -> Self {
100        Self::Custom(s.to_owned())
101    }
102}
103
104impl<'a> From<Cow<'a, str>> for ReadErrorKind {
105    fn from(s: Cow<'a, str>) -> Self {
106        Self::Custom(s.into_owned())
107    }
108}
109
110impl From<fallible_collections::TryReserveError> for ReadErrorKind {
111    fn from(e: fallible_collections::TryReserveError) -> Self {
112        Self::TryReserve(e)
113    }
114}
115
116impl From<ReadErrorKind> for io::Error {
117    fn from(e: ReadErrorKind) -> Self {
118        match e {
119            ReadErrorKind::BufSize(e) => io::Error::new(io::ErrorKind::InvalidData, e),
120            ReadErrorKind::Io(e) => e,
121            #[cfg(feature = "tokio-tungstenite021")] ReadErrorKind::Tungstenite021(e) => io::Error::new(io::ErrorKind::Other, e),
122            #[cfg(feature = "tokio-tungstenite024")] ReadErrorKind::Tungstenite024(e) => io::Error::new(io::ErrorKind::Other, e),
123            #[cfg(feature = "tokio-tungstenite027")] ReadErrorKind::Tungstenite027(e) => io::Error::new(io::ErrorKind::Other, e),
124            ReadErrorKind::Utf8(e) => io::Error::new(io::ErrorKind::InvalidData, e),
125            ReadErrorKind::EndOfStream => io::Error::new(io::ErrorKind::UnexpectedEof, e),
126            #[cfg(any(feature = "tokio-tungstenite021", feature = "tokio-tungstenite024"))] ReadErrorKind::WebSocketTextMessage024(ref msg) => io::Error::new(if msg.is_empty() { io::ErrorKind::UnexpectedEof } else { io::ErrorKind::InvalidData }, e),
127            #[cfg(feature = "tokio-tungstenite027")] ReadErrorKind::WebSocketTextMessage027(ref msg) => io::Error::new(if msg.is_empty() { io::ErrorKind::UnexpectedEof } else { io::ErrorKind::InvalidData }, e),
128            ReadErrorKind::FloatNotFinite |
129            ReadErrorKind::MaxLen { .. } |
130            ReadErrorKind::UnknownVariant8(_) |
131            ReadErrorKind::UnknownVariant16(_) |
132            ReadErrorKind::UnknownVariant32(_) |
133            ReadErrorKind::UnknownVariant64(_) |
134            ReadErrorKind::UnknownVariant128(_) => io::Error::new(io::ErrorKind::InvalidData, e),
135            #[cfg(feature = "tokio-tungstenite021")] ReadErrorKind::MessageKind021(_) => io::Error::new(io::ErrorKind::InvalidData, e),
136            #[cfg(feature = "tokio-tungstenite024")] ReadErrorKind::MessageKind024(_) => io::Error::new(io::ErrorKind::InvalidData, e),
137            #[cfg(feature = "tokio-tungstenite027")] ReadErrorKind::MessageKind027(_) => io::Error::new(io::ErrorKind::InvalidData, e),
138            #[cfg(any(feature = "tokio-tungstenite021", feature = "tokio-tungstenite024", feature = "tokio-tungstenite027"))] ReadErrorKind::ParseInt(_) => io::Error::new(io::ErrorKind::InvalidData, e),
139            ReadErrorKind::ReadNever => io::Error::new(io::ErrorKind::InvalidInput, e),
140            ReadErrorKind::TryReserve(_) => io::Error::new(io::ErrorKind::OutOfMemory, e),
141            ReadErrorKind::Custom(_) => io::Error::new(io::ErrorKind::Other, e),
142        }
143    }
144}
145
146impl From<ReadError> for io::Error {
147    fn from(ReadError { kind, .. }: ReadError) -> Self {
148        kind.into()
149    }
150}
151
152/// The error returned from the [`read`](crate::Protocol::read) and [`read_sync`](crate::Protocol::read_sync) methods.
153#[derive(Debug, thiserror::Error)]
154#[error("{kind}")]
155pub struct ReadError {
156    /// Where it went wrong.
157    pub context: ErrorContext,
158    /// What went wrong.
159    pub kind: ReadErrorKind,
160}
161
162/// Specifies what went wrong while writing (sending) a value.
163#[derive(Debug, thiserror::Error)]
164#[allow(missing_docs)]
165pub enum WriteErrorKind {
166    /// Tried to send a buffer with more than [`u64::MAX`] elements
167    #[error("tried to send a buffer with more than u64::MAX elements: {0}")]
168    BufSize(#[from] std::num::TryFromIntError),
169    /// An error variant you can use when manually implementing [`Protocol`](crate::Protocol)
170    #[error("{0}")]
171    Custom(String),
172    #[error(transparent)] Io(#[from] io::Error),
173    #[error("attempted to write length {len} exceeding specified maximum length ({max_len})")]
174    MaxLen {
175        len: u64,
176        max_len: u64,
177    },
178    #[cfg(feature = "tokio-tungstenite021")]
179    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-tungstenite021")))]
180    #[error(transparent)] Tungstenite021(#[from] tungstenite021::Error),
181    #[cfg(feature = "tokio-tungstenite024")]
182    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-tungstenite024")))]
183    #[error(transparent)] Tungstenite024(#[from] tungstenite024::Error),
184    #[cfg(feature = "tokio-tungstenite027")]
185    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-tungstenite027")))]
186    #[error(transparent)] Tungstenite027(#[from] tungstenite027::Error),
187}
188
189impl From<Infallible> for WriteErrorKind {
190    fn from(never: Infallible) -> Self {
191        match never {}
192    }
193}
194
195impl From<String> for WriteErrorKind {
196    fn from(s: String) -> Self {
197        Self::Custom(s)
198    }
199}
200
201impl<'a> From<&'a str> for WriteErrorKind {
202    fn from(s: &str) -> Self {
203        Self::Custom(s.to_owned())
204    }
205}
206
207impl<'a> From<Cow<'a, str>> for WriteErrorKind {
208    fn from(s: Cow<'a, str>) -> Self {
209        Self::Custom(s.into_owned())
210    }
211}
212
213impl From<WriteErrorKind> for io::Error {
214    fn from(e: WriteErrorKind) -> Self {
215        match e {
216            WriteErrorKind::BufSize(e) => io::Error::new(io::ErrorKind::InvalidData, e),
217            WriteErrorKind::Io(e) => e,
218            WriteErrorKind::MaxLen { .. } => io::Error::new(io::ErrorKind::InvalidData, e),
219            #[cfg(feature = "tokio-tungstenite021")] WriteErrorKind::Tungstenite021(e) => io::Error::new(io::ErrorKind::Other, e),
220            #[cfg(feature = "tokio-tungstenite024")] WriteErrorKind::Tungstenite024(e) => io::Error::new(io::ErrorKind::Other, e),
221            #[cfg(feature = "tokio-tungstenite027")] WriteErrorKind::Tungstenite027(e) => io::Error::new(io::ErrorKind::Other, e),
222            WriteErrorKind::Custom(_) => io::Error::new(io::ErrorKind::Other, e),
223        }
224    }
225}
226
227impl From<WriteError> for io::Error {
228    fn from(WriteError { kind, .. }: WriteError) -> Self {
229        kind.into()
230    }
231}
232
233/// The error returned from the [`write`](crate::Protocol::write) and [`write_sync`](crate::Protocol::write_sync) methods.
234#[derive(Debug, thiserror::Error)]
235#[error("{kind}")]
236pub struct WriteError {
237    /// Where it went wrong.
238    pub context: ErrorContext,
239    /// What went wrong.
240    pub kind: WriteErrorKind,
241}
242
243/// Provides additional information about the origin of an error.
244#[derive(Debug)]
245pub enum ErrorContext {
246    /// An error context you can use when manually implementing `Protocol`.
247    Custom(String),
248    /// The error was produced by a `Protocol` implementation defined in the `async-proto` crate.
249    BuiltIn {
250        /// The name of the type whose `Protocol` implementation produced the error.
251        ///
252        /// Typically does not include type parameters.
253        for_type: &'static str,
254    },
255    /// The error occurred while reading/writing a WebSocket message.
256    WebSocket {
257        /// The context of the error returned from the message's `Protocol` implementation.
258        source: Box<Self>,
259    },
260    /// The error was produced by a sink returned from [`async_proto::websocket021`](crate::websocket021) and [`async_proto::websocket024`](crate::websocket024).
261    WebSocketSink,
262    /// The error was produced by a stream returned from [`async_proto::websocket021`](crate::websocket021) and [`async_proto::websocket024`](crate::websocket024).
263    WebSocketStream,
264    /// The error was produced by the default implementation of a `Protocol` trait method.
265    DefaultImpl,
266    /// The error was produced by an automatically derived `Protocol` implementation.
267    Derived {
268        /// The name of the type whose `Protocol` implementation produced the error.
269        for_type: &'static str,
270    },
271    /// The error occurred while reading/writing the discriminant of an enum.
272    EnumDiscrim {
273        /// The context of the error returned from the discriminant type's `Protocol` implementation.
274        source: Box<Self>,
275    },
276    /// The error occurred while reading/writing a field of a tuple, tuple struct, or tuple enum variant.
277    UnnamedField {
278        /// The position of the field, starting at 0.
279        idx: usize,
280        /// The context of the error returned from the field's `Protocol` implementation.
281        source: Box<Self>,
282    },
283    /// The error occurred while reading/writing a field of a struct or struct enum variant.
284    NamedField {
285        /// The name of the field.
286        name: &'static str,
287        /// The context of the error returned from the field's `Protocol` implementation.
288        source: Box<Self>,
289    },
290    /// The error occurred in the `FromStr` implementation of a type whose `Protocol` implementation was derived with `#[async_proto(as_string)]`.
291    FromStr,
292    /// The error occurred while reading/writing a string representing a type whose `Protocol` implementation was derived with `#[async_proto(as_string)]`.
293    AsString {
294        /// The context of the error returned from `String`'s `Protocol` implementation.
295        source: Box<Self>,
296    },
297    /// The error occurred in the `TryInto` implementation for a type whose `Protocol` implementation was derived with `#[async_proto(via = ...)]`.
298    TryInto,
299    /// The error occurred while reading/writing a proxy type representing a type whose `Protocol` implementation was derived with `#[async_proto(via ...)]`.
300    Via {
301        /// The context of the error returned from the proxy type's `Protocol` implementation.
302        source: Box<Self>,
303    },
304    /// The error was produced by the `async_proto::bitflags` macro.
305    Bitflags {
306        /// The context of the error returned from the bits type's `Protocol` implementation.
307        source: Box<Self>,
308    },
309}