1use crate::encoding::WireType;
4use alloc::borrow::Cow;
5#[cfg(not(feature = "std"))]
6use alloc::boxed::Box;
7#[cfg(not(feature = "std"))]
8use alloc::string::String;
9#[cfg(not(feature = "std"))]
10use alloc::vec::Vec;
11use core::fmt;
12
13#[derive(Clone, PartialEq, Eq)]
19pub struct DecodeError {
20 inner: Box<Inner>,
21}
22
23#[derive(Clone, PartialEq, Eq)]
24struct Inner {
25 description: DecodeErrorKind,
27 stack: Vec<(&'static str, &'static str)>,
31}
32
33impl DecodeError {
34 #[deprecated(
38 since = "0.14.2",
39 note = "This function was meant for internal use only. Because of `doc(hidden)` it was publicly available and it is actually used by users. The prost project intents to remove this function in the next breaking release."
40 )]
41 #[cold]
42 #[doc(hidden)]
43 pub fn new(description: impl Into<Cow<'static, str>>) -> DecodeError {
44 DecodeErrorKind::Other {
45 description: description.into(),
46 }
47 .into()
48 }
49
50 #[doc(hidden)]
54 #[cold]
55 pub fn new_unexpected_type_url(
56 actual: impl Into<String>,
57 expected: impl Into<String>,
58 ) -> DecodeError {
59 DecodeErrorKind::UnexpectedTypeUrl {
60 actual: actual.into(),
61 expected: expected.into(),
62 }
63 .into()
64 }
65
66 #[doc(hidden)]
70 pub fn push(&mut self, message: &'static str, field: &'static str) {
71 self.inner.stack.push((message, field));
72 }
73}
74
75impl fmt::Debug for DecodeError {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 f.debug_struct("DecodeError")
78 .field("description", &self.inner.description)
79 .field("stack", &self.inner.stack)
80 .finish()
81 }
82}
83
84impl fmt::Display for DecodeError {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.write_str("failed to decode Protobuf message: ")?;
87 for &(message, field) in &self.inner.stack {
88 write!(f, "{message}.{field}: ")?;
89 }
90 write!(f, "{}", self.inner.description)
91 }
92}
93
94impl From<DecodeErrorKind> for DecodeError {
95 fn from(description: DecodeErrorKind) -> Self {
96 DecodeError {
97 inner: Box::new(Inner {
98 description,
99 stack: Vec::new(),
100 }),
101 }
102 }
103}
104
105#[derive(Clone, Debug, PartialEq, Eq)]
106pub(crate) enum DecodeErrorKind {
107 LengthDelimiterTooLarge,
109 InvalidVarint,
111 #[cfg(not(feature = "no-recursion-limit"))]
112 RecursionLimitReached,
114 InvalidWireType { value: u64 },
116 InvalidKey { key: u64 },
118 InvalidTag,
120 UnexpectedWireType {
122 actual: WireType,
123 expected: WireType,
124 },
125 BufferUnderflow,
127 DelimitedLengthExceeded,
129 UnexpectedEndGroupTag,
131 InvalidString,
133 UnexpectedTypeUrl { actual: String, expected: String },
135 Other { description: Cow<'static, str> },
137}
138
139impl fmt::Display for DecodeErrorKind {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self {
142 Self::LengthDelimiterTooLarge => {
143 write!(f, "length delimiter exceeds maximum usize value")
144 }
145 Self::InvalidVarint => write!(f, "invalid varint"),
146 #[cfg(not(feature = "no-recursion-limit"))]
147 Self::RecursionLimitReached => write!(f, "recursion limit reached"),
148 Self::InvalidWireType { value } => write!(f, "invalid wire type value: {value}"),
149 Self::InvalidKey { key } => write!(f, "invalid key value: {key}"),
150 Self::InvalidTag => write!(f, "invalid tag value: 0"),
151 Self::UnexpectedWireType { actual, expected } => {
152 write!(f, "invalid wire type: {actual:?} (expected {expected:?})")
153 }
154 Self::BufferUnderflow => write!(f, "buffer underflow"),
155 Self::DelimitedLengthExceeded => write!(f, "delimited length exceeded"),
156 Self::UnexpectedEndGroupTag => write!(f, "unexpected end group tag"),
157 Self::InvalidString => {
158 write!(f, "invalid string value: data is not UTF-8 encoded")
159 }
160 Self::UnexpectedTypeUrl { actual, expected } => {
161 write!(f, "unexpected type URL.type_url: expected type URL: \"{expected}\" (got: \"{actual}\")")
162 }
163 Self::Other { description } => {
164 write!(f, "{description}")
165 }
166 }
167 }
168}
169
170impl core::error::Error for DecodeError {}
171
172#[cfg(feature = "std")]
173impl From<DecodeError> for std::io::Error {
174 fn from(error: DecodeError) -> std::io::Error {
175 std::io::Error::new(std::io::ErrorKind::InvalidData, error)
176 }
177}
178
179#[derive(Copy, Clone, Debug, PartialEq, Eq)]
185pub struct EncodeError {
186 required: usize,
187 remaining: usize,
188}
189
190impl EncodeError {
191 pub(crate) fn new(required: usize, remaining: usize) -> EncodeError {
193 EncodeError {
194 required,
195 remaining,
196 }
197 }
198
199 pub fn required_capacity(&self) -> usize {
201 self.required
202 }
203
204 pub fn remaining(&self) -> usize {
206 self.remaining
207 }
208}
209
210impl fmt::Display for EncodeError {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 write!(
213 f,
214 "failed to encode Protobuf message; insufficient buffer capacity (required: {}, remaining: {})",
215 self.required, self.remaining
216 )
217 }
218}
219
220impl core::error::Error for EncodeError {}
221
222#[cfg(feature = "std")]
223impl From<EncodeError> for std::io::Error {
224 fn from(error: EncodeError) -> std::io::Error {
225 std::io::Error::new(std::io::ErrorKind::InvalidInput, error)
226 }
227}
228
229#[derive(Copy, Clone, Debug, PartialEq, Eq)]
235pub struct UnknownEnumValue(pub i32);
236
237impl fmt::Display for UnknownEnumValue {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 write!(f, "unknown enumeration value {}", self.0)
240 }
241}
242
243impl core::error::Error for UnknownEnumValue {}
244
245#[cfg(test)]
246mod test {
247 use super::*;
248
249 #[test]
250 fn test_push() {
251 let mut decode_error = DecodeError::from(DecodeErrorKind::InvalidVarint);
252 decode_error.push("Foo bad", "bar.foo");
253 decode_error.push("Baz bad", "bar.baz");
254
255 assert_eq!(
256 decode_error.to_string(),
257 "failed to decode Protobuf message: Foo bad.bar.foo: Baz bad.bar.baz: invalid varint"
258 );
259 }
260
261 #[cfg(feature = "std")]
262 #[test]
263 fn test_into_std_io_error() {
264 let decode_error = DecodeError::from(DecodeErrorKind::InvalidVarint);
265 let std_io_error = std::io::Error::from(decode_error);
266
267 assert_eq!(std_io_error.kind(), std::io::ErrorKind::InvalidData);
268 assert_eq!(
269 std_io_error.to_string(),
270 "failed to decode Protobuf message: invalid varint"
271 );
272 }
273}