1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::io;
use std::str;

use crate::reflect::error::ReflectError;
use crate::wire_format::WireType;

/// [`Result`] alias for [`Error`].
pub type Result<T> = std::result::Result<T, crate::Error>;

/// Enum values added here for diagnostic purposes.
/// Users should not depend on specific values.
#[derive(Debug, thiserror::Error)]
pub(crate) enum WireError {
    #[error("Unexpected EOF")]
    UnexpectedEof,
    #[error("Unexpected wire type")]
    UnexpectedWireType(WireType),
    #[error("Incorrect tag")]
    IncorrectTag(u32),
    #[error("Incorrect varint")]
    IncorrectVarint,
    #[error("Invalid UTF-8 sequence")]
    Utf8Error,
    #[error("Invalid enum `{}` value: {}", .0, .1)]
    InvalidEnumValue(&'static str, i32),
    #[error("Over recursion limit")]
    OverRecursionLimit,
    #[error("Truncated message")]
    TruncatedMessage,
    // not really possible
    #[error("Limit overflow")]
    LimitOverflow,
    #[error("New limit must not be greater than current limit")]
    LimitIncrease,
    #[error("Encoded message size {0} is too large")]
    MessageTooLarge(u64),
    #[error("Value too large for u32: {}", .0)]
    U32Overflow(u64),
    #[error("Value too large for i32: {}", .0)]
    I32Overflow(i64),
}

/// Generic protobuf error
#[derive(Debug, thiserror::Error)]
pub(crate) enum ProtobufError {
    /// I/O error when reading or writing
    #[error(transparent)]
    IoError(#[from] io::Error),
    /// Malformed input
    #[error(transparent)]
    WireError(#[from] WireError),
    #[error(transparent)]
    Reflect(#[from] ReflectError),
    /// Protocol contains a string which is not valid UTF-8 string
    #[error("UTF-8 decode error")]
    Utf8(
        #[source]
        #[from]
        str::Utf8Error,
    ),
    /// Not all required fields of message set.
    #[error("Message `{}` is missing required fields", .0)]
    MessageNotInitialized(String),
    /// Message is too large.
    #[error("Provided buffer has not enough capacity to write message `{0}`")]
    BufferHasNotEnoughCapacity(String),
    /// Protobuf type and runtime types mismatch.
    #[error("Protobuf type and runtime types are not compatible")]
    IncompatibleProtobufTypeAndRuntimeType,
    /// Group field type not implemented.
    #[error("Group field is not supported")]
    GroupIsNotImplemented,
}

/// Error type for protobuf operations.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct Error(pub(crate) Box<ProtobufError>);

impl From<ProtobufError> for Error {
    #[cold]
    fn from(e: ProtobufError) -> Self {
        Self(Box::new(e))
    }
}

impl From<WireError> for Error {
    #[cold]
    fn from(e: WireError) -> Self {
        Self(Box::new(ProtobufError::WireError(e)))
    }
}

impl From<ReflectError> for Error {
    #[cold]
    fn from(e: ReflectError) -> Self {
        Self(Box::new(ProtobufError::Reflect(e)))
    }
}

impl From<Error> for io::Error {
    #[cold]
    fn from(err: Error) -> Self {
        match *err.0 {
            ProtobufError::IoError(e) => e,
            ProtobufError::WireError(e) => {
                io::Error::new(io::ErrorKind::InvalidData, ProtobufError::WireError(e))
            }
            ProtobufError::MessageNotInitialized(message) => io::Error::new(
                io::ErrorKind::InvalidInput,
                ProtobufError::MessageNotInitialized(message),
            ),
            e => io::Error::new(io::ErrorKind::Other, Box::new(e)),
        }
    }
}

impl From<io::Error> for Error {
    #[cold]
    fn from(err: io::Error) -> Self {
        Error(Box::new(ProtobufError::IoError(err)))
    }
}

#[cfg(test)]
mod test {
    use std::mem;

    #[test]
    fn error_size() {
        assert_eq!(mem::size_of::<usize>(), mem::size_of::<crate::Error>());
    }
}