Coverage Report

Created: 2025-02-25 06:39

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