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