use crate::error::FromRecoverableError; use crate::error::Needed; use crate::stream::AsBStr; use crate::stream::AsBytes; use crate::stream::Checkpoint; use crate::stream::Compare; use crate::stream::CompareResult; use crate::stream::FindSlice; use crate::stream::Location; use crate::stream::Offset; #[cfg(feature = "unstable-recover")] #[cfg(feature = "std")] use crate::stream::Recover; use crate::stream::SliceLen; use crate::stream::Stream; use crate::stream::StreamIsPartial; use crate::stream::UpdateSlice; /// Allow recovering from parse errors, capturing them as the parser continues /// /// Generally, this will be used indirectly via /// [`RecoverableParser::recoverable_parse`][crate::RecoverableParser::recoverable_parse]. #[derive(Clone, Debug)] pub struct Recoverable where I: Stream, { input: I, errors: Vec, is_recoverable: bool, } impl Default for Recoverable where I: Default + Stream, { #[inline] fn default() -> Self { Self::new(I::default()) } } impl Recoverable where I: Stream, { /// Track recoverable errors with the stream #[inline] pub fn new(input: I) -> Self { Self { input, errors: Default::default(), is_recoverable: true, } } /// Act as a normal stream #[inline] pub fn unrecoverable(input: I) -> Self { Self { input, errors: Default::default(), is_recoverable: false, } } /// Access the current input and errors #[inline] pub fn into_parts(self) -> (I, Vec) { (self.input, self.errors) } } impl AsRef for Recoverable where I: Stream, { #[inline(always)] fn as_ref(&self) -> &I { &self.input } } impl crate::lib::std::ops::Deref for Recoverable where I: Stream, { type Target = I; #[inline(always)] fn deref(&self) -> &Self::Target { &self.input } } impl crate::lib::std::fmt::Display for Recoverable where I: Stream, { fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result { crate::lib::std::fmt::Display::fmt(&self.input, f) } } impl SliceLen for Recoverable where I: SliceLen, I: Stream, { #[inline(always)] fn slice_len(&self) -> usize { self.input.slice_len() } } impl Stream for Recoverable where I: Stream, { type Token = ::Token; type Slice = ::Slice; type IterOffsets = ::IterOffsets; type Checkpoint = Checkpoint; #[inline(always)] fn iter_offsets(&self) -> Self::IterOffsets { self.input.iter_offsets() } #[inline(always)] fn eof_offset(&self) -> usize { self.input.eof_offset() } #[inline(always)] fn next_token(&mut self) -> Option { self.input.next_token() } #[inline(always)] fn peek_token(&self) -> Option { self.input.peek_token() } #[inline(always)] fn offset_for

(&self, predicate: P) -> Option where P: Fn(Self::Token) -> bool, { self.input.offset_for(predicate) } #[inline(always)] fn offset_at(&self, tokens: usize) -> Result { self.input.offset_at(tokens) } #[inline(always)] fn next_slice(&mut self, offset: usize) -> Self::Slice { self.input.next_slice(offset) } #[inline(always)] unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice { // SAFETY: Passing up invariants unsafe { self.input.next_slice_unchecked(offset) } } #[inline(always)] fn peek_slice(&self, offset: usize) -> Self::Slice { self.input.peek_slice(offset) } #[inline(always)] unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice { // SAFETY: Passing up invariants unsafe { self.input.peek_slice_unchecked(offset) } } #[inline(always)] fn checkpoint(&self) -> Self::Checkpoint { Checkpoint::<_, Self>::new(self.input.checkpoint()) } #[inline(always)] fn reset(&mut self, checkpoint: &Self::Checkpoint) { self.input.reset(&checkpoint.inner); } #[inline(always)] fn raw(&self) -> &dyn crate::lib::std::fmt::Debug { &self.input } } impl Location for Recoverable where I: Location, I: Stream, { #[inline(always)] fn previous_token_end(&self) -> usize { self.input.previous_token_end() } #[inline(always)] fn current_token_start(&self) -> usize { self.input.current_token_start() } } impl Recover for Recoverable where I: Stream, R: FromRecoverableError, R: crate::lib::std::fmt::Debug, E: crate::error::ParserError, { fn record_err( &mut self, token_start: &Self::Checkpoint, err_start: &Self::Checkpoint, err: E, ) -> Result<(), E> { if self.is_recoverable { if err.is_incomplete() { Err(err) } else { self.errors .push(R::from_recoverable_error(token_start, err_start, self, err)); Ok(()) } } else { Err(err) } } /// Report whether the [`Stream`] can save off errors for recovery #[inline(always)] fn is_recovery_supported() -> bool { true } } impl StreamIsPartial for Recoverable where I: StreamIsPartial, I: Stream, { type PartialState = I::PartialState; #[inline] fn complete(&mut self) -> Self::PartialState { self.input.complete() } #[inline] fn restore_partial(&mut self, state: Self::PartialState) { self.input.restore_partial(state); } #[inline(always)] fn is_partial_supported() -> bool { I::is_partial_supported() } #[inline(always)] fn is_partial(&self) -> bool { self.input.is_partial() } } impl Offset for Recoverable where I: Stream, E: crate::lib::std::fmt::Debug, { #[inline(always)] fn offset_from(&self, other: &Self) -> usize { self.offset_from(&other.checkpoint()) } } impl Offset< as Stream>::Checkpoint> for Recoverable where I: Stream, E: crate::lib::std::fmt::Debug, { #[inline(always)] fn offset_from(&self, other: & as Stream>::Checkpoint) -> usize { self.checkpoint().offset_from(other) } } impl AsBytes for Recoverable where I: Stream, I: AsBytes, { #[inline(always)] fn as_bytes(&self) -> &[u8] { self.input.as_bytes() } } impl AsBStr for Recoverable where I: Stream, I: AsBStr, { #[inline(always)] fn as_bstr(&self) -> &[u8] { self.input.as_bstr() } } impl Compare for Recoverable where I: Stream, I: Compare, { #[inline(always)] fn compare(&self, other: U) -> CompareResult { self.input.compare(other) } } impl FindSlice for Recoverable where I: Stream, I: FindSlice, { #[inline(always)] fn find_slice(&self, substr: T) -> Option> { self.input.find_slice(substr) } } impl UpdateSlice for Recoverable where I: Stream, I: UpdateSlice, E: crate::lib::std::fmt::Debug, { #[inline(always)] fn update_slice(mut self, inner: Self::Slice) -> Self { self.input = I::update_slice(self.input, inner); self } }