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#[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 #[inline]
49 pub fn new(input: I) -> Self {
50 Self {
51 input,
52 errors: Default::default(),
53 is_recoverable: true,
54 }
55 }
56
57 #[inline]
59 pub fn unrecoverable(input: I) -> Self {
60 Self {
61 input,
62 errors: Default::default(),
63 is_recoverable: false,
64 }
65 }
66
67 #[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> core::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: core::fmt::Display, E> core::fmt::Display for Recoverable<I, E>
97where
98 I: Stream,
99{
100 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
101 core::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: core::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 unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
163 unsafe { self.input.next_slice_unchecked(offset) }
165 }
166 #[inline(always)]
167 fn peek_slice(&self, offset: usize) -> Self::Slice {
168 self.input.peek_slice(offset)
169 }
170 #[inline(always)]
171 unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
172 unsafe { self.input.peek_slice_unchecked(offset) }
174 }
175
176 #[inline(always)]
177 fn checkpoint(&self) -> Self::Checkpoint {
178 Checkpoint::<_, Self>::new(self.input.checkpoint())
179 }
180 #[inline(always)]
181 fn reset(&mut self, checkpoint: &Self::Checkpoint) {
182 self.input.reset(&checkpoint.inner);
183 }
184
185 fn trace(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
186 self.input.trace(f)
187 }
188}
189
190impl<I, E> Location for Recoverable<I, E>
191where
192 I: Location,
193 I: Stream,
194{
195 #[inline(always)]
196 fn previous_token_end(&self) -> usize {
197 self.input.previous_token_end()
198 }
199 #[inline(always)]
200 fn current_token_start(&self) -> usize {
201 self.input.current_token_start()
202 }
203}
204
205impl<I, E, R> Recover<E> for Recoverable<I, R>
206where
207 I: Stream,
208 R: FromRecoverableError<Self, E>,
209 R: core::fmt::Debug,
210 E: crate::error::ParserError<Self>,
211{
212 fn record_err(
213 &mut self,
214 token_start: &Self::Checkpoint,
215 err_start: &Self::Checkpoint,
216 err: E,
217 ) -> Result<(), E> {
218 if self.is_recoverable {
219 if err.is_incomplete() {
220 Err(err)
221 } else {
222 self.errors
223 .push(R::from_recoverable_error(token_start, err_start, self, err));
224 Ok(())
225 }
226 } else {
227 Err(err)
228 }
229 }
230
231 #[inline(always)]
233 fn is_recovery_supported() -> bool {
234 true
235 }
236}
237
238impl<I, E> StreamIsPartial for Recoverable<I, E>
239where
240 I: StreamIsPartial,
241 I: Stream,
242{
243 type PartialState = I::PartialState;
244
245 #[inline]
246 fn complete(&mut self) -> Self::PartialState {
247 self.input.complete()
248 }
249
250 #[inline]
251 fn restore_partial(&mut self, state: Self::PartialState) {
252 self.input.restore_partial(state);
253 }
254
255 #[inline(always)]
256 fn is_partial_supported() -> bool {
257 I::is_partial_supported()
258 }
259
260 #[inline(always)]
261 fn is_partial(&self) -> bool {
262 self.input.is_partial()
263 }
264}
265
266impl<I, E> Offset for Recoverable<I, E>
267where
268 I: Stream,
269 E: core::fmt::Debug,
270{
271 #[inline(always)]
272 fn offset_from(&self, other: &Self) -> usize {
273 self.offset_from(&other.checkpoint())
274 }
275}
276
277impl<I, E> Offset<<Recoverable<I, E> as Stream>::Checkpoint> for Recoverable<I, E>
278where
279 I: Stream,
280 E: core::fmt::Debug,
281{
282 #[inline(always)]
283 fn offset_from(&self, other: &<Recoverable<I, E> as Stream>::Checkpoint) -> usize {
284 self.checkpoint().offset_from(other)
285 }
286}
287
288impl<I, E> AsBytes for Recoverable<I, E>
289where
290 I: Stream,
291 I: AsBytes,
292{
293 #[inline(always)]
294 fn as_bytes(&self) -> &[u8] {
295 self.input.as_bytes()
296 }
297}
298
299impl<I, E> AsBStr for Recoverable<I, E>
300where
301 I: Stream,
302 I: AsBStr,
303{
304 #[inline(always)]
305 fn as_bstr(&self) -> &[u8] {
306 self.input.as_bstr()
307 }
308}
309
310impl<I, E, U> Compare<U> for Recoverable<I, E>
311where
312 I: Stream,
313 I: Compare<U>,
314{
315 #[inline(always)]
316 fn compare(&self, other: U) -> CompareResult {
317 self.input.compare(other)
318 }
319}
320
321impl<I, E, T> FindSlice<T> for Recoverable<I, E>
322where
323 I: Stream,
324 I: FindSlice<T>,
325{
326 #[inline(always)]
327 fn find_slice(&self, substr: T) -> Option<core::ops::Range<usize>> {
328 self.input.find_slice(substr)
329 }
330}
331
332impl<I, E> UpdateSlice for Recoverable<I, E>
333where
334 I: Stream,
335 I: UpdateSlice,
336 E: core::fmt::Debug,
337{
338 #[inline(always)]
339 fn update_slice(mut self, inner: Self::Slice) -> Self {
340 self.input = I::update_slice(self.input, inner);
341 self
342 }
343}