1use crate::memory::{Memory, MemoryError, OwnedVec};
8use core::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[non_exhaustive]
16pub enum ErrorCode {
17 UnexpectedEnd,
19 MalformedTag,
21 TagTooLarge,
23 LengthNotMinimal,
25 LengthTooLarge,
27 OffsetTooLarge,
29 IndefiniteLengthNotAllowed,
31 UnterminatedContents,
33 MalformedEndOfContents,
35 WrongConstruction,
37 UnexpectedTag,
39 IntegerNotMinimal,
41 IntegerEmpty,
43 MalformedOid,
45 MalformedBitString,
48 MalformedBoolean,
50 MalformedNull,
52 MalformedReal,
56 LimitExceeded(Limit),
62 AllocatorExhausted,
64 CapacityOverflow,
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70#[non_exhaustive]
71pub enum Limit {
72 Depth,
74 Elements,
76 ElementLength,
78 Work,
80 Memory,
82}
83
84impl fmt::Display for Limit {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.write_str(match self {
87 Self::Depth => "nesting depth",
88 Self::Elements => "element count",
89 Self::ElementLength => "element length",
90 Self::Work => "work",
91 Self::Memory => "memory",
92 })
93 }
94}
95
96impl fmt::Display for ErrorCode {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 match self {
99 Self::UnexpectedEnd => {
100 f.write_str("element runs past the end of the one containing it")
101 }
102 Self::MalformedTag => f.write_str("malformed tag number"),
103 Self::TagTooLarge => f.write_str("tag number too large"),
104 Self::LengthNotMinimal => f.write_str("length not encoded in the fewest bytes"),
105 Self::LengthTooLarge => f.write_str("length too large"),
106 Self::OffsetTooLarge => f.write_str("offset too large for this window"),
107 Self::IndefiniteLengthNotAllowed => f.write_str("indefinite length not allowed here"),
108 Self::UnterminatedContents => f.write_str("indefinite length never terminated"),
109 Self::MalformedEndOfContents => f.write_str("end-of-contents with a length"),
110 Self::WrongConstruction => {
111 f.write_str("primitive and constructed are the wrong way round")
112 }
113 Self::UnexpectedTag => f.write_str("not the element expected here"),
114 Self::IntegerNotMinimal => f.write_str("integer has a redundant leading byte"),
115 Self::IntegerEmpty => f.write_str("integer has no content"),
116 Self::MalformedOid => f.write_str("malformed object identifier"),
117 Self::MalformedBitString => f.write_str("malformed bit string"),
118 Self::MalformedBoolean => f.write_str("malformed boolean"),
119 Self::MalformedNull => f.write_str("null with contents"),
120 Self::MalformedReal => f.write_str("malformed real"),
121 Self::LimitExceeded(limit) => write!(f, "{limit} budget spent"),
122 Self::AllocatorExhausted => f.write_str("allocator could not supply storage"),
123 Self::CapacityOverflow => f.write_str("storage capacity overflow"),
124 }
125 }
126}
127
128#[derive(Debug, Default, PartialEq, Eq)]
135pub struct Path {
136 indices: Option<OwnedVec<u32>>,
137 unavailable: Option<MemoryError>,
138}
139
140impl Path {
141 #[must_use]
143 pub fn indices(&self) -> &[u32] {
144 self.indices.as_deref().unwrap_or(&[])
145 }
146
147 #[must_use]
149 pub fn is_root(&self) -> bool {
150 self.unavailable.is_none() && self.indices().is_empty()
151 }
152
153 #[must_use]
155 pub fn unavailable(&self) -> Option<MemoryError> {
156 self.unavailable
157 }
158
159 pub(crate) fn missing(reason: MemoryError) -> Self {
160 Self {
161 indices: None,
162 unavailable: Some(reason),
163 }
164 }
165
166 pub(crate) fn try_copy_in(&self, memory: &Memory) -> core::result::Result<Self, MemoryError> {
167 Ok(Self {
168 indices: match &self.indices {
169 Some(indices) => {
170 let mut copy = memory.vector();
171 copy.try_extend_from_slice(indices)?;
172 Some(copy)
173 }
174 None => None,
175 },
176 unavailable: self.unavailable,
177 })
178 }
179
180 pub(crate) fn push(
181 &mut self,
182 memory: &Memory,
183 index: u32,
184 ) -> core::result::Result<(), MemoryError> {
185 self.indices
186 .get_or_insert_with(|| memory.vector())
187 .try_push(index)
188 }
189}
190
191impl fmt::Display for Path {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 if let Some(reason) = self.unavailable {
194 return write!(f, "path unavailable: {reason}");
195 }
196 if self.indices().is_empty() {
197 return f.write_str("/");
198 }
199 for index in self.indices() {
200 write!(f, "/{index}")?;
201 }
202 Ok(())
203 }
204}
205
206#[derive(Debug, PartialEq, Eq)]
208pub struct Error {
209 code: ErrorCode,
210 offset: u64,
211 path: Path,
212}
213
214impl Error {
215 pub(crate) fn new(code: ErrorCode, offset: u64, path: Path) -> Self {
216 Self { code, offset, path }
217 }
218
219 #[must_use]
221 pub fn resource(reason: MemoryError, offset: u64) -> Self {
222 Self::new(ErrorCode::from(reason), offset, Path::missing(reason))
223 }
224
225 #[must_use]
227 pub fn code(&self) -> ErrorCode {
228 self.code
229 }
230
231 #[must_use]
234 pub fn offset(&self) -> u64 {
235 self.offset
236 }
237
238 #[must_use]
240 pub fn path(&self) -> &Path {
241 &self.path
242 }
243
244 #[must_use]
246 pub fn is_limit(&self) -> bool {
247 matches!(
251 self.code,
252 ErrorCode::LimitExceeded(_) | ErrorCode::TagTooLarge
253 )
254 }
255
256 #[must_use]
258 pub fn is_resource(&self) -> bool {
259 self.is_limit()
260 || matches!(
261 self.code,
262 ErrorCode::AllocatorExhausted | ErrorCode::CapacityOverflow
263 )
264 }
265}
266
267impl From<MemoryError> for ErrorCode {
268 fn from(reason: MemoryError) -> Self {
269 match reason {
270 MemoryError::LimitExceeded => Self::LimitExceeded(Limit::Memory),
271 MemoryError::WorkExceeded => Self::LimitExceeded(Limit::Work),
272 MemoryError::OutOfMemory => Self::AllocatorExhausted,
273 MemoryError::CapacityOverflow => Self::CapacityOverflow,
274 }
275 }
276}
277
278impl fmt::Display for Error {
279 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280 write!(f, "{} at {} ({})", self.code, self.offset, self.path)
281 }
282}
283
284#[cfg(feature = "std")]
285impl std::error::Error for Error {}
286
287pub type Result<T> = core::result::Result<T, Error>;
289
290#[cfg(test)]
291mod tests;