Coverage Report

Created: 2025-07-23 06:03

/src/nom/src/error.rs
Line
Count
Source (jump to first uncovered line)
1
//! Error management
2
//!
3
//! Parsers are generic over their error type, requiring that it implements
4
//! the `error::ParseError<Input>` trait.
5
6
use crate::internal::{Err, Mode, OutputMode, PResult, Parser};
7
use crate::lib::std::fmt;
8
9
#[cfg(feature = "alloc")]
10
use crate::alloc::borrow::ToOwned;
11
12
#[cfg(feature = "std")]
13
use crate::internal::IResult;
14
15
/// This trait must be implemented by the error type of a nom parser.
16
///
17
/// There are already implementations of it for `(Input, ErrorKind)`
18
/// and `Error<Input>`.
19
///
20
/// It provides methods to create an error from some combinators,
21
/// and combine existing errors in combinators like `alt`.
22
pub trait ParseError<I>: Sized {
23
  /// Creates an error from the input position and an [ErrorKind]
24
  fn from_error_kind(input: I, kind: ErrorKind) -> Self;
25
26
  /// Combines an existing error with a new one created from the input
27
  /// position and an [ErrorKind]. This is useful when backtracking
28
  /// through a parse tree, accumulating error context on the way
29
  fn append(input: I, kind: ErrorKind, other: Self) -> Self;
30
31
  /// Creates an error from an input position and an expected character
32
37.3k
  fn from_char(input: I, _: char) -> Self {
33
37.3k
    Self::from_error_kind(input, ErrorKind::Char)
34
37.3k
  }
<nom::error::Error<&str> as nom::error::ParseError<&str>>::from_char
Line
Count
Source
32
37.3k
  fn from_char(input: I, _: char) -> Self {
33
37.3k
    Self::from_error_kind(input, ErrorKind::Char)
34
37.3k
  }
Unexecuted instantiation: <_ as nom::error::ParseError<_>>::from_char
35
36
  /// Combines two existing errors. This function is used to compare errors
37
  /// generated in various branches of `alt`.
38
16.9k
  fn or(self, other: Self) -> Self {
39
16.9k
    other
40
16.9k
  }
<nom::error::Error<&str> as nom::error::ParseError<&str>>::or
Line
Count
Source
38
16.9k
  fn or(self, other: Self) -> Self {
39
16.9k
    other
40
16.9k
  }
Unexecuted instantiation: <_ as nom::error::ParseError<_>>::or
41
}
42
43
/// This trait is required by the `context` combinator to add a static string
44
/// to an existing error
45
pub trait ContextError<I>: Sized {
46
  /// Creates a new error from an input position, a static string and an existing error.
47
  /// This is used mainly in the [context] combinator, to add user friendly information
48
  /// to errors when backtracking through a parse tree
49
0
  fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self {
50
0
    other
51
0
  }
52
}
53
54
/// This trait is required by the `map_res` combinator to integrate
55
/// error types from external functions, like [std::str::FromStr]
56
pub trait FromExternalError<I, E> {
57
  /// Creates a new error from an input position, an [ErrorKind] indicating the
58
  /// wrapping parser, and an external error
59
  fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self;
60
}
61
62
/// default error type, only contains the error's location and code
63
#[derive(Clone, Debug, Eq, PartialEq)]
64
pub struct Error<I> {
65
  /// position of the error in the input data
66
  pub input: I,
67
  /// nom error code
68
  pub code: ErrorKind,
69
}
70
71
impl<I> Error<I> {
72
  /// creates a new basic error
73
0
  pub fn new(input: I, code: ErrorKind) -> Error<I> {
74
0
    Error { input, code }
75
0
  }
Unexecuted instantiation: <nom::error::Error<&str>>::new
Unexecuted instantiation: <nom::error::Error<_>>::new
76
}
77
78
impl<I> ParseError<I> for Error<I> {
79
42.4k
  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
80
42.4k
    Error { input, code: kind }
81
42.4k
  }
<nom::error::Error<&str> as nom::error::ParseError<&str>>::from_error_kind
Line
Count
Source
79
42.4k
  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
80
42.4k
    Error { input, code: kind }
81
42.4k
  }
Unexecuted instantiation: <nom::error::Error<_> as nom::error::ParseError<_>>::from_error_kind
82
83
16.9k
  fn append(_: I, _: ErrorKind, other: Self) -> Self {
84
16.9k
    other
85
16.9k
  }
<nom::error::Error<&str> as nom::error::ParseError<&str>>::append
Line
Count
Source
83
16.9k
  fn append(_: I, _: ErrorKind, other: Self) -> Self {
84
16.9k
    other
85
16.9k
  }
Unexecuted instantiation: <nom::error::Error<_> as nom::error::ParseError<_>>::append
86
}
87
88
impl<I> ContextError<I> for Error<I> {}
89
90
impl<I, E> FromExternalError<I, E> for Error<I> {
91
  /// Create a new error from an input position and an external error
92
2
  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
93
2
    Error { input, code: kind }
94
2
  }
<nom::error::Error<&str> as nom::error::FromExternalError<&str, core::num::error::ParseIntError>>::from_external_error
Line
Count
Source
92
2
  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
93
2
    Error { input, code: kind }
94
2
  }
Unexecuted instantiation: <nom::error::Error<_> as nom::error::FromExternalError<_, _>>::from_external_error
95
}
96
97
/// The Display implementation allows the std::error::Error implementation
98
impl<I: fmt::Display> fmt::Display for Error<I> {
99
0
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100
0
    write!(f, "error {:?} at: {}", self.code, self.input)
101
0
  }
102
}
103
104
#[cfg(feature = "alloc")]
105
impl<I: ToOwned + ?Sized> Error<&I> {
106
  /// Converts `Error<&I>` into `Error<I::Owned>` by cloning.
107
0
  pub fn cloned(self) -> Error<I::Owned> {
108
0
    Error {
109
0
      input: self.input.to_owned(),
110
0
      code: self.code,
111
0
    }
112
0
  }
113
}
114
115
#[cfg(feature = "alloc")]
116
impl<I: ToOwned + ?Sized> Error<&mut I> {
117
  /// Converts `Error<&mut I>` into `Error<I::Owned>` by cloning.
118
0
  pub fn cloned(self) -> Error<I::Owned> {
119
0
    Error {
120
0
      input: self.input.to_owned(),
121
0
      code: self.code,
122
0
    }
123
0
  }
124
}
125
126
impl<I: Copy> Error<&I> {
127
  /// Converts `Error<&I>` into `Error<I>` by copying.
128
0
  pub fn copied(self) -> Error<I> {
129
0
    Error {
130
0
      input: *self.input,
131
0
      code: self.code,
132
0
    }
133
0
  }
134
}
135
136
impl<I: Copy> Error<&mut I> {
137
  /// Converts `Error<&mut I>` into `Error<I>` by copying.
138
0
  pub fn copied(self) -> Error<I> {
139
0
    Error {
140
0
      input: *self.input,
141
0
      code: self.code,
142
0
    }
143
0
  }
144
}
145
146
#[cfg(feature = "std")]
147
impl<I: fmt::Debug + fmt::Display> std::error::Error for Error<I> {}
148
149
#[cfg(feature = "alloc")]
150
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
151
impl From<Error<&[u8]>> for Error<crate::lib::std::vec::Vec<u8>> {
152
  fn from(value: Error<&[u8]>) -> Self {
153
    Error {
154
      input: value.input.to_owned(),
155
      code: value.code,
156
    }
157
  }
158
}
159
160
#[cfg(feature = "alloc")]
161
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
162
impl From<Error<&str>> for Error<crate::lib::std::string::String> {
163
  fn from(value: Error<&str>) -> Self {
164
    Error {
165
      input: value.input.to_owned(),
166
      code: value.code,
167
    }
168
  }
169
}
170
171
// for backward compatibility, keep those trait implementations
172
// for the previously used error type
173
impl<I> ParseError<I> for (I, ErrorKind) {
174
0
  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
175
0
    (input, kind)
176
0
  }
177
178
0
  fn append(_: I, _: ErrorKind, other: Self) -> Self {
179
0
    other
180
0
  }
181
}
182
183
impl<I> ContextError<I> for (I, ErrorKind) {}
184
185
impl<I, E> FromExternalError<I, E> for (I, ErrorKind) {
186
0
  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
187
0
    (input, kind)
188
0
  }
189
}
190
191
impl<I> ParseError<I> for () {
192
0
  fn from_error_kind(_: I, _: ErrorKind) -> Self {}
193
194
0
  fn append(_: I, _: ErrorKind, _: Self) -> Self {}
195
}
196
197
impl<I> ContextError<I> for () {}
198
199
impl<I, E> FromExternalError<I, E> for () {
200
0
  fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {}
201
}
202
203
/// Creates an error from the input position and an [ErrorKind]
204
0
pub fn make_error<I, E: ParseError<I>>(input: I, kind: ErrorKind) -> E {
205
0
  E::from_error_kind(input, kind)
206
0
}
207
208
/// Combines an existing error with a new one created from the input
209
/// position and an [ErrorKind]. This is useful when backtracking
210
/// through a parse tree, accumulating error context on the way
211
0
pub fn append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) -> E {
212
0
  E::append(input, kind, other)
213
0
}
214
215
/// Create a new error from an input position, a static string and an existing error.
216
/// This is used mainly in the [context] combinator, to add user friendly information
217
/// to errors when backtracking through a parse tree
218
0
pub fn context<F>(context: &'static str, parser: F) -> Context<F> {
219
0
  Context { context, parser }
220
0
}
221
222
/// Parser implementation for [context]
223
pub struct Context<F> {
224
  context: &'static str,
225
  parser: F,
226
}
227
228
impl<I, F> Parser<I> for Context<F>
229
where
230
  I: Clone,
231
  F: Parser<I>,
232
  <F as Parser<I>>::Error: ContextError<I>,
233
{
234
  type Output = <F as Parser<I>>::Output;
235
  type Error = <F as Parser<I>>::Error;
236
237
0
  fn process<OM: OutputMode>(&mut self, input: I) -> PResult<OM, I, Self::Output, Self::Error> {
238
0
    match self.parser.process::<OM>(input.clone()) {
239
0
      Err(Err::Error(e)) => Err(Err::Error(OM::Error::map(e, |e| {
240
0
        <F as Parser<I>>::Error::add_context(input, self.context, e)
241
0
      }))),
242
0
      Err(Err::Failure(e)) => Err(Err::Failure(<F as Parser<I>>::Error::add_context(
243
0
        input,
244
0
        self.context,
245
0
        e,
246
0
      ))),
247
0
      x => x,
248
    }
249
0
  }
250
}
251
252
/// Indicates which parser returned an error
253
#[rustfmt::skip]
254
#[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)]
255
#[allow(deprecated,missing_docs)]
256
pub enum ErrorKind {
257
  Tag,
258
  MapRes,
259
  MapOpt,
260
  Alt,
261
  IsNot,
262
  IsA,
263
  SeparatedList,
264
  SeparatedNonEmptyList,
265
  Many0,
266
  Many1,
267
  ManyTill,
268
  Count,
269
  TakeUntil,
270
  LengthValue,
271
  TagClosure,
272
  Alpha,
273
  Digit,
274
  HexDigit,
275
  OctDigit,
276
  BinDigit,
277
  AlphaNumeric,
278
  Space,
279
  MultiSpace,
280
  LengthValueFn,
281
  Eof,
282
  Switch,
283
  TagBits,
284
  OneOf,
285
  NoneOf,
286
  Char,
287
  CrLf,
288
  RegexpMatch,
289
  RegexpMatches,
290
  RegexpFind,
291
  RegexpCapture,
292
  RegexpCaptures,
293
  TakeWhile1,
294
  Complete,
295
  Fix,
296
  Escaped,
297
  EscapedTransform,
298
  NonEmpty,
299
  ManyMN,
300
  Not,
301
  Permutation,
302
  Verify,
303
  TakeTill1,
304
  TakeWhileMN,
305
  TooLarge,
306
  Many0Count,
307
  Many1Count,
308
  Float,
309
  Satisfy,
310
  Fail,
311
  Many,
312
  Fold,
313
  Precedence,
314
}
315
316
#[rustfmt::skip]
317
#[allow(deprecated)]
318
/// Converts an ErrorKind to a number
319
pub fn error_to_u32(e: &ErrorKind) -> u32 {
320
  match *e {
321
    ErrorKind::Tag                       => 1,
322
    ErrorKind::MapRes                    => 2,
323
    ErrorKind::MapOpt                    => 3,
324
    ErrorKind::Alt                       => 4,
325
    ErrorKind::IsNot                     => 5,
326
    ErrorKind::IsA                       => 6,
327
    ErrorKind::SeparatedList             => 7,
328
    ErrorKind::SeparatedNonEmptyList     => 8,
329
    ErrorKind::Many1                     => 9,
330
    ErrorKind::Count                     => 10,
331
    ErrorKind::TakeUntil                 => 12,
332
    ErrorKind::LengthValue               => 15,
333
    ErrorKind::TagClosure                => 16,
334
    ErrorKind::Alpha                     => 17,
335
    ErrorKind::Digit                     => 18,
336
    ErrorKind::AlphaNumeric              => 19,
337
    ErrorKind::Space                     => 20,
338
    ErrorKind::MultiSpace                => 21,
339
    ErrorKind::LengthValueFn             => 22,
340
    ErrorKind::Eof                       => 23,
341
    ErrorKind::Switch                    => 27,
342
    ErrorKind::TagBits                   => 28,
343
    ErrorKind::OneOf                     => 29,
344
    ErrorKind::NoneOf                    => 30,
345
    ErrorKind::Char                      => 40,
346
    ErrorKind::CrLf                      => 41,
347
    ErrorKind::RegexpMatch               => 42,
348
    ErrorKind::RegexpMatches             => 43,
349
    ErrorKind::RegexpFind                => 44,
350
    ErrorKind::RegexpCapture             => 45,
351
    ErrorKind::RegexpCaptures            => 46,
352
    ErrorKind::TakeWhile1                => 47,
353
    ErrorKind::Complete                  => 48,
354
    ErrorKind::Fix                       => 49,
355
    ErrorKind::Escaped                   => 50,
356
    ErrorKind::EscapedTransform          => 51,
357
    ErrorKind::NonEmpty                  => 56,
358
    ErrorKind::ManyMN                    => 57,
359
    ErrorKind::HexDigit                  => 59,
360
    ErrorKind::OctDigit                  => 61,
361
    ErrorKind::Many0                     => 62,
362
    ErrorKind::Not                       => 63,
363
    ErrorKind::Permutation               => 64,
364
    ErrorKind::ManyTill                  => 65,
365
    ErrorKind::Verify                    => 66,
366
    ErrorKind::TakeTill1                 => 67,
367
    ErrorKind::TakeWhileMN               => 69,
368
    ErrorKind::TooLarge                  => 70,
369
    ErrorKind::Many0Count                => 71,
370
    ErrorKind::Many1Count                => 72,
371
    ErrorKind::Float                     => 73,
372
    ErrorKind::Satisfy                   => 74,
373
    ErrorKind::Fail                      => 75,
374
    ErrorKind::Many                      => 76,
375
    ErrorKind::Fold                      => 77,
376
    ErrorKind::BinDigit                  => 78,
377
    ErrorKind::Precedence                => 79,
378
  }
379
}
380
381
impl ErrorKind {
382
  #[rustfmt::skip]
383
  #[allow(deprecated)]
384
  /// Converts an ErrorKind to a text description
385
  pub fn description(&self) -> &str {
386
    match *self {
387
      ErrorKind::Tag                       => "Tag",
388
      ErrorKind::MapRes                    => "Map on Result",
389
      ErrorKind::MapOpt                    => "Map on Option",
390
      ErrorKind::Alt                       => "Alternative",
391
      ErrorKind::IsNot                     => "IsNot",
392
      ErrorKind::IsA                       => "IsA",
393
      ErrorKind::SeparatedList             => "Separated list",
394
      ErrorKind::SeparatedNonEmptyList     => "Separated non empty list",
395
      ErrorKind::Many0                     => "Many0",
396
      ErrorKind::Many1                     => "Many1",
397
      ErrorKind::Count                     => "Count",
398
      ErrorKind::TakeUntil                 => "Take until",
399
      ErrorKind::LengthValue               => "Length followed by value",
400
      ErrorKind::TagClosure                => "Tag closure",
401
      ErrorKind::Alpha                     => "Alphabetic",
402
      ErrorKind::Digit                     => "Digit",
403
      ErrorKind::AlphaNumeric              => "AlphaNumeric",
404
      ErrorKind::Space                     => "Space",
405
      ErrorKind::MultiSpace                => "Multiple spaces",
406
      ErrorKind::LengthValueFn             => "LengthValueFn",
407
      ErrorKind::Eof                       => "End of file",
408
      ErrorKind::Switch                    => "Switch",
409
      ErrorKind::TagBits                   => "Tag on bitstream",
410
      ErrorKind::OneOf                     => "OneOf",
411
      ErrorKind::NoneOf                    => "NoneOf",
412
      ErrorKind::Char                      => "Char",
413
      ErrorKind::CrLf                      => "CrLf",
414
      ErrorKind::RegexpMatch               => "RegexpMatch",
415
      ErrorKind::RegexpMatches             => "RegexpMatches",
416
      ErrorKind::RegexpFind                => "RegexpFind",
417
      ErrorKind::RegexpCapture             => "RegexpCapture",
418
      ErrorKind::RegexpCaptures            => "RegexpCaptures",
419
      ErrorKind::TakeWhile1                => "TakeWhile1",
420
      ErrorKind::Complete                  => "Complete",
421
      ErrorKind::Fix                       => "Fix",
422
      ErrorKind::Escaped                   => "Escaped",
423
      ErrorKind::EscapedTransform          => "EscapedTransform",
424
      ErrorKind::NonEmpty                  => "NonEmpty",
425
      ErrorKind::ManyMN                    => "Many(m, n)",
426
      ErrorKind::HexDigit                  => "Hexadecimal Digit",
427
      ErrorKind::OctDigit                  => "Octal digit",
428
      ErrorKind::BinDigit                  => "Binary digit",
429
      ErrorKind::Not                       => "Negation",
430
      ErrorKind::Permutation               => "Permutation",
431
      ErrorKind::ManyTill                  => "ManyTill",
432
      ErrorKind::Verify                    => "predicate verification",
433
      ErrorKind::TakeTill1                 => "TakeTill1",
434
      ErrorKind::TakeWhileMN               => "TakeWhileMN",
435
      ErrorKind::TooLarge                  => "Needed data size is too large",
436
      ErrorKind::Many0Count                => "Count occurrence of >=0 patterns",
437
      ErrorKind::Many1Count                => "Count occurrence of >=1 patterns",
438
      ErrorKind::Float                     => "Float",
439
      ErrorKind::Satisfy                   => "Satisfy",
440
      ErrorKind::Fail                      => "Fail",
441
      ErrorKind::Many                      => "Many",
442
      ErrorKind::Fold                      => "Fold",
443
      ErrorKind::Precedence                => "Precedence",
444
    }
445
  }
446
}
447
448
/// Creates a parse error from a `nom::ErrorKind`
449
/// and the position in the input
450
#[allow(unused_variables)]
451
#[macro_export(local_inner_macros)]
452
macro_rules! error_position(
453
  ($input:expr, $code:expr $(,)?) => ({
454
    $crate::error::make_error($input, $code)
455
  });
456
);
457
458
/// Creates a parse error from a `nom::ErrorKind`,
459
/// the position in the input and the next error in
460
/// the parsing tree
461
#[allow(unused_variables)]
462
#[macro_export(local_inner_macros)]
463
macro_rules! error_node_position(
464
  ($input:expr, $code:expr, $next:expr $(,)?) => ({
465
    $crate::error::append_error($input, $code, $next)
466
  });
467
);
468
469
/// Prints a message and the input if the parser fails.
470
///
471
/// The message prints the `Error` or `Incomplete`
472
/// and the parser's calling code.
473
///
474
/// It also displays the input in hexdump format
475
///
476
/// ```rust
477
/// use nom::{IResult, error::dbg_dmp, bytes::complete::tag};
478
///
479
/// fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
480
///   dbg_dmp(tag("abcd"), "tag")(i)
481
/// }
482
///
483
///   let a = &b"efghijkl"[..];
484
///
485
/// // Will print the following message:
486
/// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) '
487
/// // 00000000        65 66 67 68 69 6a 6b 6c         efghijkl
488
/// f(a);
489
/// ```
490
#[cfg(feature = "std")]
491
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
492
0
pub fn dbg_dmp<'a, F, O, E: std::fmt::Debug>(
493
0
  f: F,
494
0
  context: &'static str,
495
0
) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E>
496
0
where
497
0
  F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
498
0
{
499
  use crate::HexDisplay;
500
0
  move |i: &'a [u8]| match f(i) {
501
0
    Err(e) => {
502
0
      println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8));
503
0
      Err(e)
504
    }
505
0
    a => a,
506
0
  }
507
0
}
508
509
#[cfg(test)]
510
mod tests {
511
  use super::*;
512
513
  #[test]
514
  fn context_test() {
515
    use crate::{character::char, combinator::cut, internal::Needed};
516
517
    #[derive(Debug, PartialEq)]
518
    struct Error<I> {
519
      input: I,
520
      ctx: Option<&'static str>,
521
    }
522
523
    impl<I> ParseError<I> for Error<I> {
524
      fn from_error_kind(input: I, _kind: ErrorKind) -> Self {
525
        Self { input, ctx: None }
526
      }
527
528
      fn append(input: I, _kind: ErrorKind, other: Self) -> Self {
529
        Self {
530
          input,
531
          ctx: other.ctx,
532
        }
533
      }
534
    }
535
536
    impl<I> ContextError<I> for Error<I> {
537
      fn add_context(input: I, ctx: &'static str, _other: Self) -> Self {
538
        Self {
539
          input,
540
          ctx: Some(ctx),
541
        }
542
      }
543
    }
544
545
    assert_eq!(
546
      context("ctx", char::<_, Error<_>>('a')).parse("abcd"),
547
      Ok(("bcd", 'a'))
548
    );
549
    assert_eq!(
550
      context("ctx", char::<_, Error<_>>('a')).parse(""),
551
      Err(Err::Incomplete(Needed::new(1)))
552
    );
553
    assert_eq!(
554
      context("ctx", char::<_, Error<_>>('a')).parse_complete(""),
555
      Err(Err::Error(Error {
556
        input: "",
557
        ctx: Some("ctx")
558
      }))
559
    );
560
    assert_eq!(
561
      context("ctx", cut(char::<_, Error<_>>('a'))).parse("bcd"),
562
      Err(Err::Failure(Error {
563
        input: "bcd",
564
        ctx: Some("ctx")
565
      }))
566
    );
567
  }
568
569
  #[cfg(feature = "alloc")]
570
  #[test]
571
  fn clone_error() {
572
    use crate::lib::std::string::String;
573
    let err = Error {
574
      code: ErrorKind::Eof,
575
      input: "test",
576
    };
577
578
    let _err: Error<String> = err.cloned();
579
  }
580
581
  #[test]
582
  fn copy_error() {
583
    let err = Error {
584
      code: ErrorKind::Eof,
585
      input: &0_u8,
586
    };
587
588
    let _err: Error<u8> = err.copied();
589
  }
590
}
591
592
/*
593
#[cfg(feature = "alloc")]
594
use lib::std::{vec::Vec, collections::HashMap};
595
596
#[cfg(feature = "std")]
597
use lib::std::hash::Hash;
598
599
#[cfg(feature = "std")]
600
pub fn add_error_pattern<'a, I: Clone + Hash + Eq, O, E: Clone + Hash + Eq>(
601
  h: &mut HashMap<VerboseError<I>, &'a str>,
602
  e: VerboseError<I>,
603
  message: &'a str,
604
) -> bool {
605
  h.insert(e, message);
606
  true
607
}
608
609
pub fn slice_to_offsets(input: &[u8], s: &[u8]) -> (usize, usize) {
610
  let start = input.as_ptr();
611
  let off1 = s.as_ptr() as usize - start as usize;
612
  let off2 = off1 + s.len();
613
  (off1, off2)
614
}
615
616
#[cfg(feature = "std")]
617
pub fn prepare_errors<O, E: Clone>(input: &[u8], e: VerboseError<&[u8]>) -> Option<Vec<(ErrorKind, usize, usize)>> {
618
  let mut v: Vec<(ErrorKind, usize, usize)> = Vec::new();
619
620
  for (p, kind) in e.errors.drain(..) {
621
    let (o1, o2) = slice_to_offsets(input, p);
622
    v.push((kind, o1, o2));
623
  }
624
625
  v.reverse();
626
  Some(v)
627
}
628
629
#[cfg(feature = "std")]
630
pub fn print_error<O, E: Clone>(input: &[u8], res: VerboseError<&[u8]>) {
631
  if let Some(v) = prepare_errors(input, res) {
632
    let colors = generate_colors(&v);
633
    println!("parser codes: {}", print_codes(&colors, &HashMap::new()));
634
    println!("{}", print_offsets(input, 0, &v));
635
  } else {
636
    println!("not an error");
637
  }
638
}
639
640
#[cfg(feature = "std")]
641
pub fn generate_colors<E>(v: &[(ErrorKind, usize, usize)]) -> HashMap<u32, u8> {
642
  let mut h: HashMap<u32, u8> = HashMap::new();
643
  let mut color = 0;
644
645
  for &(ref c, _, _) in v.iter() {
646
    h.insert(error_to_u32(c), color + 31);
647
    color = color + 1 % 7;
648
  }
649
650
  h
651
}
652
653
pub fn code_from_offset(v: &[(ErrorKind, usize, usize)], offset: usize) -> Option<u32> {
654
  let mut acc: Option<(u32, usize, usize)> = None;
655
  for &(ref ek, s, e) in v.iter() {
656
    let c = error_to_u32(ek);
657
    if s <= offset && offset <= e {
658
      if let Some((_, start, end)) = acc {
659
        if start <= s && e <= end {
660
          acc = Some((c, s, e));
661
        }
662
      } else {
663
        acc = Some((c, s, e));
664
      }
665
    }
666
  }
667
  if let Some((code, _, _)) = acc {
668
    return Some(code);
669
  } else {
670
    return None;
671
  }
672
}
673
674
#[cfg(feature = "alloc")]
675
pub fn reset_color(v: &mut Vec<u8>) {
676
  v.push(0x1B);
677
  v.push(b'[');
678
  v.push(0);
679
  v.push(b'm');
680
}
681
682
#[cfg(feature = "alloc")]
683
pub fn write_color(v: &mut Vec<u8>, color: u8) {
684
  v.push(0x1B);
685
  v.push(b'[');
686
  v.push(1);
687
  v.push(b';');
688
  let s = color.to_string();
689
  let bytes = s.as_bytes();
690
  v.extend(bytes.iter().cloned());
691
  v.push(b'm');
692
}
693
694
#[cfg(feature = "std")]
695
#[cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
696
pub fn print_codes(colors: &HashMap<u32, u8>, names: &HashMap<u32, &str>) -> String {
697
  let mut v = Vec::new();
698
  for (code, &color) in colors {
699
    if let Some(&s) = names.get(code) {
700
      let bytes = s.as_bytes();
701
      write_color(&mut v, color);
702
      v.extend(bytes.iter().cloned());
703
    } else {
704
      let s = code.to_string();
705
      let bytes = s.as_bytes();
706
      write_color(&mut v, color);
707
      v.extend(bytes.iter().cloned());
708
    }
709
    reset_color(&mut v);
710
    v.push(b' ');
711
  }
712
  reset_color(&mut v);
713
714
  String::from_utf8_lossy(&v[..]).into_owned()
715
}
716
717
#[cfg(feature = "std")]
718
pub fn print_offsets(input: &[u8], from: usize, offsets: &[(ErrorKind, usize, usize)]) -> String {
719
  let mut v = Vec::with_capacity(input.len() * 3);
720
  let mut i = from;
721
  let chunk_size = 8;
722
  let mut current_code: Option<u32> = None;
723
  let mut current_code2: Option<u32> = None;
724
725
  let colors = generate_colors(&offsets);
726
727
  for chunk in input.chunks(chunk_size) {
728
    let s = format!("{:08x}", i);
729
    for &ch in s.as_bytes().iter() {
730
      v.push(ch);
731
    }
732
    v.push(b'\t');
733
734
    let mut k = i;
735
    let mut l = i;
736
    for &byte in chunk {
737
      if let Some(code) = code_from_offset(&offsets, k) {
738
        if let Some(current) = current_code {
739
          if current != code {
740
            reset_color(&mut v);
741
            current_code = Some(code);
742
            if let Some(&color) = colors.get(&code) {
743
              write_color(&mut v, color);
744
            }
745
          }
746
        } else {
747
          current_code = Some(code);
748
          if let Some(&color) = colors.get(&code) {
749
            write_color(&mut v, color);
750
          }
751
        }
752
      }
753
      v.push(CHARS[(byte >> 4) as usize]);
754
      v.push(CHARS[(byte & 0xf) as usize]);
755
      v.push(b' ');
756
      k = k + 1;
757
    }
758
759
    reset_color(&mut v);
760
761
    if chunk_size > chunk.len() {
762
      for _ in 0..(chunk_size - chunk.len()) {
763
        v.push(b' ');
764
        v.push(b' ');
765
        v.push(b' ');
766
      }
767
    }
768
    v.push(b'\t');
769
770
    for &byte in chunk {
771
      if let Some(code) = code_from_offset(&offsets, l) {
772
        if let Some(current) = current_code2 {
773
          if current != code {
774
            reset_color(&mut v);
775
            current_code2 = Some(code);
776
            if let Some(&color) = colors.get(&code) {
777
              write_color(&mut v, color);
778
            }
779
          }
780
        } else {
781
          current_code2 = Some(code);
782
          if let Some(&color) = colors.get(&code) {
783
            write_color(&mut v, color);
784
          }
785
        }
786
      }
787
      if (byte >= 32 && byte <= 126) || byte >= 128 {
788
        v.push(byte);
789
      } else {
790
        v.push(b'.');
791
      }
792
      l = l + 1;
793
    }
794
    reset_color(&mut v);
795
796
    v.push(b'\n');
797
    i = i + chunk_size;
798
  }
799
800
  String::from_utf8_lossy(&v[..]).into_owned()
801
}
802
*/