planus/
errors.rs

1/// The main error type for Planus
2#[derive(Copy, Clone, Debug)]
3pub struct Error {
4    /// The location of the error
5    pub source_location: ErrorLocation,
6    /// The kind of error
7    pub error_kind: ErrorKind,
8}
9
10impl core::fmt::Display for Error {
11    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12        write!(f, "In {}: {}", self.source_location, self.error_kind)
13    }
14}
15
16#[cfg(feature = "std")]
17impl std::error::Error for Error {
18    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
19        Some(&self.error_kind)
20    }
21}
22
23/// The possible errors in planus when reading data from a serialized buffer.
24#[derive(Copy, Clone, Debug)]
25#[non_exhaustive]
26pub enum ErrorKind {
27    /// The offset was out of bounds.
28    InvalidOffset,
29    /// The buffer was too short while validating a length field.
30    InvalidLength,
31    /// An enum contained an unknown value. For forward compatibility this
32    /// error should be handled appropriately.
33    UnknownEnumTag {
34        /// The enum value that wasn't recognized.
35        source: UnknownEnumTagKind,
36    },
37    /// An union contained an unknown variant. For forward compatibility this
38    /// error should be handled appropriately.
39    UnknownUnionTag {
40        /// The union tag that wasn't recognized.
41        tag: u8,
42    },
43    /// A vtable had an invalid length (too large, too small or unaligned).
44    InvalidVtableLength {
45        /// The length of the vtable.
46        length: u16,
47    },
48    /// A string contained invalid utf-8.
49    InvalidUtf8 {
50        /// The utf-8 error triggered by the string.
51        source: core::str::Utf8Error,
52    },
53    /// A required field was missing.
54    MissingRequired,
55    /// A string null terminator was missing.
56    MissingNullTerminator,
57}
58
59impl core::fmt::Display for ErrorKind {
60    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61        match self {
62            ErrorKind::InvalidOffset => write!(f, "Invalid offset"),
63            ErrorKind::InvalidLength => write!(f, "Invalid length"),
64            ErrorKind::UnknownEnumTag { source } => source.fmt(f),
65            ErrorKind::UnknownUnionTag { tag } => write!(f, "Unknown union (tag = {})", tag),
66            ErrorKind::InvalidVtableLength { length } => {
67                write!(f, "Invalid vtable length (length = {})", length)
68            }
69            ErrorKind::InvalidUtf8 { source } => write!(f, "Invalid utf-8: {}", source),
70            ErrorKind::MissingRequired => write!(f, "Missing required field"),
71            ErrorKind::MissingNullTerminator => write!(f, "Missing null terminator"),
72        }
73    }
74}
75
76#[cfg(feature = "std")]
77impl std::error::Error for ErrorKind {
78    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
79        match self {
80            ErrorKind::InvalidOffset => None,
81            ErrorKind::InvalidLength => None,
82            ErrorKind::UnknownEnumTag { source } => Some(source),
83            ErrorKind::UnknownUnionTag { .. } => None,
84            ErrorKind::InvalidVtableLength { .. } => None,
85            ErrorKind::InvalidUtf8 { source } => Some(source),
86            ErrorKind::MissingRequired => None,
87            ErrorKind::MissingNullTerminator => None,
88        }
89    }
90}
91
92impl From<UnknownEnumTagKind> for ErrorKind {
93    fn from(source: UnknownEnumTagKind) -> Self {
94        ErrorKind::UnknownEnumTag { source }
95    }
96}
97
98impl From<core::str::Utf8Error> for ErrorKind {
99    fn from(source: core::str::Utf8Error) -> Self {
100        ErrorKind::InvalidUtf8 { source }
101    }
102}
103
104#[derive(Clone, Debug)]
105/// Information about an unrecognized enum tag.
106///
107/// In order to be forward compatible [`Result`]s with this error variant should
108/// be handled gracefully.
109pub struct UnknownEnumTag {
110    /// The location of the unknown tag.
111    pub source_location: ErrorLocation,
112    /// The unknown tag.
113    pub error_kind: UnknownEnumTagKind,
114}
115
116impl core::fmt::Display for UnknownEnumTag {
117    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118        write!(f, "In {}: {}", self.source_location, self.error_kind)
119    }
120}
121
122#[cfg(feature = "std")]
123impl std::error::Error for UnknownEnumTag {
124    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
125        Some(&self.error_kind)
126    }
127}
128
129#[derive(Copy, Clone, Debug)]
130/// The value of an unknown enum tag.
131pub struct UnknownEnumTagKind {
132    /// The unknown tag.
133    pub tag: i128,
134}
135
136impl core::fmt::Display for UnknownEnumTagKind {
137    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
138        write!(f, "Unknown enum (tag = {})", self.tag)
139    }
140}
141
142#[cfg(feature = "std")]
143impl std::error::Error for UnknownEnumTagKind {}
144
145#[derive(Copy, Clone, Debug)]
146/// The location of the error in both the generated code and the binary data
147/// where it was encountered.
148pub struct ErrorLocation {
149    /// The flatbuffers type where the error was encountered.
150    pub type_: &'static str,
151    /// The generated method where the error was encountered.
152    pub method: &'static str,
153    /// Offset into the flatbuffers buffer where the error was encountered.
154    pub byte_offset: usize,
155}
156
157impl core::fmt::Display for ErrorLocation {
158    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
159        if self.byte_offset != usize::MAX {
160            write!(
161                f,
162                "<{}@{:x}>::{}()",
163                self.type_, self.byte_offset, self.method,
164            )
165        } else {
166            write!(f, "<{}>::{}()", self.type_, self.method,)
167        }
168    }
169}
170
171impl From<UnknownEnumTag> for Error {
172    fn from(error: UnknownEnumTag) -> Self {
173        Self {
174            source_location: error.source_location,
175            error_kind: error.error_kind.into(),
176        }
177    }
178}
179
180impl From<core::convert::Infallible> for Error {
181    fn from(value: core::convert::Infallible) -> Self {
182        match value {}
183    }
184}
185
186impl UnknownEnumTagKind {
187    /// Helper function that adds an error location to this error.
188    pub fn with_error_location(
189        self,
190        type_: &'static str,
191        method: &'static str,
192        byte_offset: usize,
193    ) -> UnknownEnumTag {
194        UnknownEnumTag {
195            source_location: ErrorLocation {
196                type_,
197                method,
198                byte_offset,
199            },
200            error_kind: self,
201        }
202    }
203}
204
205impl ErrorKind {
206    /// Helper function that adds an error location to this error.
207    pub fn with_error_location(
208        self,
209        type_: &'static str,
210        method: &'static str,
211        byte_offset: usize,
212    ) -> Error {
213        Error {
214            source_location: ErrorLocation {
215                type_,
216                method,
217                byte_offset,
218            },
219            error_kind: self,
220        }
221    }
222}