winnow/
error.rs

1//! # Error management
2//!
3//! Errors are designed with multiple needs in mind:
4//! - Accumulate more [context][Parser::context] as the error goes up the parser chain
5//! - Distinguish between [recoverable errors,
6//!   unrecoverable errors, and more data is needed][ErrMode]
7//! - Have a very low overhead, as errors are often discarded by the calling parser (examples: `repeat`, `alt`)
8//! - Can be modified according to the user's needs, because some languages need a lot more information
9//! - Help thread-through the [stream][crate::stream]
10//!
11//! To abstract these needs away from the user, generally `winnow` parsers use the [`ModalResult`]
12//! alias, rather than [`Result`].  [`Parser::parse`] is a top-level operation
13//! that can help convert to a `Result` for integrating with your application's error reporting.
14//!
15//! Error types include:
16//! - [`EmptyError`] when the reason for failure doesn't matter
17//! - [`ContextError`]
18//! - [`InputError`] (mostly for testing)
19//! - [`TreeError`] (mostly for testing)
20//! - [Custom errors][crate::_topic::error]
21
22#[cfg(feature = "alloc")]
23use alloc::borrow::ToOwned;
24use core::fmt;
25
26#[cfg(feature = "binary")]
27use crate::binary::bits::Bits;
28use crate::stream::AsBStr;
29use crate::stream::Stream;
30#[allow(unused_imports)] // Here for intra-doc links
31use crate::Parser;
32
33pub use crate::stream::Needed;
34
35/// By default, the error type (`E`) is [`ContextError`].
36///
37/// When integrating into the result of the application, see
38/// - [`Parser::parse`]
39/// - [`ParserError::into_inner`]
40pub type Result<O, E = ContextError> = core::result::Result<O, E>;
41
42/// [Modal error reporting][ErrMode] for [`Parser::parse_next`]
43///
44/// - `Ok(O)` is the parsed value
45/// - [`Err(ErrMode<E>)`][ErrMode] is the error along with how to respond to it
46///
47/// By default, the error type (`E`) is [`ContextError`].
48///
49/// When integrating into the result of the application, see
50/// - [`Parser::parse`]
51/// - [`ParserError::into_inner`]
52pub type ModalResult<O, E = ContextError> = Result<O, ErrMode<E>>;
53
54#[cfg(test)]
55pub(crate) type TestResult<I, O> = ModalResult<O, InputError<I>>;
56
57/// Add parse error state to [`ParserError`]s
58///
59/// Needed for
60/// - [`Partial`][crate::stream::Partial] to track whether the [`Stream`] is [`ErrMode::Incomplete`].
61///   See also [`crate::_topic::partial`]
62/// - Marking errors as unrecoverable ([`ErrMode::Cut`]) and not retrying alternative parsers.
63///   See also [`crate::_tutorial::chapter_7#error-cuts`]
64#[derive(Debug, Clone, PartialEq)]
65pub enum ErrMode<E> {
66    /// There was not enough data to determine the appropriate action
67    ///
68    /// More data needs to be buffered before retrying the parse.
69    ///
70    /// This must only be set when the [`Stream`] is [partial][`crate::stream::StreamIsPartial`], like with
71    /// [`Partial`][crate::Partial]
72    ///
73    /// Convert this into an `Backtrack` with [`Parser::complete_err`]
74    Incomplete(Needed),
75    /// The parser failed with a recoverable error (the default).
76    ///
77    /// For example, a parser for json values might include a
78    /// [`dec_uint`][crate::ascii::dec_uint] as one case in an [`alt`][crate::combinator::alt]
79    /// combinator. If it fails, the next case should be tried.
80    Backtrack(E),
81    /// The parser had an unrecoverable error.
82    ///
83    /// The parser was on the right branch, so directly report it to the user rather than trying
84    /// other branches. You can use [`cut_err()`][crate::combinator::cut_err] combinator to switch
85    /// from `ErrMode::Backtrack` to `ErrMode::Cut`.
86    ///
87    /// For example, one case in an [`alt`][crate::combinator::alt] combinator found a unique prefix
88    /// and you want any further errors parsing the case to be reported to the user.
89    Cut(E),
90}
91
92impl<E> ErrMode<E> {
93    /// Tests if the result is Incomplete
94    #[inline]
95    pub fn is_incomplete(&self) -> bool {
96        matches!(self, ErrMode::Incomplete(_))
97    }
98
99    /// Prevent backtracking, bubbling the error up to the top
100    pub fn cut(self) -> Self {
101        match self {
102            ErrMode::Backtrack(e) => ErrMode::Cut(e),
103            rest => rest,
104        }
105    }
106
107    /// Enable backtracking support
108    pub fn backtrack(self) -> Self {
109        match self {
110            ErrMode::Cut(e) => ErrMode::Backtrack(e),
111            rest => rest,
112        }
113    }
114
115    /// Applies the given function to the inner error
116    pub fn map<E2, F>(self, f: F) -> ErrMode<E2>
117    where
118        F: FnOnce(E) -> E2,
119    {
120        match self {
121            ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
122            ErrMode::Cut(t) => ErrMode::Cut(f(t)),
123            ErrMode::Backtrack(t) => ErrMode::Backtrack(f(t)),
124        }
125    }
126
127    /// Automatically converts between errors if the underlying type supports it
128    pub fn convert<F>(self) -> ErrMode<F>
129    where
130        E: ErrorConvert<F>,
131    {
132        ErrorConvert::convert(self)
133    }
134
135    /// Unwrap the mode, returning the underlying error
136    ///
137    /// Returns `Err(self)` for [`ErrMode::Incomplete`]
138    #[inline(always)]
139    pub fn into_inner(self) -> Result<E, Self> {
140        match self {
141            ErrMode::Backtrack(e) | ErrMode::Cut(e) => Ok(e),
142            err @ ErrMode::Incomplete(_) => Err(err),
143        }
144    }
145}
146
147impl<I: Stream, E: ParserError<I>> ParserError<I> for ErrMode<E> {
148    type Inner = E;
149
150    #[inline(always)]
151    fn from_input(input: &I) -> Self {
152        ErrMode::Backtrack(E::from_input(input))
153    }
154
155    #[inline(always)]
156    fn assert(input: &I, message: &'static str) -> Self
157    where
158        I: core::fmt::Debug,
159    {
160        ErrMode::Cut(E::assert(input, message))
161    }
162
163    #[inline(always)]
164    fn incomplete(_input: &I, needed: Needed) -> Self {
165        ErrMode::Incomplete(needed)
166    }
167
168    #[inline]
169    fn append(self, input: &I, token_start: &<I as Stream>::Checkpoint) -> Self {
170        match self {
171            ErrMode::Backtrack(e) => ErrMode::Backtrack(e.append(input, token_start)),
172            e => e,
173        }
174    }
175
176    fn or(self, other: Self) -> Self {
177        match (self, other) {
178            (ErrMode::Backtrack(e), ErrMode::Backtrack(o)) => ErrMode::Backtrack(e.or(o)),
179            (ErrMode::Incomplete(e), _) | (_, ErrMode::Incomplete(e)) => ErrMode::Incomplete(e),
180            (ErrMode::Cut(e), _) | (_, ErrMode::Cut(e)) => ErrMode::Cut(e),
181        }
182    }
183
184    #[inline(always)]
185    fn is_backtrack(&self) -> bool {
186        matches!(self, ErrMode::Backtrack(_))
187    }
188
189    #[inline(always)]
190    fn into_inner(self) -> Result<Self::Inner, Self> {
191        match self {
192            ErrMode::Backtrack(e) | ErrMode::Cut(e) => Ok(e),
193            err @ ErrMode::Incomplete(_) => Err(err),
194        }
195    }
196
197    #[inline(always)]
198    fn is_incomplete(&self) -> bool {
199        matches!(self, ErrMode::Incomplete(_))
200    }
201
202    #[inline(always)]
203    fn needed(&self) -> Option<Needed> {
204        match self {
205            ErrMode::Incomplete(needed) => Some(*needed),
206            _ => None,
207        }
208    }
209}
210
211impl<E> ModalError for ErrMode<E> {
212    fn cut(self) -> Self {
213        self.cut()
214    }
215
216    fn backtrack(self) -> Self {
217        self.backtrack()
218    }
219}
220
221impl<E1, E2> ErrorConvert<ErrMode<E2>> for ErrMode<E1>
222where
223    E1: ErrorConvert<E2>,
224{
225    #[inline(always)]
226    fn convert(self) -> ErrMode<E2> {
227        self.map(|e| e.convert())
228    }
229}
230
231impl<I, EXT, E> FromExternalError<I, EXT> for ErrMode<E>
232where
233    E: FromExternalError<I, EXT>,
234{
235    #[inline(always)]
236    fn from_external_error(input: &I, e: EXT) -> Self {
237        ErrMode::Backtrack(E::from_external_error(input, e))
238    }
239}
240
241impl<I: Stream, C, E: AddContext<I, C>> AddContext<I, C> for ErrMode<E> {
242    #[inline(always)]
243    fn add_context(self, input: &I, token_start: &<I as Stream>::Checkpoint, context: C) -> Self {
244        self.map(|err| err.add_context(input, token_start, context))
245    }
246}
247
248#[cfg(feature = "unstable-recover")]
249#[cfg(feature = "std")]
250impl<I: Stream, E1: FromRecoverableError<I, E2>, E2> FromRecoverableError<I, ErrMode<E2>>
251    for ErrMode<E1>
252{
253    #[inline]
254    fn from_recoverable_error(
255        token_start: &<I as Stream>::Checkpoint,
256        err_start: &<I as Stream>::Checkpoint,
257        input: &I,
258        e: ErrMode<E2>,
259    ) -> Self {
260        e.map(|e| E1::from_recoverable_error(token_start, err_start, input, e))
261    }
262}
263
264impl<T: Clone> ErrMode<InputError<T>> {
265    /// Maps `ErrMode<InputError<T>>` to `ErrMode<InputError<U>>` with the given `F: T -> U`
266    pub fn map_input<U: Clone, F>(self, f: F) -> ErrMode<InputError<U>>
267    where
268        F: FnOnce(T) -> U,
269    {
270        match self {
271            ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
272            ErrMode::Cut(InputError { input }) => ErrMode::Cut(InputError { input: f(input) }),
273            ErrMode::Backtrack(InputError { input }) => {
274                ErrMode::Backtrack(InputError { input: f(input) })
275            }
276        }
277    }
278}
279
280impl<E: Eq> Eq for ErrMode<E> {}
281
282impl<E> fmt::Display for ErrMode<E>
283where
284    E: fmt::Debug,
285{
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        match self {
288            ErrMode::Incomplete(Needed::Size(u)) => write!(f, "Parsing requires {u} more data"),
289            ErrMode::Incomplete(Needed::Unknown) => write!(f, "Parsing requires more data"),
290            ErrMode::Cut(c) => write!(f, "Parsing Failure: {c:?}"),
291            ErrMode::Backtrack(c) => write!(f, "Parsing Error: {c:?}"),
292        }
293    }
294}
295
296/// The basic [`Parser`] trait for errors
297///
298/// It provides methods to create an error from some combinators,
299/// and combine existing errors in combinators like `alt`.
300pub trait ParserError<I: Stream>: Sized {
301    /// Generally, `Self`
302    ///
303    /// Mostly used for [`ErrMode`]
304    type Inner;
305
306    /// Creates an error from the input position
307    fn from_input(input: &I) -> Self;
308
309    /// Process a parser assertion
310    #[inline(always)]
311    fn assert(input: &I, _message: &'static str) -> Self
312    where
313        I: core::fmt::Debug,
314    {
315        #[cfg(debug_assertions)]
316        panic!("assert `{_message}` failed at {input:#?}");
317        #[cfg(not(debug_assertions))]
318        Self::from_input(input)
319    }
320
321    /// There was not enough data to determine the appropriate action
322    ///
323    /// More data needs to be buffered before retrying the parse.
324    ///
325    /// This must only be set when the [`Stream`] is [partial][`crate::stream::StreamIsPartial`], like with
326    /// [`Partial`][crate::Partial]
327    ///
328    /// Convert this into an `Backtrack` with [`Parser::complete_err`]
329    #[inline(always)]
330    fn incomplete(input: &I, _needed: Needed) -> Self {
331        Self::from_input(input)
332    }
333
334    /// Like [`ParserError::from_input`] but merges it with the existing error.
335    ///
336    /// This is useful when backtracking through a parse tree, accumulating error context on the
337    /// way.
338    #[inline]
339    fn append(self, _input: &I, _token_start: &<I as Stream>::Checkpoint) -> Self {
340        self
341    }
342
343    /// Combines errors from two different parse branches.
344    ///
345    /// For example, this would be used by [`alt`][crate::combinator::alt] to report the error from
346    /// each case.
347    #[inline]
348    fn or(self, other: Self) -> Self {
349        other
350    }
351
352    /// Is backtracking and trying new parse branches allowed?
353    #[inline(always)]
354    fn is_backtrack(&self) -> bool {
355        true
356    }
357
358    /// Unwrap the mode, returning the underlying error, if present
359    fn into_inner(self) -> Result<Self::Inner, Self>;
360
361    /// Is more data [`Needed`]
362    ///
363    /// This must be the same as [`err.needed().is_some()`][ParserError::needed]
364    #[inline(always)]
365    fn is_incomplete(&self) -> bool {
366        false
367    }
368
369    /// Extract the [`Needed`] data, if present
370    ///
371    /// `Self::needed().is_some()` must be the same as
372    /// [`err.is_incomplete()`][ParserError::is_incomplete]
373    #[inline(always)]
374    fn needed(&self) -> Option<Needed> {
375        None
376    }
377}
378
379/// Manipulate the how parsers respond to this error
380pub trait ModalError {
381    /// Prevent backtracking, bubbling the error up to the top
382    fn cut(self) -> Self;
383    /// Enable backtracking support
384    fn backtrack(self) -> Self;
385}
386
387/// Used by [`Parser::context`] to add custom data to error while backtracking
388///
389/// May be implemented multiple times for different kinds of context.
390pub trait AddContext<I: Stream, C = &'static str>: Sized {
391    /// Append to an existing error custom data
392    ///
393    /// This is used mainly by [`Parser::context`], to add user friendly information
394    /// to errors when backtracking through a parse tree
395    #[inline]
396    fn add_context(
397        self,
398        _input: &I,
399        _token_start: &<I as Stream>::Checkpoint,
400        _context: C,
401    ) -> Self {
402        self
403    }
404}
405
406/// Capture context from when an error was recovered
407#[cfg(feature = "unstable-recover")]
408#[cfg(feature = "std")]
409pub trait FromRecoverableError<I: Stream, E> {
410    /// Capture context from when an error was recovered
411    fn from_recoverable_error(
412        token_start: &<I as Stream>::Checkpoint,
413        err_start: &<I as Stream>::Checkpoint,
414        input: &I,
415        e: E,
416    ) -> Self;
417}
418
419/// Create a new error with an external error, from [`std::str::FromStr`]
420///
421/// This trait is required by the [`Parser::try_map`] combinator.
422pub trait FromExternalError<I, E> {
423    /// Like [`ParserError::from_input`] but also include an external error.
424    fn from_external_error(input: &I, e: E) -> Self;
425}
426
427/// Equivalent of `From` implementation to avoid orphan rules in bits parsers
428pub trait ErrorConvert<E> {
429    /// Transform to another error type
430    fn convert(self) -> E;
431}
432
433/// Capture input on error
434///
435/// This is useful for testing of generic parsers to ensure the error happens at the right
436/// location.
437///
438/// <div class="warning">
439///
440/// **Note:** [context][Parser::context] and inner errors (like from [`Parser::try_map`]) will be
441/// dropped.
442///
443/// </div>
444#[derive(Copy, Clone, Debug, Eq, PartialEq)]
445pub struct InputError<I: Clone> {
446    /// The input stream, pointing to the location where the error occurred
447    pub input: I,
448}
449
450impl<I: Clone> InputError<I> {
451    /// Creates a new basic error
452    #[inline]
453    pub fn at(input: I) -> Self {
454        Self { input }
455    }
456
457    /// Translate the input type
458    #[inline]
459    pub fn map_input<I2: Clone, O: Fn(I) -> I2>(self, op: O) -> InputError<I2> {
460        InputError {
461            input: op(self.input),
462        }
463    }
464}
465
466#[cfg(feature = "alloc")]
467impl<I: ToOwned> InputError<&I>
468where
469    <I as ToOwned>::Owned: Clone,
470{
471    /// Obtaining ownership
472    pub fn into_owned(self) -> InputError<<I as ToOwned>::Owned> {
473        self.map_input(ToOwned::to_owned)
474    }
475}
476
477impl<I: Stream + Clone> ParserError<I> for InputError<I> {
478    type Inner = Self;
479
480    #[inline]
481    fn from_input(input: &I) -> Self {
482        Self {
483            input: input.clone(),
484        }
485    }
486
487    #[inline(always)]
488    fn into_inner(self) -> Result<Self::Inner, Self> {
489        Ok(self)
490    }
491}
492
493impl<I: Stream + Clone, C> AddContext<I, C> for InputError<I> {}
494
495#[cfg(feature = "unstable-recover")]
496#[cfg(feature = "std")]
497impl<I: Clone + Stream> FromRecoverableError<I, Self> for InputError<I> {
498    #[inline]
499    fn from_recoverable_error(
500        _token_start: &<I as Stream>::Checkpoint,
501        _err_start: &<I as Stream>::Checkpoint,
502        _input: &I,
503        e: Self,
504    ) -> Self {
505        e
506    }
507}
508
509impl<I: Clone, E> FromExternalError<I, E> for InputError<I> {
510    /// Create a new error from an input position and an external error
511    #[inline]
512    fn from_external_error(input: &I, _e: E) -> Self {
513        Self {
514            input: input.clone(),
515        }
516    }
517}
518
519/// The Display implementation allows the `std::error::Error` implementation
520impl<I: Clone + fmt::Display> fmt::Display for InputError<I> {
521    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522        write!(f, "failed to parse starting at: {}", self.input)
523    }
524}
525
526#[cfg(feature = "std")]
527impl<I: Clone + fmt::Debug + fmt::Display + Sync + Send + 'static> std::error::Error
528    for InputError<I>
529{
530}
531
532/// Track an error occurred without any other [`StrContext`]
533#[derive(Copy, Clone, Debug, Eq, PartialEq)]
534pub struct EmptyError;
535
536impl<I: Stream> ParserError<I> for EmptyError {
537    type Inner = Self;
538
539    #[inline(always)]
540    fn from_input(_: &I) -> Self {
541        Self
542    }
543
544    #[inline(always)]
545    fn into_inner(self) -> Result<Self::Inner, Self> {
546        Ok(self)
547    }
548}
549
550impl<I: Stream, C> AddContext<I, C> for EmptyError {}
551
552#[cfg(feature = "unstable-recover")]
553#[cfg(feature = "std")]
554impl<I: Stream> FromRecoverableError<I, Self> for EmptyError {
555    #[inline(always)]
556    fn from_recoverable_error(
557        _token_start: &<I as Stream>::Checkpoint,
558        _err_start: &<I as Stream>::Checkpoint,
559        _input: &I,
560        e: Self,
561    ) -> Self {
562        e
563    }
564}
565
566impl<I, E> FromExternalError<I, E> for EmptyError {
567    #[inline(always)]
568    fn from_external_error(_input: &I, _e: E) -> Self {
569        Self
570    }
571}
572
573impl ErrorConvert<EmptyError> for EmptyError {
574    #[inline(always)]
575    fn convert(self) -> EmptyError {
576        self
577    }
578}
579
580impl core::fmt::Display for EmptyError {
581    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
582        "failed to parse".fmt(f)
583    }
584}
585
586impl<I: Stream> ParserError<I> for () {
587    type Inner = Self;
588
589    #[inline]
590    fn from_input(_: &I) -> Self {}
591
592    #[inline(always)]
593    fn into_inner(self) -> Result<Self::Inner, Self> {
594        Ok(self)
595    }
596}
597
598impl<I: Stream, C> AddContext<I, C> for () {}
599
600#[cfg(feature = "unstable-recover")]
601#[cfg(feature = "std")]
602impl<I: Stream> FromRecoverableError<I, Self> for () {
603    #[inline]
604    fn from_recoverable_error(
605        _token_start: &<I as Stream>::Checkpoint,
606        _err_start: &<I as Stream>::Checkpoint,
607        _input: &I,
608        (): Self,
609    ) -> Self {
610    }
611}
612
613impl<I, E> FromExternalError<I, E> for () {
614    #[inline]
615    fn from_external_error(_input: &I, _e: E) -> Self {}
616}
617
618impl ErrorConvert<()> for () {
619    #[inline]
620    fn convert(self) {}
621}
622
623/// Accumulate context while backtracking errors
624///
625/// See the [tutorial][crate::_tutorial::chapter_7#error-adaptation-and-rendering]
626/// for an example of how to adapt this to an application error with custom rendering.
627#[derive(Debug)]
628pub struct ContextError<C = StrContext> {
629    #[cfg(feature = "alloc")]
630    context: alloc::vec::Vec<C>,
631    #[cfg(not(feature = "alloc"))]
632    context: core::marker::PhantomData<C>,
633    #[cfg(feature = "std")]
634    cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
635}
636
637impl<C> ContextError<C> {
638    /// Create an empty error
639    #[inline]
640    pub fn new() -> Self {
641        Self {
642            context: Default::default(),
643            #[cfg(feature = "std")]
644            cause: None,
645        }
646    }
647
648    /// Add more context
649    #[inline]
650    pub fn push(&mut self, context: C) {
651        #[cfg(feature = "alloc")]
652        self.context.push(context);
653    }
654
655    /// Add more context
656    #[inline]
657    pub fn extend<I: IntoIterator<Item = C>>(&mut self, context: I) {
658        #[cfg(feature = "alloc")]
659        self.context.extend(context);
660    }
661
662    /// Access context from [`Parser::context`]
663    #[inline]
664    #[cfg(feature = "alloc")]
665    pub fn context(&self) -> impl Iterator<Item = &C> {
666        self.context.iter()
667    }
668
669    /// Originating [`std::error::Error`]
670    #[inline]
671    #[cfg(feature = "std")]
672    pub fn cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
673        self.cause.as_deref()
674    }
675}
676
677impl<C: Clone> Clone for ContextError<C> {
678    fn clone(&self) -> Self {
679        Self {
680            context: self.context.clone(),
681            #[cfg(feature = "std")]
682            cause: self.cause.as_ref().map(|e| e.to_string().into()),
683        }
684    }
685}
686
687impl<C> Default for ContextError<C> {
688    #[inline]
689    fn default() -> Self {
690        Self::new()
691    }
692}
693
694impl<I: Stream, C> ParserError<I> for ContextError<C> {
695    type Inner = Self;
696
697    #[inline]
698    fn from_input(_input: &I) -> Self {
699        Self::new()
700    }
701
702    #[inline(always)]
703    fn into_inner(self) -> Result<Self::Inner, Self> {
704        Ok(self)
705    }
706}
707
708impl<C, I: Stream> AddContext<I, C> for ContextError<C> {
709    #[inline]
710    fn add_context(
711        mut self,
712        _input: &I,
713        _token_start: &<I as Stream>::Checkpoint,
714        context: C,
715    ) -> Self {
716        self.push(context);
717        self
718    }
719}
720
721#[cfg(feature = "unstable-recover")]
722#[cfg(feature = "std")]
723impl<I: Stream, C> FromRecoverableError<I, Self> for ContextError<C> {
724    #[inline]
725    fn from_recoverable_error(
726        _token_start: &<I as Stream>::Checkpoint,
727        _err_start: &<I as Stream>::Checkpoint,
728        _input: &I,
729        e: Self,
730    ) -> Self {
731        e
732    }
733}
734
735#[cfg(feature = "std")]
736impl<C, I, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E>
737    for ContextError<C>
738{
739    #[inline]
740    fn from_external_error(_input: &I, e: E) -> Self {
741        let mut err = Self::new();
742        {
743            err.cause = Some(Box::new(e));
744        }
745        err
746    }
747}
748
749// HACK: This is more general than `std`, making the features non-additive
750#[cfg(not(feature = "std"))]
751impl<C, I, E: Send + Sync + 'static> FromExternalError<I, E> for ContextError<C> {
752    #[inline]
753    fn from_external_error(_input: &I, _e: E) -> Self {
754        let err = Self::new();
755        err
756    }
757}
758
759// For tests
760impl<C: core::cmp::PartialEq> core::cmp::PartialEq for ContextError<C> {
761    fn eq(&self, other: &Self) -> bool {
762        #[cfg(feature = "alloc")]
763        {
764            if self.context != other.context {
765                return false;
766            }
767        }
768        #[cfg(feature = "std")]
769        {
770            if self.cause.as_ref().map(ToString::to_string)
771                != other.cause.as_ref().map(ToString::to_string)
772            {
773                return false;
774            }
775        }
776
777        true
778    }
779}
780
781impl core::fmt::Display for ContextError<StrContext> {
782    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
783        #[cfg(feature = "alloc")]
784        {
785            let expression = self.context().find_map(|c| match c {
786                StrContext::Label(c) => Some(c),
787                _ => None,
788            });
789            let expected = self
790                .context()
791                .filter_map(|c| match c {
792                    StrContext::Expected(c) => Some(c),
793                    _ => None,
794                })
795                .collect::<alloc::vec::Vec<_>>();
796
797            let mut newline = false;
798
799            if let Some(expression) = expression {
800                newline = true;
801
802                write!(f, "invalid {expression}")?;
803            }
804
805            if !expected.is_empty() {
806                if newline {
807                    writeln!(f)?;
808                }
809                newline = true;
810
811                write!(f, "expected ")?;
812                for (i, expected) in expected.iter().enumerate() {
813                    if i != 0 {
814                        write!(f, ", ")?;
815                    }
816                    write!(f, "{expected}")?;
817                }
818            }
819            #[cfg(feature = "std")]
820            {
821                if let Some(cause) = self.cause() {
822                    if newline {
823                        writeln!(f)?;
824                    }
825                    write!(f, "{cause}")?;
826                }
827            }
828        }
829
830        Ok(())
831    }
832}
833
834impl<C> ErrorConvert<ContextError<C>> for ContextError<C> {
835    #[inline]
836    fn convert(self) -> ContextError<C> {
837        self
838    }
839}
840
841/// Additional parse context for [`ContextError`] added via [`Parser::context`]
842#[derive(Clone, Debug, PartialEq, Eq)]
843#[non_exhaustive]
844pub enum StrContext {
845    /// Description of what is currently being parsed
846    Label(&'static str),
847    /// Grammar item that was expected
848    Expected(StrContextValue),
849}
850
851impl core::fmt::Display for StrContext {
852    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
853        match self {
854            Self::Label(name) => write!(f, "invalid {name}"),
855            Self::Expected(value) => write!(f, "expected {value}"),
856        }
857    }
858}
859
860/// See [`StrContext`]
861#[derive(Clone, Debug, PartialEq, Eq)]
862#[non_exhaustive]
863pub enum StrContextValue {
864    /// A [`char`] token
865    CharLiteral(char),
866    /// A [`&str`] token
867    StringLiteral(&'static str),
868    /// A description of what was being parsed
869    Description(&'static str),
870}
871
872impl From<char> for StrContextValue {
873    #[inline]
874    fn from(inner: char) -> Self {
875        Self::CharLiteral(inner)
876    }
877}
878
879impl From<&'static str> for StrContextValue {
880    #[inline]
881    fn from(inner: &'static str) -> Self {
882        Self::StringLiteral(inner)
883    }
884}
885
886impl core::fmt::Display for StrContextValue {
887    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
888        match self {
889            Self::CharLiteral('\n') => "newline".fmt(f),
890            Self::CharLiteral('`') => "'`'".fmt(f),
891            Self::CharLiteral(c) if c.is_ascii_control() => {
892                write!(f, "`{}`", c.escape_debug())
893            }
894            Self::CharLiteral(c) => write!(f, "`{c}`"),
895            Self::StringLiteral(c) => write!(f, "`{c}`"),
896            Self::Description(c) => write!(f, "{c}"),
897        }
898    }
899}
900
901/// Trace all error paths, particularly for tests
902#[derive(Debug)]
903#[cfg(feature = "std")]
904pub enum TreeError<I, C = StrContext> {
905    /// Initial error that kicked things off
906    Base(TreeErrorBase<I>),
907    /// Traces added to the error while walking back up the stack
908    Stack {
909        /// Initial error that kicked things off
910        base: Box<Self>,
911        /// Traces added to the error while walking back up the stack
912        stack: Vec<TreeErrorFrame<I, C>>,
913    },
914    /// All failed branches of an `alt`
915    Alt(Vec<Self>),
916}
917
918/// See [`TreeError::Stack`]
919#[derive(Debug)]
920#[cfg(feature = "std")]
921pub enum TreeErrorFrame<I, C = StrContext> {
922    /// See [`ParserError::append`]
923    Kind(TreeErrorBase<I>),
924    /// See [`AddContext::add_context`]
925    Context(TreeErrorContext<I, C>),
926}
927
928/// See [`TreeErrorFrame::Kind`], [`ParserError::append`]
929#[derive(Debug)]
930#[cfg(feature = "std")]
931pub struct TreeErrorBase<I> {
932    /// Parsed input, at the location where the error occurred
933    pub input: I,
934    /// See [`FromExternalError::from_external_error`]
935    pub cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
936}
937
938/// See [`TreeErrorFrame::Context`], [`AddContext::add_context`]
939#[derive(Debug)]
940#[cfg(feature = "std")]
941pub struct TreeErrorContext<I, C = StrContext> {
942    /// Parsed input, at the location where the error occurred
943    pub input: I,
944    /// See [`AddContext::add_context`]
945    pub context: C,
946}
947
948#[cfg(feature = "std")]
949impl<I: ToOwned, C> TreeError<&I, C> {
950    /// Obtaining ownership
951    pub fn into_owned(self) -> TreeError<<I as ToOwned>::Owned, C> {
952        self.map_input(ToOwned::to_owned)
953    }
954}
955
956#[cfg(feature = "std")]
957impl<I, C> TreeError<I, C> {
958    /// Translate the input type
959    pub fn map_input<I2, O: Clone + Fn(I) -> I2>(self, op: O) -> TreeError<I2, C> {
960        match self {
961            TreeError::Base(base) => TreeError::Base(TreeErrorBase {
962                input: op(base.input),
963                cause: base.cause,
964            }),
965            TreeError::Stack { base, stack } => {
966                let base = Box::new(base.map_input(op.clone()));
967                let stack = stack
968                    .into_iter()
969                    .map(|frame| match frame {
970                        TreeErrorFrame::Kind(kind) => TreeErrorFrame::Kind(TreeErrorBase {
971                            input: op(kind.input),
972                            cause: kind.cause,
973                        }),
974                        TreeErrorFrame::Context(context) => {
975                            TreeErrorFrame::Context(TreeErrorContext {
976                                input: op(context.input),
977                                context: context.context,
978                            })
979                        }
980                    })
981                    .collect();
982                TreeError::Stack { base, stack }
983            }
984            TreeError::Alt(alt) => {
985                TreeError::Alt(alt.into_iter().map(|e| e.map_input(op.clone())).collect())
986            }
987        }
988    }
989
990    fn append_frame(self, frame: TreeErrorFrame<I, C>) -> Self {
991        match self {
992            TreeError::Stack { base, mut stack } => {
993                stack.push(frame);
994                TreeError::Stack { base, stack }
995            }
996            base => TreeError::Stack {
997                base: Box::new(base),
998                stack: vec![frame],
999            },
1000        }
1001    }
1002}
1003
1004#[cfg(feature = "std")]
1005impl<I, C> ParserError<I> for TreeError<I, C>
1006where
1007    I: Stream + Clone,
1008{
1009    type Inner = Self;
1010
1011    fn from_input(input: &I) -> Self {
1012        TreeError::Base(TreeErrorBase {
1013            input: input.clone(),
1014            cause: None,
1015        })
1016    }
1017
1018    fn append(self, input: &I, token_start: &<I as Stream>::Checkpoint) -> Self {
1019        let mut input = input.clone();
1020        input.reset(token_start);
1021        let frame = TreeErrorFrame::Kind(TreeErrorBase { input, cause: None });
1022        self.append_frame(frame)
1023    }
1024
1025    fn or(self, other: Self) -> Self {
1026        match (self, other) {
1027            (TreeError::Alt(mut first), TreeError::Alt(second)) => {
1028                // Just in case an implementation does a divide-and-conquer algorithm
1029                //
1030                // To prevent mixing `alt`s at different levels, parsers should
1031                // `alt_err.append(input)`.
1032                first.extend(second);
1033                TreeError::Alt(first)
1034            }
1035            (TreeError::Alt(mut alt), new) | (new, TreeError::Alt(mut alt)) => {
1036                alt.push(new);
1037                TreeError::Alt(alt)
1038            }
1039            (first, second) => TreeError::Alt(vec![first, second]),
1040        }
1041    }
1042
1043    #[inline(always)]
1044    fn into_inner(self) -> Result<Self::Inner, Self> {
1045        Ok(self)
1046    }
1047}
1048
1049#[cfg(feature = "std")]
1050impl<I, C> AddContext<I, C> for TreeError<I, C>
1051where
1052    I: Stream + Clone,
1053{
1054    fn add_context(self, input: &I, token_start: &<I as Stream>::Checkpoint, context: C) -> Self {
1055        let mut input = input.clone();
1056        input.reset(token_start);
1057        let frame = TreeErrorFrame::Context(TreeErrorContext { input, context });
1058        self.append_frame(frame)
1059    }
1060}
1061
1062#[cfg(feature = "std")]
1063#[cfg(feature = "unstable-recover")]
1064impl<I: Stream, C> FromRecoverableError<I, Self> for TreeError<I, C> {
1065    #[inline]
1066    fn from_recoverable_error(
1067        _token_start: &<I as Stream>::Checkpoint,
1068        _err_start: &<I as Stream>::Checkpoint,
1069        _input: &I,
1070        e: Self,
1071    ) -> Self {
1072        e
1073    }
1074}
1075
1076#[cfg(feature = "std")]
1077impl<I, C, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E> for TreeError<I, C>
1078where
1079    I: Clone,
1080{
1081    fn from_external_error(input: &I, e: E) -> Self {
1082        TreeError::Base(TreeErrorBase {
1083            input: input.clone(),
1084            cause: Some(Box::new(e)),
1085        })
1086    }
1087}
1088
1089#[cfg(feature = "std")]
1090#[cfg(feature = "binary")]
1091impl<I, C> ErrorConvert<TreeError<Bits<I>, C>> for TreeError<I, C> {
1092    #[inline]
1093    fn convert(self) -> TreeError<Bits<I>, C> {
1094        self.map_input(|i| Bits(i, 0))
1095    }
1096}
1097
1098#[cfg(feature = "std")]
1099#[cfg(feature = "binary")]
1100impl<I, C> ErrorConvert<TreeError<I, C>> for TreeError<Bits<I>, C> {
1101    #[inline]
1102    fn convert(self) -> TreeError<I, C> {
1103        self.map_input(|Bits(i, _o)| i)
1104    }
1105}
1106
1107/// deprecated since 1.0.2
1108#[cfg(feature = "std")]
1109impl<I, C> ErrorConvert<TreeError<(I, usize), C>> for TreeError<I, C> {
1110    #[inline]
1111    fn convert(self) -> TreeError<(I, usize), C> {
1112        self.map_input(|i| (i, 0))
1113    }
1114}
1115
1116/// deprecated since 1.0.2
1117#[cfg(feature = "std")]
1118impl<I, C> ErrorConvert<TreeError<I, C>> for TreeError<(I, usize), C> {
1119    #[inline]
1120    fn convert(self) -> TreeError<I, C> {
1121        self.map_input(|(i, _o)| i)
1122    }
1123}
1124
1125#[cfg(feature = "std")]
1126impl<I, C> TreeError<I, C>
1127where
1128    I: core::fmt::Display,
1129    C: fmt::Display,
1130{
1131    fn write(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result {
1132        let child_indent = indent + 2;
1133        match self {
1134            TreeError::Base(base) => {
1135                writeln!(f, "{:indent$}{base}", "")?;
1136            }
1137            TreeError::Stack { base, stack } => {
1138                base.write(f, indent)?;
1139                for (level, frame) in stack.iter().enumerate() {
1140                    match frame {
1141                        TreeErrorFrame::Kind(frame) => {
1142                            writeln!(f, "{:child_indent$}{level}: {frame}", "")?;
1143                        }
1144                        TreeErrorFrame::Context(frame) => {
1145                            writeln!(f, "{:child_indent$}{level}: {frame}", "")?;
1146                        }
1147                    }
1148                }
1149            }
1150            TreeError::Alt(alt) => {
1151                writeln!(f, "{:indent$}during one of:", "")?;
1152                for child in alt {
1153                    child.write(f, child_indent)?;
1154                }
1155            }
1156        }
1157
1158        Ok(())
1159    }
1160}
1161
1162#[cfg(feature = "std")]
1163impl<I: fmt::Display> fmt::Display for TreeErrorBase<I> {
1164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1165        if let Some(cause) = self.cause.as_ref() {
1166            write!(f, "caused by {cause}")?;
1167        }
1168        let input = abbreviate(self.input.to_string());
1169        write!(f, " at '{input}'")?;
1170        Ok(())
1171    }
1172}
1173
1174#[cfg(feature = "std")]
1175impl<I: fmt::Display, C: fmt::Display> fmt::Display for TreeErrorContext<I, C> {
1176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1177        let context = &self.context;
1178        let input = abbreviate(self.input.to_string());
1179        write!(f, "{context} at '{input}'")?;
1180        Ok(())
1181    }
1182}
1183
1184#[cfg(feature = "std")]
1185impl<I: fmt::Debug + fmt::Display + Sync + Send + 'static, C: fmt::Display + fmt::Debug>
1186    std::error::Error for TreeError<I, C>
1187{
1188}
1189
1190#[cfg(feature = "std")]
1191fn abbreviate(input: String) -> String {
1192    let mut abbrev = None;
1193
1194    if let Some((line, _)) = input.split_once('\n') {
1195        abbrev = Some(line);
1196    }
1197
1198    let max_len = 20;
1199    let current = abbrev.unwrap_or(&input);
1200    if max_len < current.len() {
1201        if let Some((index, _)) = current.char_indices().nth(max_len) {
1202            abbrev = Some(&current[..index]);
1203        }
1204    }
1205
1206    if let Some(abbrev) = abbrev {
1207        format!("{abbrev}...")
1208    } else {
1209        input
1210    }
1211}
1212
1213#[cfg(feature = "std")]
1214impl<I: fmt::Display, C: fmt::Display> fmt::Display for TreeError<I, C> {
1215    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1216        self.write(f, 0)
1217    }
1218}
1219
1220/// See [`Parser::parse`]
1221#[derive(Clone, Debug, PartialEq, Eq)]
1222pub struct ParseError<I, E> {
1223    input: I,
1224    offset: usize,
1225    inner: E,
1226}
1227
1228impl<I: Stream, E: ParserError<I>> ParseError<I, E> {
1229    pub(crate) fn new(mut input: I, start: I::Checkpoint, inner: E) -> Self {
1230        let offset = input.offset_from(&start);
1231        input.reset(&start);
1232        Self {
1233            input,
1234            offset,
1235            inner,
1236        }
1237    }
1238}
1239
1240impl<I, E> ParseError<I, E> {
1241    /// The [`Stream`] at the initial location when parsing started
1242    #[inline]
1243    pub fn input(&self) -> &I {
1244        &self.input
1245    }
1246
1247    /// The location in [`ParseError::input`] where parsing failed
1248    ///
1249    /// To get the span for the `char` this points to, see [`ParseError::char_span`].
1250    ///
1251    /// <div class="warning">
1252    ///
1253    /// **Note:** This is an offset, not an index, and may point to the end of input
1254    /// (`input.len()`) on eof errors.
1255    ///
1256    /// </div>
1257    #[inline]
1258    pub fn offset(&self) -> usize {
1259        self.offset
1260    }
1261
1262    /// The original [`ParserError`]
1263    #[inline]
1264    pub fn inner(&self) -> &E {
1265        &self.inner
1266    }
1267
1268    /// The original [`ParserError`]
1269    #[inline]
1270    pub fn into_inner(self) -> E {
1271        self.inner
1272    }
1273}
1274
1275impl<I: AsBStr, E> ParseError<I, E> {
1276    /// The byte indices for the `char` at [`ParseError::offset`]
1277    #[inline]
1278    pub fn char_span(&self) -> core::ops::Range<usize> {
1279        char_boundary(self.input.as_bstr(), self.offset())
1280    }
1281}
1282
1283fn char_boundary(input: &[u8], offset: usize) -> core::ops::Range<usize> {
1284    let len = input.len();
1285    if offset == len {
1286        return offset..offset;
1287    }
1288
1289    let start = (0..(offset + 1).min(len))
1290        .rev()
1291        .find(|i| {
1292            input
1293                .get(*i)
1294                .copied()
1295                .map(is_utf8_char_boundary)
1296                .unwrap_or(false)
1297        })
1298        .unwrap_or(0);
1299    let end = (offset + 1..len)
1300        .find(|i| {
1301            input
1302                .get(*i)
1303                .copied()
1304                .map(is_utf8_char_boundary)
1305                .unwrap_or(false)
1306        })
1307        .unwrap_or(len);
1308    start..end
1309}
1310
1311/// Taken from `core::num`
1312const fn is_utf8_char_boundary(b: u8) -> bool {
1313    // This is bit magic equivalent to: b < 128 || b >= 192
1314    (b as i8) >= -0x40
1315}
1316
1317impl<I, E> core::fmt::Display for ParseError<I, E>
1318where
1319    I: AsBStr,
1320    E: core::fmt::Display,
1321{
1322    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1323        let input = self.input.as_bstr();
1324        let span_start = self.offset;
1325        let span_end = span_start;
1326        #[cfg(feature = "std")]
1327        if input.contains(&b'\n') {
1328            let (line_idx, col_idx) = translate_position(input, span_start);
1329            let line_num = line_idx + 1;
1330            let col_num = col_idx + 1;
1331            let gutter = line_num.to_string().len();
1332            let content = input
1333                .split(|c| *c == b'\n')
1334                .nth(line_idx)
1335                .expect("valid line number");
1336
1337            writeln!(f, "parse error at line {line_num}, column {col_num}")?;
1338            //   |
1339            for _ in 0..gutter {
1340                write!(f, " ")?;
1341            }
1342            writeln!(f, " |")?;
1343
1344            // 1 | 00:32:00.a999999
1345            write!(f, "{line_num} | ")?;
1346            writeln!(f, "{}", String::from_utf8_lossy(content))?;
1347
1348            //   |          ^
1349            for _ in 0..gutter {
1350                write!(f, " ")?;
1351            }
1352            write!(f, " | ")?;
1353            for _ in 0..col_idx {
1354                write!(f, " ")?;
1355            }
1356            // The span will be empty at eof, so we need to make sure we always print at least
1357            // one `^`
1358            write!(f, "^")?;
1359            for _ in (span_start + 1)..(span_end.min(span_start + content.len())) {
1360                write!(f, "^")?;
1361            }
1362            writeln!(f)?;
1363        } else {
1364            let content = input;
1365            writeln!(f, "{}", String::from_utf8_lossy(content))?;
1366            for _ in 0..span_start {
1367                write!(f, " ")?;
1368            }
1369            // The span will be empty at eof, so we need to make sure we always print at least
1370            // one `^`
1371            write!(f, "^")?;
1372            for _ in (span_start + 1)..(span_end.min(span_start + content.len())) {
1373                write!(f, "^")?;
1374            }
1375            writeln!(f)?;
1376        }
1377        write!(f, "{}", self.inner)?;
1378
1379        Ok(())
1380    }
1381}
1382
1383#[cfg(feature = "std")]
1384fn translate_position(input: &[u8], index: usize) -> (usize, usize) {
1385    if input.is_empty() {
1386        return (0, index);
1387    }
1388
1389    let safe_index = index.min(input.len() - 1);
1390    let column_offset = index - safe_index;
1391    let index = safe_index;
1392
1393    let nl = input[0..index]
1394        .iter()
1395        .rev()
1396        .enumerate()
1397        .find(|(_, b)| **b == b'\n')
1398        .map(|(nl, _)| index - nl - 1);
1399    let line_start = match nl {
1400        Some(nl) => nl + 1,
1401        None => 0,
1402    };
1403    let line = input[0..line_start].iter().filter(|b| **b == b'\n').count();
1404
1405    // HACK: This treats byte offset and column offsets the same
1406    let column = core::str::from_utf8(&input[line_start..=index])
1407        .map(|s| s.chars().count() - 1)
1408        .unwrap_or_else(|_| index - line_start);
1409    let column = column + column_offset;
1410
1411    (line, column)
1412}
1413
1414#[cfg(test)]
1415mod test_char_boundary {
1416    use super::*;
1417
1418    #[test]
1419    fn ascii() {
1420        let input = "hi";
1421        let cases = [(0, 0..1), (1, 1..2), (2, 2..2)];
1422        for (offset, expected) in cases {
1423            assert_eq!(
1424                char_boundary(input.as_bytes(), offset),
1425                expected,
1426                "input={input:?}, offset={offset:?}"
1427            );
1428        }
1429    }
1430
1431    #[test]
1432    fn utf8() {
1433        let input = "βèƒôřè";
1434        assert_eq!(input.len(), 12);
1435        let cases = [
1436            (0, 0..2),
1437            (1, 0..2),
1438            (2, 2..4),
1439            (3, 2..4),
1440            (4, 4..6),
1441            (5, 4..6),
1442            (6, 6..8),
1443            (7, 6..8),
1444            (8, 8..10),
1445            (9, 8..10),
1446            (10, 10..12),
1447            (11, 10..12),
1448            (12, 12..12),
1449        ];
1450        for (offset, expected) in cases {
1451            assert_eq!(
1452                char_boundary(input.as_bytes(), offset),
1453                expected,
1454                "input={input:?}, offset={offset:?}"
1455            );
1456        }
1457    }
1458}
1459
1460#[cfg(test)]
1461#[cfg(feature = "std")]
1462mod test_parse_error {
1463    use super::*;
1464
1465    #[test]
1466    fn single_line() {
1467        let mut input = "0xZ123";
1468        let start = input.checkpoint();
1469        let _ = input.next_token().unwrap();
1470        let _ = input.next_token().unwrap();
1471        let inner = InputError::at(input);
1472        let error = ParseError::new(input, start, inner);
1473        let expected = "\
14740xZ123
1475  ^
1476failed to parse starting at: Z123";
1477        assert_eq!(error.to_string(), expected);
1478    }
1479}
1480
1481#[cfg(test)]
1482#[cfg(feature = "std")]
1483mod test_translate_position {
1484    use super::*;
1485
1486    #[test]
1487    fn empty() {
1488        let input = b"";
1489        let index = 0;
1490        let position = translate_position(&input[..], index);
1491        assert_eq!(position, (0, 0));
1492    }
1493
1494    #[test]
1495    fn start() {
1496        let input = b"Hello";
1497        let index = 0;
1498        let position = translate_position(&input[..], index);
1499        assert_eq!(position, (0, 0));
1500    }
1501
1502    #[test]
1503    fn end() {
1504        let input = b"Hello";
1505        let index = input.len() - 1;
1506        let position = translate_position(&input[..], index);
1507        assert_eq!(position, (0, input.len() - 1));
1508    }
1509
1510    #[test]
1511    fn after() {
1512        let input = b"Hello";
1513        let index = input.len();
1514        let position = translate_position(&input[..], index);
1515        assert_eq!(position, (0, input.len()));
1516    }
1517
1518    #[test]
1519    fn first_line() {
1520        let input = b"Hello\nWorld\n";
1521        let index = 2;
1522        let position = translate_position(&input[..], index);
1523        assert_eq!(position, (0, 2));
1524    }
1525
1526    #[test]
1527    fn end_of_line() {
1528        let input = b"Hello\nWorld\n";
1529        let index = 5;
1530        let position = translate_position(&input[..], index);
1531        assert_eq!(position, (0, 5));
1532    }
1533
1534    #[test]
1535    fn start_of_second_line() {
1536        let input = b"Hello\nWorld\n";
1537        let index = 6;
1538        let position = translate_position(&input[..], index);
1539        assert_eq!(position, (1, 0));
1540    }
1541
1542    #[test]
1543    fn second_line() {
1544        let input = b"Hello\nWorld\n";
1545        let index = 8;
1546        let position = translate_position(&input[..], index);
1547        assert_eq!(position, (1, 2));
1548    }
1549}