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 copy_work(&self, additional: usize) -> core::result::Result<u64, MemoryError> {
184 let length = self.indices().len() as u64;
185 let additional = additional as u64;
186 let target = length
187 .checked_add(additional)
188 .ok_or(MemoryError::WorkExceeded)?;
189 let mut work = length
191 .checked_mul(8)
192 .and_then(|work| work.checked_add(additional))
193 .ok_or(MemoryError::WorkExceeded)?;
194 let mut capacity = length;
195 while capacity < target {
199 let next = capacity
200 .checked_mul(2)
201 .ok_or(MemoryError::WorkExceeded)?
202 .max(4);
203 work = next
204 .checked_add(capacity)
205 .and_then(|bytes| bytes.checked_mul(4))
206 .and_then(|bytes| work.checked_add(bytes))
207 .ok_or(MemoryError::WorkExceeded)?;
208 capacity = next;
209 }
210 Ok(work)
211 }
212
213 pub(crate) fn push(
214 &mut self,
215 memory: &Memory,
216 index: u32,
217 ) -> core::result::Result<(), MemoryError> {
218 self.indices
219 .get_or_insert_with(|| memory.vector())
220 .try_push(index)
221 }
222}
223
224impl fmt::Display for Path {
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226 if let Some(reason) = self.unavailable {
227 return write!(f, "path unavailable: {reason}");
228 }
229 if self.indices().is_empty() {
230 return f.write_str("/");
231 }
232 for index in self.indices() {
233 write!(f, "/{index}")?;
234 }
235 Ok(())
236 }
237}
238
239#[derive(Debug, PartialEq, Eq)]
241pub struct Error {
242 code: ErrorCode,
243 offset: u64,
244 path: Path,
245}
246
247impl Error {
248 pub(crate) fn new(code: ErrorCode, offset: u64, path: Path) -> Self {
249 Self { code, offset, path }
250 }
251
252 #[must_use]
254 pub fn resource(reason: MemoryError, offset: u64) -> Self {
255 Self::new(ErrorCode::from(reason), offset, Path::missing(reason))
256 }
257
258 #[must_use]
260 pub fn code(&self) -> ErrorCode {
261 self.code
262 }
263
264 #[must_use]
267 pub fn offset(&self) -> u64 {
268 self.offset
269 }
270
271 #[must_use]
273 pub fn path(&self) -> &Path {
274 &self.path
275 }
276
277 #[must_use]
279 pub fn is_limit(&self) -> bool {
280 matches!(
284 self.code,
285 ErrorCode::LimitExceeded(_) | ErrorCode::TagTooLarge
286 )
287 }
288
289 #[must_use]
291 pub fn is_resource(&self) -> bool {
292 self.is_limit()
293 || matches!(
294 self.code,
295 ErrorCode::AllocatorExhausted | ErrorCode::CapacityOverflow
296 )
297 }
298}
299
300impl From<MemoryError> for ErrorCode {
301 fn from(reason: MemoryError) -> Self {
302 match reason {
303 MemoryError::LimitExceeded => Self::LimitExceeded(Limit::Memory),
304 MemoryError::WorkExceeded => Self::LimitExceeded(Limit::Work),
305 MemoryError::OutOfMemory => Self::AllocatorExhausted,
306 MemoryError::CapacityOverflow => Self::CapacityOverflow,
307 }
308 }
309}
310
311impl fmt::Display for Error {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 write!(f, "{} at {} ({})", self.code, self.offset, self.path)
314 }
315}
316
317#[cfg(feature = "std")]
318impl std::error::Error for Error {}
319
320pub type Result<T> = core::result::Result<T, Error>;
322
323#[cfg(test)]
324mod tests;