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