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