winnow/stream/
recoverable.rs

1use crate::error::FromRecoverableError;
2use crate::error::Needed;
3use crate::stream::AsBStr;
4use crate::stream::AsBytes;
5use crate::stream::Checkpoint;
6use crate::stream::Compare;
7use crate::stream::CompareResult;
8use crate::stream::FindSlice;
9use crate::stream::Location;
10use crate::stream::Offset;
11#[cfg(feature = "unstable-recover")]
12#[cfg(feature = "std")]
13use crate::stream::Recover;
14use crate::stream::SliceLen;
15use crate::stream::Stream;
16use crate::stream::StreamIsPartial;
17use crate::stream::UpdateSlice;
18
19/// Allow recovering from parse errors, capturing them as the parser continues
20///
21/// Generally, this will be used indirectly via
22/// [`RecoverableParser::recoverable_parse`][crate::RecoverableParser::recoverable_parse].
23#[derive(Clone, Debug)]
24pub struct Recoverable<I, E>
25where
26    I: Stream,
27{
28    input: I,
29    errors: Vec<E>,
30    is_recoverable: bool,
31}
32
33impl<I, E> Default for Recoverable<I, E>
34where
35    I: Default + Stream,
36{
37    #[inline]
38    fn default() -> Self {
39        Self::new(I::default())
40    }
41}
42
43impl<I, E> Recoverable<I, E>
44where
45    I: Stream,
46{
47    /// Track recoverable errors with the stream
48    #[inline]
49    pub fn new(input: I) -> Self {
50        Self {
51            input,
52            errors: Default::default(),
53            is_recoverable: true,
54        }
55    }
56
57    /// Act as a normal stream
58    #[inline]
59    pub fn unrecoverable(input: I) -> Self {
60        Self {
61            input,
62            errors: Default::default(),
63            is_recoverable: false,
64        }
65    }
66
67    /// Access the current input and errors
68    #[inline]
69    pub fn into_parts(self) -> (I, Vec<E>) {
70        (self.input, self.errors)
71    }
72}
73
74impl<I, E> AsRef<I> for Recoverable<I, E>
75where
76    I: Stream,
77{
78    #[inline(always)]
79    fn as_ref(&self) -> &I {
80        &self.input
81    }
82}
83
84impl<I, E> crate::lib::std::ops::Deref for Recoverable<I, E>
85where
86    I: Stream,
87{
88    type Target = I;
89
90    #[inline(always)]
91    fn deref(&self) -> &Self::Target {
92        &self.input
93    }
94}
95
96impl<I: crate::lib::std::fmt::Display, E> crate::lib::std::fmt::Display for Recoverable<I, E>
97where
98    I: Stream,
99{
100    fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
101        crate::lib::std::fmt::Display::fmt(&self.input, f)
102    }
103}
104
105impl<I, E> SliceLen for Recoverable<I, E>
106where
107    I: SliceLen,
108    I: Stream,
109{
110    #[inline(always)]
111    fn slice_len(&self) -> usize {
112        self.input.slice_len()
113    }
114}
115
116impl<I, E: crate::lib::std::fmt::Debug> Stream for Recoverable<I, E>
117where
118    I: Stream,
119{
120    type Token = <I as Stream>::Token;
121    type Slice = <I as Stream>::Slice;
122
123    type IterOffsets = <I as Stream>::IterOffsets;
124
125    type Checkpoint = Checkpoint<I::Checkpoint, Self>;
126
127    #[inline(always)]
128    fn iter_offsets(&self) -> Self::IterOffsets {
129        self.input.iter_offsets()
130    }
131    #[inline(always)]
132    fn eof_offset(&self) -> usize {
133        self.input.eof_offset()
134    }
135
136    #[inline(always)]
137    fn next_token(&mut self) -> Option<Self::Token> {
138        self.input.next_token()
139    }
140
141    #[inline(always)]
142    fn peek_token(&self) -> Option<Self::Token> {
143        self.input.peek_token()
144    }
145
146    #[inline(always)]
147    fn offset_for<P>(&self, predicate: P) -> Option<usize>
148    where
149        P: Fn(Self::Token) -> bool,
150    {
151        self.input.offset_for(predicate)
152    }
153    #[inline(always)]
154    fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
155        self.input.offset_at(tokens)
156    }
157    #[inline(always)]
158    fn next_slice(&mut self, offset: usize) -> Self::Slice {
159        self.input.next_slice(offset)
160    }
161    #[inline(always)]
162    fn peek_slice(&self, offset: usize) -> Self::Slice {
163        self.input.peek_slice(offset)
164    }
165
166    #[inline(always)]
167    fn checkpoint(&self) -> Self::Checkpoint {
168        Checkpoint::<_, Self>::new(self.input.checkpoint())
169    }
170    #[inline(always)]
171    fn reset(&mut self, checkpoint: &Self::Checkpoint) {
172        self.input.reset(&checkpoint.inner);
173    }
174
175    #[inline(always)]
176    fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
177        &self.input
178    }
179}
180
181impl<I, E> Location for Recoverable<I, E>
182where
183    I: Location,
184    I: Stream,
185{
186    #[inline(always)]
187    fn previous_token_end(&self) -> usize {
188        self.input.previous_token_end()
189    }
190    #[inline(always)]
191    fn current_token_start(&self) -> usize {
192        self.input.current_token_start()
193    }
194}
195
196impl<I, E, R> Recover<E> for Recoverable<I, R>
197where
198    I: Stream,
199    R: FromRecoverableError<Self, E>,
200    R: crate::lib::std::fmt::Debug,
201    E: crate::error::ParserError<Self>,
202{
203    fn record_err(
204        &mut self,
205        token_start: &Self::Checkpoint,
206        err_start: &Self::Checkpoint,
207        err: E,
208    ) -> Result<(), E> {
209        if self.is_recoverable {
210            if err.is_incomplete() {
211                Err(err)
212            } else {
213                self.errors
214                    .push(R::from_recoverable_error(token_start, err_start, self, err));
215                Ok(())
216            }
217        } else {
218            Err(err)
219        }
220    }
221
222    /// Report whether the [`Stream`] can save off errors for recovery
223    #[inline(always)]
224    fn is_recovery_supported() -> bool {
225        true
226    }
227}
228
229impl<I, E> StreamIsPartial for Recoverable<I, E>
230where
231    I: StreamIsPartial,
232    I: Stream,
233{
234    type PartialState = I::PartialState;
235
236    #[inline]
237    fn complete(&mut self) -> Self::PartialState {
238        self.input.complete()
239    }
240
241    #[inline]
242    fn restore_partial(&mut self, state: Self::PartialState) {
243        self.input.restore_partial(state);
244    }
245
246    #[inline(always)]
247    fn is_partial_supported() -> bool {
248        I::is_partial_supported()
249    }
250
251    #[inline(always)]
252    fn is_partial(&self) -> bool {
253        self.input.is_partial()
254    }
255}
256
257impl<I, E> Offset for Recoverable<I, E>
258where
259    I: Stream,
260    E: crate::lib::std::fmt::Debug,
261{
262    #[inline(always)]
263    fn offset_from(&self, other: &Self) -> usize {
264        self.offset_from(&other.checkpoint())
265    }
266}
267
268impl<I, E> Offset<<Recoverable<I, E> as Stream>::Checkpoint> for Recoverable<I, E>
269where
270    I: Stream,
271    E: crate::lib::std::fmt::Debug,
272{
273    #[inline(always)]
274    fn offset_from(&self, other: &<Recoverable<I, E> as Stream>::Checkpoint) -> usize {
275        self.checkpoint().offset_from(other)
276    }
277}
278
279impl<I, E> AsBytes for Recoverable<I, E>
280where
281    I: Stream,
282    I: AsBytes,
283{
284    #[inline(always)]
285    fn as_bytes(&self) -> &[u8] {
286        self.input.as_bytes()
287    }
288}
289
290impl<I, E> AsBStr for Recoverable<I, E>
291where
292    I: Stream,
293    I: AsBStr,
294{
295    #[inline(always)]
296    fn as_bstr(&self) -> &[u8] {
297        self.input.as_bstr()
298    }
299}
300
301impl<I, E, U> Compare<U> for Recoverable<I, E>
302where
303    I: Stream,
304    I: Compare<U>,
305{
306    #[inline(always)]
307    fn compare(&self, other: U) -> CompareResult {
308        self.input.compare(other)
309    }
310}
311
312impl<I, E, T> FindSlice<T> for Recoverable<I, E>
313where
314    I: Stream,
315    I: FindSlice<T>,
316{
317    #[inline(always)]
318    fn find_slice(&self, substr: T) -> Option<crate::lib::std::ops::Range<usize>> {
319        self.input.find_slice(substr)
320    }
321}
322
323impl<I, E> UpdateSlice for Recoverable<I, E>
324where
325    I: Stream,
326    I: UpdateSlice,
327    E: crate::lib::std::fmt::Debug,
328{
329    #[inline(always)]
330    fn update_slice(mut self, inner: Self::Slice) -> Self {
331        self.input = I::update_slice(self.input, inner);
332        self
333    }
334}