msgpack_rpc/
errors.rs

1use rmpv::decode;
2use std::{error, fmt, io};
3
4/// Error while decoding a sequence of bytes into a `MessagePack-RPC` message
5#[derive(Debug)]
6pub enum DecodeError {
7    /// Some bytes are missing to decode a full msgpack value
8    Truncated(io::Error),
9    /// A byte sequence could not be decoded as a msgpack value, or this value is not a valid
10    /// msgpack-rpc message.
11    Invalid,
12    /// The maximum recursion depth before [`Error::DepthLimitExceeded`] is returned.
13    DepthLimitExceeded,
14    /// An unknown IO error while reading a byte sequence
15    UnknownIo(io::Error),
16}
17
18impl DecodeError {
19    fn description(&self) -> &str {
20        match *self {
21            DecodeError::Truncated(_) => "could not read enough bytes to decode a complete message",
22            DecodeError::UnknownIo(_) => "Unknown IO error while decoding a message",
23            DecodeError::Invalid => "the byte sequence is not a valid msgpack-rpc message",
24            DecodeError::DepthLimitExceeded => {
25                "The depth limit [`MAX_DEPTH`] of 1024 bytes were exceeded."
26            }
27        }
28    }
29}
30
31impl fmt::Display for DecodeError {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
33        self.description().fmt(f)
34    }
35}
36
37impl error::Error for DecodeError {
38    fn description(&self) -> &str {
39        self.description()
40    }
41
42    fn cause(&self) -> Option<&dyn error::Error> {
43        match *self {
44            DecodeError::UnknownIo(ref e) => Some(e),
45            DecodeError::Truncated(ref e) => Some(e),
46            _ => None,
47        }
48    }
49}
50
51impl From<io::Error> for DecodeError {
52    fn from(err: io::Error) -> DecodeError {
53        log::error!("Got I/O error {err}");
54        match err.kind() {
55            io::ErrorKind::UnexpectedEof => DecodeError::Truncated(err),
56            io::ErrorKind::Other => {
57                if let Some(cause) = err.get_ref().unwrap().source() {
58                    // XXX Allocating here sucks, but `description` is deprecated :(
59                    //     Regardless, this depends on implementation details of rmpv, which isn't
60                    //     a great idea in the first place.
61                    if cause.to_string() == "type mismatch" {
62                        return DecodeError::Invalid;
63                    }
64                }
65                DecodeError::UnknownIo(err)
66            }
67            _ => DecodeError::UnknownIo(err),
68        }
69    }
70}
71
72impl From<decode::Error> for DecodeError {
73    fn from(err: decode::Error) -> DecodeError {
74        match err {
75            decode::Error::InvalidMarkerRead(io_err) | decode::Error::InvalidDataRead(io_err) => {
76                From::from(io_err)
77            }
78            decode::Error::DepthLimitExceeded => DecodeError::DepthLimitExceeded,
79        }
80    }
81}