prost/
error.rs

1//! Protobuf encoding and decoding errors.
2
3use alloc::borrow::Cow;
4use alloc::boxed::Box;
5use alloc::vec::Vec;
6
7use core::fmt;
8
9/// A Protobuf message decoding error.
10///
11/// `DecodeError` indicates that the input buffer does not contain a valid
12/// Protobuf message. The error details should be considered 'best effort': in
13/// general it is not possible to exactly pinpoint why data is malformed.
14#[derive(Clone, PartialEq, Eq)]
15pub struct DecodeError {
16    inner: Box<Inner>,
17}
18
19#[derive(Clone, PartialEq, Eq)]
20struct Inner {
21    /// A 'best effort' root cause description.
22    description: Cow<'static, str>,
23    /// A stack of (message, field) name pairs, which identify the specific
24    /// message type and field where decoding failed. The stack contains an
25    /// entry per level of nesting.
26    stack: Vec<(&'static str, &'static str)>,
27}
28
29impl DecodeError {
30    /// Creates a new `DecodeError` with a 'best effort' root cause description.
31    ///
32    /// Meant to be used only by `Message` implementations.
33    #[doc(hidden)]
34    #[cold]
35    pub fn new(description: impl Into<Cow<'static, str>>) -> DecodeError {
36        DecodeError {
37            inner: Box::new(Inner {
38                description: description.into(),
39                stack: Vec::new(),
40            }),
41        }
42    }
43
44    /// Pushes a (message, field) name location pair on to the location stack.
45    ///
46    /// Meant to be used only by `Message` implementations.
47    #[doc(hidden)]
48    pub fn push(&mut self, message: &'static str, field: &'static str) {
49        self.inner.stack.push((message, field));
50    }
51}
52
53impl fmt::Debug for DecodeError {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        f.debug_struct("DecodeError")
56            .field("description", &self.inner.description)
57            .field("stack", &self.inner.stack)
58            .finish()
59    }
60}
61
62impl fmt::Display for DecodeError {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        f.write_str("failed to decode Protobuf message: ")?;
65        for &(message, field) in &self.inner.stack {
66            write!(f, "{}.{}: ", message, field)?;
67        }
68        f.write_str(&self.inner.description)
69    }
70}
71
72#[cfg(feature = "std")]
73impl std::error::Error for DecodeError {}
74
75#[cfg(feature = "std")]
76impl From<DecodeError> for std::io::Error {
77    fn from(error: DecodeError) -> std::io::Error {
78        std::io::Error::new(std::io::ErrorKind::InvalidData, error)
79    }
80}
81
82/// A Protobuf message encoding error.
83///
84/// `EncodeError` always indicates that a message failed to encode because the
85/// provided buffer had insufficient capacity. Message encoding is otherwise
86/// infallible.
87#[derive(Copy, Clone, Debug, PartialEq, Eq)]
88pub struct EncodeError {
89    required: usize,
90    remaining: usize,
91}
92
93impl EncodeError {
94    /// Creates a new `EncodeError`.
95    pub(crate) fn new(required: usize, remaining: usize) -> EncodeError {
96        EncodeError {
97            required,
98            remaining,
99        }
100    }
101
102    /// Returns the required buffer capacity to encode the message.
103    pub fn required_capacity(&self) -> usize {
104        self.required
105    }
106
107    /// Returns the remaining length in the provided buffer at the time of encoding.
108    pub fn remaining(&self) -> usize {
109        self.remaining
110    }
111}
112
113impl fmt::Display for EncodeError {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        write!(
116            f,
117            "failed to encode Protobuf message; insufficient buffer capacity (required: {}, remaining: {})",
118            self.required, self.remaining
119        )
120    }
121}
122
123#[cfg(feature = "std")]
124impl std::error::Error for EncodeError {}
125
126#[cfg(feature = "std")]
127impl From<EncodeError> for std::io::Error {
128    fn from(error: EncodeError) -> std::io::Error {
129        std::io::Error::new(std::io::ErrorKind::InvalidInput, error)
130    }
131}