1 //! Protobuf encoding and decoding errors. 2 3 use alloc::borrow::Cow; 4 use alloc::boxed::Box; 5 use alloc::vec::Vec; 6 7 use 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)] 15 pub struct DecodeError { 16 inner: Box<Inner>, 17 } 18 19 #[derive(Clone, PartialEq, Eq)] 20 struct 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 29 impl 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] new(description: impl Into<Cow<'static, str>>) -> DecodeError35 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)] push(&mut self, message: &'static str, field: &'static str)48 pub fn push(&mut self, message: &'static str, field: &'static str) { 49 self.inner.stack.push((message, field)); 50 } 51 } 52 53 impl fmt::Debug for DecodeError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result54 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 62 impl fmt::Display for DecodeError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result63 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")] 73 impl std::error::Error for DecodeError {} 74 75 #[cfg(feature = "std")] 76 impl From<DecodeError> for std::io::Error { from(error: DecodeError) -> std::io::Error77 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)] 88 pub struct EncodeError { 89 required: usize, 90 remaining: usize, 91 } 92 93 impl EncodeError { 94 /// Creates a new `EncodeError`. new(required: usize, remaining: usize) -> EncodeError95 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. required_capacity(&self) -> usize103 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. remaining(&self) -> usize108 pub fn remaining(&self) -> usize { 109 self.remaining 110 } 111 } 112 113 impl fmt::Display for EncodeError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result114 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")] 124 impl std::error::Error for EncodeError {} 125 126 #[cfg(feature = "std")] 127 impl From<EncodeError> for std::io::Error { from(error: EncodeError) -> std::io::Error128 fn from(error: EncodeError) -> std::io::Error { 129 std::io::Error::new(std::io::ErrorKind::InvalidInput, error) 130 } 131 } 132