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