1 //! Protobuf error type
2 
3 use std::error::Error;
4 use std::fmt;
5 use std::io;
6 use std::str;
7 
8 use crate::wire_format::WireType;
9 
10 /// `Result` alias for `ProtobufError`
11 pub type ProtobufResult<T> = Result<T, ProtobufError>;
12 
13 /// Enum values added here for diagnostic purposes.
14 /// Users should not depend on specific values.
15 #[derive(Debug)]
16 pub enum WireError {
17     /// Could not read complete message because stream is EOF
18     UnexpectedEof,
19     /// Wrong wire type for given field
20     UnexpectedWireType(WireType),
21     /// Incorrect tag value
22     IncorrectTag(u32),
23     /// Malformed map field
24     IncompleteMap,
25     /// Malformed varint
26     IncorrectVarint,
27     /// String is not valid UTD-8
28     Utf8Error,
29     /// Enum value is unknown
30     InvalidEnumValue(i32),
31     /// Message is too nested
32     OverRecursionLimit,
33     /// Could not read complete message because stream is EOF
34     TruncatedMessage,
35     /// Other error
36     Other,
37 }
38 
39 impl fmt::Display for WireError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result40     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41         match self {
42             WireError::Utf8Error => write!(f, "invalid UTF-8 sequence"),
43             WireError::UnexpectedWireType(..) => write!(f, "unexpected wire type"),
44             WireError::InvalidEnumValue(..) => write!(f, "invalid enum value"),
45             WireError::IncorrectTag(..) => write!(f, "incorrect tag"),
46             WireError::IncorrectVarint => write!(f, "incorrect varint"),
47             WireError::IncompleteMap => write!(f, "incomplete map"),
48             WireError::UnexpectedEof => write!(f, "unexpected EOF"),
49             WireError::OverRecursionLimit => write!(f, "over recursion limit"),
50             WireError::TruncatedMessage => write!(f, "truncated message"),
51             WireError::Other => write!(f, "other error"),
52         }
53     }
54 }
55 
56 /// Generic protobuf error
57 #[derive(Debug)]
58 pub enum ProtobufError {
59     /// I/O error when reading or writing
60     IoError(io::Error),
61     /// Malformed input
62     WireError(WireError),
63     /// Protocol contains a string which is not valid UTF-8 string
64     Utf8(str::Utf8Error),
65     /// Not all required fields set
66     MessageNotInitialized {
67         /// Message name
68         message: &'static str,
69     },
70 }
71 
72 impl ProtobufError {
73     /// Create message not initialized error.
74     #[doc(hidden)]
message_not_initialized(message: &'static str) -> ProtobufError75     pub fn message_not_initialized(message: &'static str) -> ProtobufError {
76         ProtobufError::MessageNotInitialized { message: message }
77     }
78 }
79 
80 impl fmt::Display for ProtobufError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result81     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82         match self {
83             // not sure that cause should be included in message
84             &ProtobufError::IoError(ref e) => write!(f, "IO error: {}", e),
85             &ProtobufError::WireError(ref e) => fmt::Display::fmt(e, f),
86             &ProtobufError::Utf8(ref e) => write!(f, "{}", e),
87             &ProtobufError::MessageNotInitialized { .. } => write!(f, "not all message fields set"),
88         }
89     }
90 }
91 
92 impl Error for ProtobufError {
93     #[allow(deprecated)] // call to `description`
description(&self) -> &str94     fn description(&self) -> &str {
95         match self {
96             // not sure that cause should be included in message
97             &ProtobufError::IoError(ref e) => e.description(),
98             &ProtobufError::WireError(ref e) => match *e {
99                 WireError::Utf8Error => "invalid UTF-8 sequence",
100                 WireError::UnexpectedWireType(..) => "unexpected wire type",
101                 WireError::InvalidEnumValue(..) => "invalid enum value",
102                 WireError::IncorrectTag(..) => "incorrect tag",
103                 WireError::IncorrectVarint => "incorrect varint",
104                 WireError::IncompleteMap => "incomplete map",
105                 WireError::UnexpectedEof => "unexpected EOF",
106                 WireError::OverRecursionLimit => "over recursion limit",
107                 WireError::TruncatedMessage => "truncated message",
108                 WireError::Other => "other error",
109             },
110             &ProtobufError::Utf8(ref e) => &e.description(),
111             &ProtobufError::MessageNotInitialized { .. } => "not all message fields set",
112         }
113     }
114 
cause(&self) -> Option<&dyn Error>115     fn cause(&self) -> Option<&dyn Error> {
116         match self {
117             &ProtobufError::IoError(ref e) => Some(e),
118             &ProtobufError::Utf8(ref e) => Some(e),
119             &ProtobufError::WireError(..) => None,
120             &ProtobufError::MessageNotInitialized { .. } => None,
121         }
122     }
123 }
124 
125 impl From<io::Error> for ProtobufError {
from(err: io::Error) -> Self126     fn from(err: io::Error) -> Self {
127         ProtobufError::IoError(err)
128     }
129 }
130 
131 impl From<str::Utf8Error> for ProtobufError {
from(err: str::Utf8Error) -> Self132     fn from(err: str::Utf8Error) -> Self {
133         ProtobufError::Utf8(err)
134     }
135 }
136 
137 impl From<ProtobufError> for io::Error {
from(err: ProtobufError) -> Self138     fn from(err: ProtobufError) -> Self {
139         match err {
140             ProtobufError::IoError(e) => e,
141             ProtobufError::WireError(e) => {
142                 io::Error::new(io::ErrorKind::InvalidData, ProtobufError::WireError(e))
143             }
144             ProtobufError::MessageNotInitialized { message: msg } => io::Error::new(
145                 io::ErrorKind::InvalidInput,
146                 ProtobufError::MessageNotInitialized { message: msg },
147             ),
148             e => io::Error::new(io::ErrorKind::Other, Box::new(e)),
149         }
150     }
151 }
152