Skip to main content

vest_lib/core/exec/
error.rs

1//! Runtime parse errors.
2use core::fmt;
3
4#[cfg(feature = "alloc")]
5use alloc::vec::Vec;
6
7use vstd::prelude::*;
8
9verus! {
10
11/// A minimal runtime parser failure.
12///
13/// Vest parsers work on progressively sliced inputs, so a globally meaningful byte offset is not
14/// available unless the caller explicitly threads that information through the parser stack.
15/// Instead, this error carries a coarse-grained failure kind plus the names of the DSL-defined
16/// formats on the failing path, when that information is available.
17#[derive(Debug, PartialEq, Eq)]
18pub struct ParseError {
19    /// The kind of failure that occurred.
20    pub kind: ParseErrorKind,
21    /// The innermost named format known to have failed.
22    pub failed_format: Option<&'static str>,
23    /// The named-format call stack that led to the failure, stored innermost-first.
24    #[cfg(feature = "alloc")]
25    pub format_stack: Vec<&'static str>,
26}
27
28impl Clone for ParseError {
29    fn clone(&self) -> Self {
30        Self {
31            kind: self.kind.clone(),
32            failed_format: self.failed_format,
33            #[cfg(feature = "alloc")]
34            format_stack: self.format_stack.clone(),
35        }
36    }
37}
38
39impl ParseError {
40    /// Creates a new parse error.
41    pub fn new(kind: ParseErrorKind) -> (e: Self)
42        ensures
43            e.kind == kind,
44    {
45        Self {
46            kind,
47            failed_format: None,
48            #[cfg(feature = "alloc")]
49            format_stack: Vec::new(),
50        }
51    }
52
53    /// Pushes one named format onto the failing format stack.
54    ///
55    /// The first pushed format becomes `current_format`, so `current_format` continues to refer to
56    /// the innermost failing named format even as outer formats append themselves during
57    /// propagation.
58    pub fn push_format(self, current_format: &'static str) -> Self {
59        let mut err = self;
60        if err.failed_format.is_none() {
61            err.failed_format = Some(current_format);
62        }
63        #[cfg(feature = "alloc")]
64        {
65            err.format_stack.push(current_format);
66        }
67        err
68    }
69
70    /// Returns the recorded format stack as an innermost-first slice.
71    pub fn format_trace(&self) -> &[&'static str] {
72        #[cfg(feature = "alloc")]
73        { self.format_stack.as_slice() }
74        #[cfg(not(feature = "alloc"))]
75        { &[] }
76    }
77}
78
79impl ParseError {
80    /// Creates an unexpected end-of-input error.
81    pub fn unexpected_eof() -> (e: Self)
82        ensures
83            e.kind == ParseErrorKind::UnexpectedEof,
84    {
85        Self::new(ParseErrorKind::UnexpectedEof)
86    }
87
88    /// Creates an expecting end-of-input error.
89    pub fn expecting_eof() -> Self {
90        Self::new(ParseErrorKind::ExpectingEof)
91    }
92
93    /// Creates an invalid-tag error.
94    pub fn invalid_tag() -> Self {
95        Self::new(ParseErrorKind::InvalidTag)
96    }
97
98    /// Creates an invalid-choice error.
99    pub fn invalid_choice() -> Self {
100        Self::new(ParseErrorKind::InvalidChoice)
101    }
102
103    /// Creates an invalid-length error.
104    pub fn invalid_length() -> Self {
105        Self::new(ParseErrorKind::InvalidLength)
106    }
107
108    /// Creates a length-mismatch error.
109    pub fn length_mismatch() -> Self {
110        Self::new(ParseErrorKind::LengthMismatch)
111    }
112
113    /// Creates a predicate-failed error.
114    pub fn predicate_failed() -> Self {
115        Self::new(ParseErrorKind::PredicateFailed)
116    }
117
118    /// Creates a condition-rejected error.
119    pub fn cond_rejected() -> Self {
120        Self::new(ParseErrorKind::CondRejected)
121    }
122
123    /// Creates a non-canonical-encoding error.
124    pub fn non_canonical() -> Self {
125        Self::new(ParseErrorKind::NonCanonical)
126    }
127
128    /// Creates an overflow error.
129    pub fn overflow() -> (e: Self)
130        ensures
131            e.kind == ParseErrorKind::Overflow,
132    {
133        Self::new(ParseErrorKind::Overflow)
134    }
135
136    /// Creates a recursion-limit-exceeded error.
137    pub fn recursion_limit_exceeded() -> Self {
138        Self::new(ParseErrorKind::RecursionLimitExceeded)
139    }
140
141    /// Creates a custom error with the given message.
142    pub fn custom(msg: &'static str) -> Self {
143        Self::new(ParseErrorKind::Custom(msg))
144    }
145}
146
147} // verus!
148impl fmt::Display for ParseError {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        let format_trace = self.format_trace();
151        if !format_trace.is_empty() {
152            write!(f, "{} while parsing format stack ", self.kind)?;
153            for (i, format_name) in format_trace.iter().rev().enumerate() {
154                if i > 0 {
155                    f.write_str(" -> ")?;
156                }
157                write!(f, "`{}`", format_name)?;
158            }
159            Ok(())
160        } else {
161            match self.failed_format {
162                Some(current_format) => {
163                    write!(f, "{} while parsing format `{}`", self.kind, current_format)
164                }
165                None => write!(f, "{}", self.kind),
166            }
167        }
168    }
169}
170
171#[cfg(feature = "std")]
172impl std::error::Error for ParseError {}
173
174verus! {
175
176/// The coarse-grained kind of parse failure.
177#[derive(Debug, Copy, PartialEq, Eq)]
178pub enum ParseErrorKind {
179    /// The parser needed more input bytes.
180    UnexpectedEof,
181    /// The parser expected the end of input, but more bytes were present.
182    ExpectingEof,
183    /// A tag or discriminant byte sequence was invalid.
184    InvalidTag,
185    /// Input did not match any branch of a choice-like format.
186    InvalidChoice,
187    /// A parsed length field was invalid.
188    InvalidLength,
189    /// A computed length disagreed with the enclosing format.
190    LengthMismatch,
191    /// A refinement predicate or semantic check failed.
192    PredicateFailed,
193    /// A branch was rejected after partial inspection.
194    CondRejected,
195    /// A non-canonical representation was observed.
196    NonCanonical,
197    /// An integer or size computation overflowed.
198    Overflow,
199    /// Recursion limit exceeded.
200    RecursionLimitExceeded,
201    /// A custom error message.
202    Custom(&'static str),
203}
204
205impl Clone for ParseErrorKind {
206    fn clone(&self) -> Self {
207        *self
208    }
209}
210
211} // verus!
212impl fmt::Display for ParseErrorKind {
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        match self {
215            ParseErrorKind::UnexpectedEof => {
216                f.write_str("input ended before the format could finish parsing")
217            }
218            ParseErrorKind::ExpectingEof => f.write_str("unexpected trailing input"),
219            ParseErrorKind::InvalidTag => {
220                f.write_str("tag or discriminant did not match the format")
221            }
222            ParseErrorKind::InvalidChoice => f.write_str("input did not match any choice branch"),
223            ParseErrorKind::InvalidLength => {
224                f.write_str("length field is outside the format's valid range")
225            }
226            ParseErrorKind::LengthMismatch => {
227                f.write_str("a length-delimited parser did not consume the declared length")
228            }
229            ParseErrorKind::PredicateFailed => {
230                f.write_str("parsed value failed a refinement predicate")
231            }
232            ParseErrorKind::CondRejected => f.write_str("conditional format rejected this branch"),
233            ParseErrorKind::NonCanonical => f.write_str("non-canonical encoding"),
234            ParseErrorKind::Overflow => f.write_str("integer or size computation overflowed"),
235            ParseErrorKind::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
236            ParseErrorKind::Custom(s) => f.write_str(s),
237        }
238    }
239}