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