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, 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, error) in &self.errors { 214 match error { 215 VerboseErrorKind::Nom(e) => writeln!(f, "{:?} at: {}", e, input)?, 216 VerboseErrorKind::Char(c) => writeln!(f, "expected '{}' at: {}", c, input)?, 217 VerboseErrorKind::Context(s) => 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(i.clone()) { 241 Ok(o) => Ok(o), 242 Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)), 243 Err(Err::Error(e)) => Err(Err::Error(E::add_context(i, context, e))), 244 Err(Err::Failure(e)) => Err(Err::Failure(E::add_context(i, context, 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) => { 600 println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8)); 601 Err(e) 602 } 603 a => 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