16855e09eSopenharmony_ci//! Error management 26855e09eSopenharmony_ci//! 36855e09eSopenharmony_ci//! Parsers are generic over their error type, requiring that it implements 46855e09eSopenharmony_ci//! the `error::ParseError<Input>` trait. 56855e09eSopenharmony_ci 66855e09eSopenharmony_ciuse crate::internal::Parser; 76855e09eSopenharmony_ciuse crate::lib::std::fmt; 86855e09eSopenharmony_ci 96855e09eSopenharmony_ci/// This trait must be implemented by the error type of a nom parser. 106855e09eSopenharmony_ci/// 116855e09eSopenharmony_ci/// There are already implementations of it for `(Input, ErrorKind)` 126855e09eSopenharmony_ci/// and `VerboseError<Input>`. 136855e09eSopenharmony_ci/// 146855e09eSopenharmony_ci/// It provides methods to create an error from some combinators, 156855e09eSopenharmony_ci/// and combine existing errors in combinators like `alt`. 166855e09eSopenharmony_cipub trait ParseError<I>: Sized { 176855e09eSopenharmony_ci /// Creates an error from the input position and an [ErrorKind] 186855e09eSopenharmony_ci fn from_error_kind(input: I, kind: ErrorKind) -> Self; 196855e09eSopenharmony_ci 206855e09eSopenharmony_ci /// Combines an existing error with a new one created from the input 216855e09eSopenharmony_ci /// position and an [ErrorKind]. This is useful when backtracking 226855e09eSopenharmony_ci /// through a parse tree, accumulating error context on the way 236855e09eSopenharmony_ci fn append(input: I, kind: ErrorKind, other: Self) -> Self; 246855e09eSopenharmony_ci 256855e09eSopenharmony_ci /// Creates an error from an input position and an expected character 266855e09eSopenharmony_ci fn from_char(input: I, _: char) -> Self { 276855e09eSopenharmony_ci Self::from_error_kind(input, ErrorKind::Char) 286855e09eSopenharmony_ci } 296855e09eSopenharmony_ci 306855e09eSopenharmony_ci /// Combines two existing errors. This function is used to compare errors 316855e09eSopenharmony_ci /// generated in various branches of `alt`. 326855e09eSopenharmony_ci fn or(self, other: Self) -> Self { 336855e09eSopenharmony_ci other 346855e09eSopenharmony_ci } 356855e09eSopenharmony_ci} 366855e09eSopenharmony_ci 376855e09eSopenharmony_ci/// This trait is required by the `context` combinator to add a static string 386855e09eSopenharmony_ci/// to an existing error 396855e09eSopenharmony_cipub trait ContextError<I>: Sized { 406855e09eSopenharmony_ci /// Creates a new error from an input position, a static string and an existing error. 416855e09eSopenharmony_ci /// This is used mainly in the [context] combinator, to add user friendly information 426855e09eSopenharmony_ci /// to errors when backtracking through a parse tree 436855e09eSopenharmony_ci fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self { 446855e09eSopenharmony_ci other 456855e09eSopenharmony_ci } 466855e09eSopenharmony_ci} 476855e09eSopenharmony_ci 486855e09eSopenharmony_ci/// This trait is required by the `map_res` combinator to integrate 496855e09eSopenharmony_ci/// error types from external functions, like [std::str::FromStr] 506855e09eSopenharmony_cipub trait FromExternalError<I, E> { 516855e09eSopenharmony_ci /// Creates a new error from an input position, an [ErrorKind] indicating the 526855e09eSopenharmony_ci /// wrapping parser, and an external error 536855e09eSopenharmony_ci fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self; 546855e09eSopenharmony_ci} 556855e09eSopenharmony_ci 566855e09eSopenharmony_ci/// default error type, only contains the error' location and code 576855e09eSopenharmony_ci#[derive(Debug, PartialEq)] 586855e09eSopenharmony_cipub struct Error<I> { 596855e09eSopenharmony_ci /// position of the error in the input data 606855e09eSopenharmony_ci pub input: I, 616855e09eSopenharmony_ci /// nom error code 626855e09eSopenharmony_ci pub code: ErrorKind, 636855e09eSopenharmony_ci} 646855e09eSopenharmony_ci 656855e09eSopenharmony_ciimpl<I> Error<I> { 666855e09eSopenharmony_ci /// creates a new basic error 676855e09eSopenharmony_ci pub fn new(input: I, code: ErrorKind) -> Error<I> { 686855e09eSopenharmony_ci Error { input, code } 696855e09eSopenharmony_ci } 706855e09eSopenharmony_ci} 716855e09eSopenharmony_ci 726855e09eSopenharmony_ciimpl<I> ParseError<I> for Error<I> { 736855e09eSopenharmony_ci fn from_error_kind(input: I, kind: ErrorKind) -> Self { 746855e09eSopenharmony_ci Error { input, code: kind } 756855e09eSopenharmony_ci } 766855e09eSopenharmony_ci 776855e09eSopenharmony_ci fn append(_: I, _: ErrorKind, other: Self) -> Self { 786855e09eSopenharmony_ci other 796855e09eSopenharmony_ci } 806855e09eSopenharmony_ci} 816855e09eSopenharmony_ci 826855e09eSopenharmony_ciimpl<I> ContextError<I> for Error<I> {} 836855e09eSopenharmony_ci 846855e09eSopenharmony_ciimpl<I, E> FromExternalError<I, E> for Error<I> { 856855e09eSopenharmony_ci /// Create a new error from an input position and an external error 866855e09eSopenharmony_ci fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self { 876855e09eSopenharmony_ci Error { input, code: kind } 886855e09eSopenharmony_ci } 896855e09eSopenharmony_ci} 906855e09eSopenharmony_ci 916855e09eSopenharmony_ci/// The Display implementation allows the std::error::Error implementation 926855e09eSopenharmony_ciimpl<I: fmt::Display> fmt::Display for Error<I> { 936855e09eSopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 946855e09eSopenharmony_ci write!(f, "error {:?} at: {}", self.code, self.input) 956855e09eSopenharmony_ci } 966855e09eSopenharmony_ci} 976855e09eSopenharmony_ci 986855e09eSopenharmony_ci#[cfg(feature = "std")] 996855e09eSopenharmony_ciimpl<I: fmt::Debug + fmt::Display> std::error::Error for Error<I> {} 1006855e09eSopenharmony_ci 1016855e09eSopenharmony_ci// for backward compatibility, keep those trait implementations 1026855e09eSopenharmony_ci// for the previously used error type 1036855e09eSopenharmony_ciimpl<I> ParseError<I> for (I, ErrorKind) { 1046855e09eSopenharmony_ci fn from_error_kind(input: I, kind: ErrorKind) -> Self { 1056855e09eSopenharmony_ci (input, kind) 1066855e09eSopenharmony_ci } 1076855e09eSopenharmony_ci 1086855e09eSopenharmony_ci fn append(_: I, _: ErrorKind, other: Self) -> Self { 1096855e09eSopenharmony_ci other 1106855e09eSopenharmony_ci } 1116855e09eSopenharmony_ci} 1126855e09eSopenharmony_ci 1136855e09eSopenharmony_ciimpl<I> ContextError<I> for (I, ErrorKind) {} 1146855e09eSopenharmony_ci 1156855e09eSopenharmony_ciimpl<I, E> FromExternalError<I, E> for (I, ErrorKind) { 1166855e09eSopenharmony_ci fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self { 1176855e09eSopenharmony_ci (input, kind) 1186855e09eSopenharmony_ci } 1196855e09eSopenharmony_ci} 1206855e09eSopenharmony_ci 1216855e09eSopenharmony_ciimpl<I> ParseError<I> for () { 1226855e09eSopenharmony_ci fn from_error_kind(_: I, _: ErrorKind) -> Self {} 1236855e09eSopenharmony_ci 1246855e09eSopenharmony_ci fn append(_: I, _: ErrorKind, _: Self) -> Self {} 1256855e09eSopenharmony_ci} 1266855e09eSopenharmony_ci 1276855e09eSopenharmony_ciimpl<I> ContextError<I> for () {} 1286855e09eSopenharmony_ci 1296855e09eSopenharmony_ciimpl<I, E> FromExternalError<I, E> for () { 1306855e09eSopenharmony_ci fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {} 1316855e09eSopenharmony_ci} 1326855e09eSopenharmony_ci 1336855e09eSopenharmony_ci/// Creates an error from the input position and an [ErrorKind] 1346855e09eSopenharmony_cipub fn make_error<I, E: ParseError<I>>(input: I, kind: ErrorKind) -> E { 1356855e09eSopenharmony_ci E::from_error_kind(input, kind) 1366855e09eSopenharmony_ci} 1376855e09eSopenharmony_ci 1386855e09eSopenharmony_ci/// Combines an existing error with a new one created from the input 1396855e09eSopenharmony_ci/// position and an [ErrorKind]. This is useful when backtracking 1406855e09eSopenharmony_ci/// through a parse tree, accumulating error context on the way 1416855e09eSopenharmony_cipub fn append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) -> E { 1426855e09eSopenharmony_ci E::append(input, kind, other) 1436855e09eSopenharmony_ci} 1446855e09eSopenharmony_ci 1456855e09eSopenharmony_ci/// This error type accumulates errors and their position when backtracking 1466855e09eSopenharmony_ci/// through a parse tree. With some post processing (cf `examples/json.rs`), 1476855e09eSopenharmony_ci/// it can be used to display user friendly error messages 1486855e09eSopenharmony_ci#[cfg(feature = "alloc")] 1496855e09eSopenharmony_ci#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] 1506855e09eSopenharmony_ci#[derive(Clone, Debug, PartialEq)] 1516855e09eSopenharmony_cipub struct VerboseError<I> { 1526855e09eSopenharmony_ci /// List of errors accumulated by `VerboseError`, containing the affected 1536855e09eSopenharmony_ci /// part of input data, and some context 1546855e09eSopenharmony_ci pub errors: crate::lib::std::vec::Vec<(I, VerboseErrorKind)>, 1556855e09eSopenharmony_ci} 1566855e09eSopenharmony_ci 1576855e09eSopenharmony_ci#[cfg(feature = "alloc")] 1586855e09eSopenharmony_ci#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] 1596855e09eSopenharmony_ci#[derive(Clone, Debug, PartialEq)] 1606855e09eSopenharmony_ci/// Error context for `VerboseError` 1616855e09eSopenharmony_cipub enum VerboseErrorKind { 1626855e09eSopenharmony_ci /// Static string added by the `context` function 1636855e09eSopenharmony_ci Context(&'static str), 1646855e09eSopenharmony_ci /// Indicates which character was expected by the `char` function 1656855e09eSopenharmony_ci Char(char), 1666855e09eSopenharmony_ci /// Error kind given by various nom parsers 1676855e09eSopenharmony_ci Nom(ErrorKind), 1686855e09eSopenharmony_ci} 1696855e09eSopenharmony_ci 1706855e09eSopenharmony_ci#[cfg(feature = "alloc")] 1716855e09eSopenharmony_ci#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] 1726855e09eSopenharmony_ciimpl<I> ParseError<I> for VerboseError<I> { 1736855e09eSopenharmony_ci fn from_error_kind(input: I, kind: ErrorKind) -> Self { 1746855e09eSopenharmony_ci VerboseError { 1756855e09eSopenharmony_ci errors: vec![(input, VerboseErrorKind::Nom(kind))], 1766855e09eSopenharmony_ci } 1776855e09eSopenharmony_ci } 1786855e09eSopenharmony_ci 1796855e09eSopenharmony_ci fn append(input: I, kind: ErrorKind, mut other: Self) -> Self { 1806855e09eSopenharmony_ci other.errors.push((input, VerboseErrorKind::Nom(kind))); 1816855e09eSopenharmony_ci other 1826855e09eSopenharmony_ci } 1836855e09eSopenharmony_ci 1846855e09eSopenharmony_ci fn from_char(input: I, c: char) -> Self { 1856855e09eSopenharmony_ci VerboseError { 1866855e09eSopenharmony_ci errors: vec![(input, VerboseErrorKind::Char(c))], 1876855e09eSopenharmony_ci } 1886855e09eSopenharmony_ci } 1896855e09eSopenharmony_ci} 1906855e09eSopenharmony_ci 1916855e09eSopenharmony_ci#[cfg(feature = "alloc")] 1926855e09eSopenharmony_ci#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] 1936855e09eSopenharmony_ciimpl<I> ContextError<I> for VerboseError<I> { 1946855e09eSopenharmony_ci fn add_context(input: I, ctx: &'static str, mut other: Self) -> Self { 1956855e09eSopenharmony_ci other.errors.push((input, VerboseErrorKind::Context(ctx))); 1966855e09eSopenharmony_ci other 1976855e09eSopenharmony_ci } 1986855e09eSopenharmony_ci} 1996855e09eSopenharmony_ci 2006855e09eSopenharmony_ci#[cfg(feature = "alloc")] 2016855e09eSopenharmony_ci#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] 2026855e09eSopenharmony_ciimpl<I, E> FromExternalError<I, E> for VerboseError<I> { 2036855e09eSopenharmony_ci /// Create a new error from an input position and an external error 2046855e09eSopenharmony_ci fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self { 2056855e09eSopenharmony_ci Self::from_error_kind(input, kind) 2066855e09eSopenharmony_ci } 2076855e09eSopenharmony_ci} 2086855e09eSopenharmony_ci 2096855e09eSopenharmony_ci#[cfg(feature = "alloc")] 2106855e09eSopenharmony_ciimpl<I: fmt::Display> fmt::Display for VerboseError<I> { 2116855e09eSopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 2126855e09eSopenharmony_ci writeln!(f, "Parse error:")?; 2136855e09eSopenharmony_ci for (input, error) in &self.errors { 2146855e09eSopenharmony_ci match error { 2156855e09eSopenharmony_ci VerboseErrorKind::Nom(e) => writeln!(f, "{:?} at: {}", e, input)?, 2166855e09eSopenharmony_ci VerboseErrorKind::Char(c) => writeln!(f, "expected '{}' at: {}", c, input)?, 2176855e09eSopenharmony_ci VerboseErrorKind::Context(s) => writeln!(f, "in section '{}', at: {}", s, input)?, 2186855e09eSopenharmony_ci } 2196855e09eSopenharmony_ci } 2206855e09eSopenharmony_ci 2216855e09eSopenharmony_ci Ok(()) 2226855e09eSopenharmony_ci } 2236855e09eSopenharmony_ci} 2246855e09eSopenharmony_ci 2256855e09eSopenharmony_ci#[cfg(feature = "std")] 2266855e09eSopenharmony_ciimpl<I: fmt::Debug + fmt::Display> std::error::Error for VerboseError<I> {} 2276855e09eSopenharmony_ci 2286855e09eSopenharmony_ciuse crate::internal::{Err, IResult}; 2296855e09eSopenharmony_ci 2306855e09eSopenharmony_ci/// Create a new error from an input position, a static string and an existing error. 2316855e09eSopenharmony_ci/// This is used mainly in the [context] combinator, to add user friendly information 2326855e09eSopenharmony_ci/// to errors when backtracking through a parse tree 2336855e09eSopenharmony_cipub fn context<I: Clone, E: ContextError<I>, F, O>( 2346855e09eSopenharmony_ci context: &'static str, 2356855e09eSopenharmony_ci mut f: F, 2366855e09eSopenharmony_ci) -> impl FnMut(I) -> IResult<I, O, E> 2376855e09eSopenharmony_ciwhere 2386855e09eSopenharmony_ci F: Parser<I, O, E>, 2396855e09eSopenharmony_ci{ 2406855e09eSopenharmony_ci move |i: I| match f.parse(i.clone()) { 2416855e09eSopenharmony_ci Ok(o) => Ok(o), 2426855e09eSopenharmony_ci Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)), 2436855e09eSopenharmony_ci Err(Err::Error(e)) => Err(Err::Error(E::add_context(i, context, e))), 2446855e09eSopenharmony_ci Err(Err::Failure(e)) => Err(Err::Failure(E::add_context(i, context, e))), 2456855e09eSopenharmony_ci } 2466855e09eSopenharmony_ci} 2476855e09eSopenharmony_ci 2486855e09eSopenharmony_ci/// Transforms a `VerboseError` into a trace with input position information 2496855e09eSopenharmony_ci#[cfg(feature = "alloc")] 2506855e09eSopenharmony_ci#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] 2516855e09eSopenharmony_cipub fn convert_error<I: core::ops::Deref<Target = str>>( 2526855e09eSopenharmony_ci input: I, 2536855e09eSopenharmony_ci e: VerboseError<I>, 2546855e09eSopenharmony_ci) -> crate::lib::std::string::String { 2556855e09eSopenharmony_ci use crate::lib::std::fmt::Write; 2566855e09eSopenharmony_ci use crate::traits::Offset; 2576855e09eSopenharmony_ci 2586855e09eSopenharmony_ci let mut result = crate::lib::std::string::String::new(); 2596855e09eSopenharmony_ci 2606855e09eSopenharmony_ci for (i, (substring, kind)) in e.errors.iter().enumerate() { 2616855e09eSopenharmony_ci let offset = input.offset(substring); 2626855e09eSopenharmony_ci 2636855e09eSopenharmony_ci if input.is_empty() { 2646855e09eSopenharmony_ci match kind { 2656855e09eSopenharmony_ci VerboseErrorKind::Char(c) => { 2666855e09eSopenharmony_ci write!(&mut result, "{}: expected '{}', got empty input\n\n", i, c) 2676855e09eSopenharmony_ci } 2686855e09eSopenharmony_ci VerboseErrorKind::Context(s) => write!(&mut result, "{}: in {}, got empty input\n\n", i, s), 2696855e09eSopenharmony_ci VerboseErrorKind::Nom(e) => write!(&mut result, "{}: in {:?}, got empty input\n\n", i, e), 2706855e09eSopenharmony_ci } 2716855e09eSopenharmony_ci } else { 2726855e09eSopenharmony_ci let prefix = &input.as_bytes()[..offset]; 2736855e09eSopenharmony_ci 2746855e09eSopenharmony_ci // Count the number of newlines in the first `offset` bytes of input 2756855e09eSopenharmony_ci let line_number = prefix.iter().filter(|&&b| b == b'\n').count() + 1; 2766855e09eSopenharmony_ci 2776855e09eSopenharmony_ci // Find the line that includes the subslice: 2786855e09eSopenharmony_ci // Find the *last* newline before the substring starts 2796855e09eSopenharmony_ci let line_begin = prefix 2806855e09eSopenharmony_ci .iter() 2816855e09eSopenharmony_ci .rev() 2826855e09eSopenharmony_ci .position(|&b| b == b'\n') 2836855e09eSopenharmony_ci .map(|pos| offset - pos) 2846855e09eSopenharmony_ci .unwrap_or(0); 2856855e09eSopenharmony_ci 2866855e09eSopenharmony_ci // Find the full line after that newline 2876855e09eSopenharmony_ci let line = input[line_begin..] 2886855e09eSopenharmony_ci .lines() 2896855e09eSopenharmony_ci .next() 2906855e09eSopenharmony_ci .unwrap_or(&input[line_begin..]) 2916855e09eSopenharmony_ci .trim_end(); 2926855e09eSopenharmony_ci 2936855e09eSopenharmony_ci // The (1-indexed) column number is the offset of our substring into that line 2946855e09eSopenharmony_ci let column_number = line.offset(substring) + 1; 2956855e09eSopenharmony_ci 2966855e09eSopenharmony_ci match kind { 2976855e09eSopenharmony_ci VerboseErrorKind::Char(c) => { 2986855e09eSopenharmony_ci if let Some(actual) = substring.chars().next() { 2996855e09eSopenharmony_ci write!( 3006855e09eSopenharmony_ci &mut result, 3016855e09eSopenharmony_ci "{i}: at line {line_number}:\n\ 3026855e09eSopenharmony_ci {line}\n\ 3036855e09eSopenharmony_ci {caret:>column$}\n\ 3046855e09eSopenharmony_ci expected '{expected}', found {actual}\n\n", 3056855e09eSopenharmony_ci i = i, 3066855e09eSopenharmony_ci line_number = line_number, 3076855e09eSopenharmony_ci line = line, 3086855e09eSopenharmony_ci caret = '^', 3096855e09eSopenharmony_ci column = column_number, 3106855e09eSopenharmony_ci expected = c, 3116855e09eSopenharmony_ci actual = actual, 3126855e09eSopenharmony_ci ) 3136855e09eSopenharmony_ci } else { 3146855e09eSopenharmony_ci write!( 3156855e09eSopenharmony_ci &mut result, 3166855e09eSopenharmony_ci "{i}: at line {line_number}:\n\ 3176855e09eSopenharmony_ci {line}\n\ 3186855e09eSopenharmony_ci {caret:>column$}\n\ 3196855e09eSopenharmony_ci expected '{expected}', got end of input\n\n", 3206855e09eSopenharmony_ci i = i, 3216855e09eSopenharmony_ci line_number = line_number, 3226855e09eSopenharmony_ci line = line, 3236855e09eSopenharmony_ci caret = '^', 3246855e09eSopenharmony_ci column = column_number, 3256855e09eSopenharmony_ci expected = c, 3266855e09eSopenharmony_ci ) 3276855e09eSopenharmony_ci } 3286855e09eSopenharmony_ci } 3296855e09eSopenharmony_ci VerboseErrorKind::Context(s) => write!( 3306855e09eSopenharmony_ci &mut result, 3316855e09eSopenharmony_ci "{i}: at line {line_number}, in {context}:\n\ 3326855e09eSopenharmony_ci {line}\n\ 3336855e09eSopenharmony_ci {caret:>column$}\n\n", 3346855e09eSopenharmony_ci i = i, 3356855e09eSopenharmony_ci line_number = line_number, 3366855e09eSopenharmony_ci context = s, 3376855e09eSopenharmony_ci line = line, 3386855e09eSopenharmony_ci caret = '^', 3396855e09eSopenharmony_ci column = column_number, 3406855e09eSopenharmony_ci ), 3416855e09eSopenharmony_ci VerboseErrorKind::Nom(e) => write!( 3426855e09eSopenharmony_ci &mut result, 3436855e09eSopenharmony_ci "{i}: at line {line_number}, in {nom_err:?}:\n\ 3446855e09eSopenharmony_ci {line}\n\ 3456855e09eSopenharmony_ci {caret:>column$}\n\n", 3466855e09eSopenharmony_ci i = i, 3476855e09eSopenharmony_ci line_number = line_number, 3486855e09eSopenharmony_ci nom_err = e, 3496855e09eSopenharmony_ci line = line, 3506855e09eSopenharmony_ci caret = '^', 3516855e09eSopenharmony_ci column = column_number, 3526855e09eSopenharmony_ci ), 3536855e09eSopenharmony_ci } 3546855e09eSopenharmony_ci } 3556855e09eSopenharmony_ci // Because `write!` to a `String` is infallible, this `unwrap` is fine. 3566855e09eSopenharmony_ci .unwrap(); 3576855e09eSopenharmony_ci } 3586855e09eSopenharmony_ci 3596855e09eSopenharmony_ci result 3606855e09eSopenharmony_ci} 3616855e09eSopenharmony_ci 3626855e09eSopenharmony_ci/// Indicates which parser returned an error 3636855e09eSopenharmony_ci#[rustfmt::skip] 3646855e09eSopenharmony_ci#[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)] 3656855e09eSopenharmony_ci#[allow(deprecated,missing_docs)] 3666855e09eSopenharmony_cipub enum ErrorKind { 3676855e09eSopenharmony_ci Tag, 3686855e09eSopenharmony_ci MapRes, 3696855e09eSopenharmony_ci MapOpt, 3706855e09eSopenharmony_ci Alt, 3716855e09eSopenharmony_ci IsNot, 3726855e09eSopenharmony_ci IsA, 3736855e09eSopenharmony_ci SeparatedList, 3746855e09eSopenharmony_ci SeparatedNonEmptyList, 3756855e09eSopenharmony_ci Many0, 3766855e09eSopenharmony_ci Many1, 3776855e09eSopenharmony_ci ManyTill, 3786855e09eSopenharmony_ci Count, 3796855e09eSopenharmony_ci TakeUntil, 3806855e09eSopenharmony_ci LengthValue, 3816855e09eSopenharmony_ci TagClosure, 3826855e09eSopenharmony_ci Alpha, 3836855e09eSopenharmony_ci Digit, 3846855e09eSopenharmony_ci HexDigit, 3856855e09eSopenharmony_ci OctDigit, 3866855e09eSopenharmony_ci AlphaNumeric, 3876855e09eSopenharmony_ci Space, 3886855e09eSopenharmony_ci MultiSpace, 3896855e09eSopenharmony_ci LengthValueFn, 3906855e09eSopenharmony_ci Eof, 3916855e09eSopenharmony_ci Switch, 3926855e09eSopenharmony_ci TagBits, 3936855e09eSopenharmony_ci OneOf, 3946855e09eSopenharmony_ci NoneOf, 3956855e09eSopenharmony_ci Char, 3966855e09eSopenharmony_ci CrLf, 3976855e09eSopenharmony_ci RegexpMatch, 3986855e09eSopenharmony_ci RegexpMatches, 3996855e09eSopenharmony_ci RegexpFind, 4006855e09eSopenharmony_ci RegexpCapture, 4016855e09eSopenharmony_ci RegexpCaptures, 4026855e09eSopenharmony_ci TakeWhile1, 4036855e09eSopenharmony_ci Complete, 4046855e09eSopenharmony_ci Fix, 4056855e09eSopenharmony_ci Escaped, 4066855e09eSopenharmony_ci EscapedTransform, 4076855e09eSopenharmony_ci NonEmpty, 4086855e09eSopenharmony_ci ManyMN, 4096855e09eSopenharmony_ci Not, 4106855e09eSopenharmony_ci Permutation, 4116855e09eSopenharmony_ci Verify, 4126855e09eSopenharmony_ci TakeTill1, 4136855e09eSopenharmony_ci TakeWhileMN, 4146855e09eSopenharmony_ci TooLarge, 4156855e09eSopenharmony_ci Many0Count, 4166855e09eSopenharmony_ci Many1Count, 4176855e09eSopenharmony_ci Float, 4186855e09eSopenharmony_ci Satisfy, 4196855e09eSopenharmony_ci Fail, 4206855e09eSopenharmony_ci} 4216855e09eSopenharmony_ci 4226855e09eSopenharmony_ci#[rustfmt::skip] 4236855e09eSopenharmony_ci#[allow(deprecated)] 4246855e09eSopenharmony_ci/// Converts an ErrorKind to a number 4256855e09eSopenharmony_cipub fn error_to_u32(e: &ErrorKind) -> u32 { 4266855e09eSopenharmony_ci match *e { 4276855e09eSopenharmony_ci ErrorKind::Tag => 1, 4286855e09eSopenharmony_ci ErrorKind::MapRes => 2, 4296855e09eSopenharmony_ci ErrorKind::MapOpt => 3, 4306855e09eSopenharmony_ci ErrorKind::Alt => 4, 4316855e09eSopenharmony_ci ErrorKind::IsNot => 5, 4326855e09eSopenharmony_ci ErrorKind::IsA => 6, 4336855e09eSopenharmony_ci ErrorKind::SeparatedList => 7, 4346855e09eSopenharmony_ci ErrorKind::SeparatedNonEmptyList => 8, 4356855e09eSopenharmony_ci ErrorKind::Many1 => 9, 4366855e09eSopenharmony_ci ErrorKind::Count => 10, 4376855e09eSopenharmony_ci ErrorKind::TakeUntil => 12, 4386855e09eSopenharmony_ci ErrorKind::LengthValue => 15, 4396855e09eSopenharmony_ci ErrorKind::TagClosure => 16, 4406855e09eSopenharmony_ci ErrorKind::Alpha => 17, 4416855e09eSopenharmony_ci ErrorKind::Digit => 18, 4426855e09eSopenharmony_ci ErrorKind::AlphaNumeric => 19, 4436855e09eSopenharmony_ci ErrorKind::Space => 20, 4446855e09eSopenharmony_ci ErrorKind::MultiSpace => 21, 4456855e09eSopenharmony_ci ErrorKind::LengthValueFn => 22, 4466855e09eSopenharmony_ci ErrorKind::Eof => 23, 4476855e09eSopenharmony_ci ErrorKind::Switch => 27, 4486855e09eSopenharmony_ci ErrorKind::TagBits => 28, 4496855e09eSopenharmony_ci ErrorKind::OneOf => 29, 4506855e09eSopenharmony_ci ErrorKind::NoneOf => 30, 4516855e09eSopenharmony_ci ErrorKind::Char => 40, 4526855e09eSopenharmony_ci ErrorKind::CrLf => 41, 4536855e09eSopenharmony_ci ErrorKind::RegexpMatch => 42, 4546855e09eSopenharmony_ci ErrorKind::RegexpMatches => 43, 4556855e09eSopenharmony_ci ErrorKind::RegexpFind => 44, 4566855e09eSopenharmony_ci ErrorKind::RegexpCapture => 45, 4576855e09eSopenharmony_ci ErrorKind::RegexpCaptures => 46, 4586855e09eSopenharmony_ci ErrorKind::TakeWhile1 => 47, 4596855e09eSopenharmony_ci ErrorKind::Complete => 48, 4606855e09eSopenharmony_ci ErrorKind::Fix => 49, 4616855e09eSopenharmony_ci ErrorKind::Escaped => 50, 4626855e09eSopenharmony_ci ErrorKind::EscapedTransform => 51, 4636855e09eSopenharmony_ci ErrorKind::NonEmpty => 56, 4646855e09eSopenharmony_ci ErrorKind::ManyMN => 57, 4656855e09eSopenharmony_ci ErrorKind::HexDigit => 59, 4666855e09eSopenharmony_ci ErrorKind::OctDigit => 61, 4676855e09eSopenharmony_ci ErrorKind::Many0 => 62, 4686855e09eSopenharmony_ci ErrorKind::Not => 63, 4696855e09eSopenharmony_ci ErrorKind::Permutation => 64, 4706855e09eSopenharmony_ci ErrorKind::ManyTill => 65, 4716855e09eSopenharmony_ci ErrorKind::Verify => 66, 4726855e09eSopenharmony_ci ErrorKind::TakeTill1 => 67, 4736855e09eSopenharmony_ci ErrorKind::TakeWhileMN => 69, 4746855e09eSopenharmony_ci ErrorKind::TooLarge => 70, 4756855e09eSopenharmony_ci ErrorKind::Many0Count => 71, 4766855e09eSopenharmony_ci ErrorKind::Many1Count => 72, 4776855e09eSopenharmony_ci ErrorKind::Float => 73, 4786855e09eSopenharmony_ci ErrorKind::Satisfy => 74, 4796855e09eSopenharmony_ci ErrorKind::Fail => 75, 4806855e09eSopenharmony_ci } 4816855e09eSopenharmony_ci} 4826855e09eSopenharmony_ci 4836855e09eSopenharmony_ciimpl ErrorKind { 4846855e09eSopenharmony_ci #[rustfmt::skip] 4856855e09eSopenharmony_ci #[allow(deprecated)] 4866855e09eSopenharmony_ci /// Converts an ErrorKind to a text description 4876855e09eSopenharmony_ci pub fn description(&self) -> &str { 4886855e09eSopenharmony_ci match *self { 4896855e09eSopenharmony_ci ErrorKind::Tag => "Tag", 4906855e09eSopenharmony_ci ErrorKind::MapRes => "Map on Result", 4916855e09eSopenharmony_ci ErrorKind::MapOpt => "Map on Option", 4926855e09eSopenharmony_ci ErrorKind::Alt => "Alternative", 4936855e09eSopenharmony_ci ErrorKind::IsNot => "IsNot", 4946855e09eSopenharmony_ci ErrorKind::IsA => "IsA", 4956855e09eSopenharmony_ci ErrorKind::SeparatedList => "Separated list", 4966855e09eSopenharmony_ci ErrorKind::SeparatedNonEmptyList => "Separated non empty list", 4976855e09eSopenharmony_ci ErrorKind::Many0 => "Many0", 4986855e09eSopenharmony_ci ErrorKind::Many1 => "Many1", 4996855e09eSopenharmony_ci ErrorKind::Count => "Count", 5006855e09eSopenharmony_ci ErrorKind::TakeUntil => "Take until", 5016855e09eSopenharmony_ci ErrorKind::LengthValue => "Length followed by value", 5026855e09eSopenharmony_ci ErrorKind::TagClosure => "Tag closure", 5036855e09eSopenharmony_ci ErrorKind::Alpha => "Alphabetic", 5046855e09eSopenharmony_ci ErrorKind::Digit => "Digit", 5056855e09eSopenharmony_ci ErrorKind::AlphaNumeric => "AlphaNumeric", 5066855e09eSopenharmony_ci ErrorKind::Space => "Space", 5076855e09eSopenharmony_ci ErrorKind::MultiSpace => "Multiple spaces", 5086855e09eSopenharmony_ci ErrorKind::LengthValueFn => "LengthValueFn", 5096855e09eSopenharmony_ci ErrorKind::Eof => "End of file", 5106855e09eSopenharmony_ci ErrorKind::Switch => "Switch", 5116855e09eSopenharmony_ci ErrorKind::TagBits => "Tag on bitstream", 5126855e09eSopenharmony_ci ErrorKind::OneOf => "OneOf", 5136855e09eSopenharmony_ci ErrorKind::NoneOf => "NoneOf", 5146855e09eSopenharmony_ci ErrorKind::Char => "Char", 5156855e09eSopenharmony_ci ErrorKind::CrLf => "CrLf", 5166855e09eSopenharmony_ci ErrorKind::RegexpMatch => "RegexpMatch", 5176855e09eSopenharmony_ci ErrorKind::RegexpMatches => "RegexpMatches", 5186855e09eSopenharmony_ci ErrorKind::RegexpFind => "RegexpFind", 5196855e09eSopenharmony_ci ErrorKind::RegexpCapture => "RegexpCapture", 5206855e09eSopenharmony_ci ErrorKind::RegexpCaptures => "RegexpCaptures", 5216855e09eSopenharmony_ci ErrorKind::TakeWhile1 => "TakeWhile1", 5226855e09eSopenharmony_ci ErrorKind::Complete => "Complete", 5236855e09eSopenharmony_ci ErrorKind::Fix => "Fix", 5246855e09eSopenharmony_ci ErrorKind::Escaped => "Escaped", 5256855e09eSopenharmony_ci ErrorKind::EscapedTransform => "EscapedTransform", 5266855e09eSopenharmony_ci ErrorKind::NonEmpty => "NonEmpty", 5276855e09eSopenharmony_ci ErrorKind::ManyMN => "Many(m, n)", 5286855e09eSopenharmony_ci ErrorKind::HexDigit => "Hexadecimal Digit", 5296855e09eSopenharmony_ci ErrorKind::OctDigit => "Octal digit", 5306855e09eSopenharmony_ci ErrorKind::Not => "Negation", 5316855e09eSopenharmony_ci ErrorKind::Permutation => "Permutation", 5326855e09eSopenharmony_ci ErrorKind::ManyTill => "ManyTill", 5336855e09eSopenharmony_ci ErrorKind::Verify => "predicate verification", 5346855e09eSopenharmony_ci ErrorKind::TakeTill1 => "TakeTill1", 5356855e09eSopenharmony_ci ErrorKind::TakeWhileMN => "TakeWhileMN", 5366855e09eSopenharmony_ci ErrorKind::TooLarge => "Needed data size is too large", 5376855e09eSopenharmony_ci ErrorKind::Many0Count => "Count occurrence of >=0 patterns", 5386855e09eSopenharmony_ci ErrorKind::Many1Count => "Count occurrence of >=1 patterns", 5396855e09eSopenharmony_ci ErrorKind::Float => "Float", 5406855e09eSopenharmony_ci ErrorKind::Satisfy => "Satisfy", 5416855e09eSopenharmony_ci ErrorKind::Fail => "Fail", 5426855e09eSopenharmony_ci } 5436855e09eSopenharmony_ci } 5446855e09eSopenharmony_ci} 5456855e09eSopenharmony_ci 5466855e09eSopenharmony_ci/// Creates a parse error from a `nom::ErrorKind` 5476855e09eSopenharmony_ci/// and the position in the input 5486855e09eSopenharmony_ci#[allow(unused_variables)] 5496855e09eSopenharmony_ci#[macro_export(local_inner_macros)] 5506855e09eSopenharmony_cimacro_rules! error_position( 5516855e09eSopenharmony_ci ($input:expr, $code:expr) => ({ 5526855e09eSopenharmony_ci $crate::error::make_error($input, $code) 5536855e09eSopenharmony_ci }); 5546855e09eSopenharmony_ci); 5556855e09eSopenharmony_ci 5566855e09eSopenharmony_ci/// Creates a parse error from a `nom::ErrorKind`, 5576855e09eSopenharmony_ci/// the position in the input and the next error in 5586855e09eSopenharmony_ci/// the parsing tree 5596855e09eSopenharmony_ci#[allow(unused_variables)] 5606855e09eSopenharmony_ci#[macro_export(local_inner_macros)] 5616855e09eSopenharmony_cimacro_rules! error_node_position( 5626855e09eSopenharmony_ci ($input:expr, $code:expr, $next:expr) => ({ 5636855e09eSopenharmony_ci $crate::error::append_error($input, $code, $next) 5646855e09eSopenharmony_ci }); 5656855e09eSopenharmony_ci); 5666855e09eSopenharmony_ci 5676855e09eSopenharmony_ci/// Prints a message and the input if the parser fails. 5686855e09eSopenharmony_ci/// 5696855e09eSopenharmony_ci/// The message prints the `Error` or `Incomplete` 5706855e09eSopenharmony_ci/// and the parser's calling code. 5716855e09eSopenharmony_ci/// 5726855e09eSopenharmony_ci/// It also displays the input in hexdump format 5736855e09eSopenharmony_ci/// 5746855e09eSopenharmony_ci/// ```rust 5756855e09eSopenharmony_ci/// use nom::{IResult, error::dbg_dmp, bytes::complete::tag}; 5766855e09eSopenharmony_ci/// 5776855e09eSopenharmony_ci/// fn f(i: &[u8]) -> IResult<&[u8], &[u8]> { 5786855e09eSopenharmony_ci/// dbg_dmp(tag("abcd"), "tag")(i) 5796855e09eSopenharmony_ci/// } 5806855e09eSopenharmony_ci/// 5816855e09eSopenharmony_ci/// let a = &b"efghijkl"[..]; 5826855e09eSopenharmony_ci/// 5836855e09eSopenharmony_ci/// // Will print the following message: 5846855e09eSopenharmony_ci/// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) ' 5856855e09eSopenharmony_ci/// // 00000000 65 66 67 68 69 6a 6b 6c efghijkl 5866855e09eSopenharmony_ci/// f(a); 5876855e09eSopenharmony_ci/// ``` 5886855e09eSopenharmony_ci#[cfg(feature = "std")] 5896855e09eSopenharmony_ci#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))] 5906855e09eSopenharmony_cipub fn dbg_dmp<'a, F, O, E: std::fmt::Debug>( 5916855e09eSopenharmony_ci f: F, 5926855e09eSopenharmony_ci context: &'static str, 5936855e09eSopenharmony_ci) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E> 5946855e09eSopenharmony_ciwhere 5956855e09eSopenharmony_ci F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>, 5966855e09eSopenharmony_ci{ 5976855e09eSopenharmony_ci use crate::HexDisplay; 5986855e09eSopenharmony_ci move |i: &'a [u8]| match f(i) { 5996855e09eSopenharmony_ci Err(e) => { 6006855e09eSopenharmony_ci println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8)); 6016855e09eSopenharmony_ci Err(e) 6026855e09eSopenharmony_ci } 6036855e09eSopenharmony_ci a => a, 6046855e09eSopenharmony_ci } 6056855e09eSopenharmony_ci} 6066855e09eSopenharmony_ci 6076855e09eSopenharmony_ci#[cfg(test)] 6086855e09eSopenharmony_ci#[cfg(feature = "alloc")] 6096855e09eSopenharmony_cimod tests { 6106855e09eSopenharmony_ci use super::*; 6116855e09eSopenharmony_ci use crate::character::complete::char; 6126855e09eSopenharmony_ci 6136855e09eSopenharmony_ci #[test] 6146855e09eSopenharmony_ci fn convert_error_panic() { 6156855e09eSopenharmony_ci let input = ""; 6166855e09eSopenharmony_ci 6176855e09eSopenharmony_ci let _result: IResult<_, _, VerboseError<&str>> = char('x')(input); 6186855e09eSopenharmony_ci } 6196855e09eSopenharmony_ci} 6206855e09eSopenharmony_ci 6216855e09eSopenharmony_ci/* 6226855e09eSopenharmony_ci#[cfg(feature = "alloc")] 6236855e09eSopenharmony_ciuse lib::std::{vec::Vec, collections::HashMap}; 6246855e09eSopenharmony_ci 6256855e09eSopenharmony_ci#[cfg(feature = "std")] 6266855e09eSopenharmony_ciuse lib::std::hash::Hash; 6276855e09eSopenharmony_ci 6286855e09eSopenharmony_ci#[cfg(feature = "std")] 6296855e09eSopenharmony_cipub fn add_error_pattern<'a, I: Clone + Hash + Eq, O, E: Clone + Hash + Eq>( 6306855e09eSopenharmony_ci h: &mut HashMap<VerboseError<I>, &'a str>, 6316855e09eSopenharmony_ci e: VerboseError<I>, 6326855e09eSopenharmony_ci message: &'a str, 6336855e09eSopenharmony_ci) -> bool { 6346855e09eSopenharmony_ci h.insert(e, message); 6356855e09eSopenharmony_ci true 6366855e09eSopenharmony_ci} 6376855e09eSopenharmony_ci 6386855e09eSopenharmony_cipub fn slice_to_offsets(input: &[u8], s: &[u8]) -> (usize, usize) { 6396855e09eSopenharmony_ci let start = input.as_ptr(); 6406855e09eSopenharmony_ci let off1 = s.as_ptr() as usize - start as usize; 6416855e09eSopenharmony_ci let off2 = off1 + s.len(); 6426855e09eSopenharmony_ci (off1, off2) 6436855e09eSopenharmony_ci} 6446855e09eSopenharmony_ci 6456855e09eSopenharmony_ci#[cfg(feature = "std")] 6466855e09eSopenharmony_cipub fn prepare_errors<O, E: Clone>(input: &[u8], e: VerboseError<&[u8]>) -> Option<Vec<(ErrorKind, usize, usize)>> { 6476855e09eSopenharmony_ci let mut v: Vec<(ErrorKind, usize, usize)> = Vec::new(); 6486855e09eSopenharmony_ci 6496855e09eSopenharmony_ci for (p, kind) in e.errors.drain(..) { 6506855e09eSopenharmony_ci let (o1, o2) = slice_to_offsets(input, p); 6516855e09eSopenharmony_ci v.push((kind, o1, o2)); 6526855e09eSopenharmony_ci } 6536855e09eSopenharmony_ci 6546855e09eSopenharmony_ci v.reverse(); 6556855e09eSopenharmony_ci Some(v) 6566855e09eSopenharmony_ci} 6576855e09eSopenharmony_ci 6586855e09eSopenharmony_ci#[cfg(feature = "std")] 6596855e09eSopenharmony_cipub fn print_error<O, E: Clone>(input: &[u8], res: VerboseError<&[u8]>) { 6606855e09eSopenharmony_ci if let Some(v) = prepare_errors(input, res) { 6616855e09eSopenharmony_ci let colors = generate_colors(&v); 6626855e09eSopenharmony_ci println!("parser codes: {}", print_codes(&colors, &HashMap::new())); 6636855e09eSopenharmony_ci println!("{}", print_offsets(input, 0, &v)); 6646855e09eSopenharmony_ci } else { 6656855e09eSopenharmony_ci println!("not an error"); 6666855e09eSopenharmony_ci } 6676855e09eSopenharmony_ci} 6686855e09eSopenharmony_ci 6696855e09eSopenharmony_ci#[cfg(feature = "std")] 6706855e09eSopenharmony_cipub fn generate_colors<E>(v: &[(ErrorKind, usize, usize)]) -> HashMap<u32, u8> { 6716855e09eSopenharmony_ci let mut h: HashMap<u32, u8> = HashMap::new(); 6726855e09eSopenharmony_ci let mut color = 0; 6736855e09eSopenharmony_ci 6746855e09eSopenharmony_ci for &(ref c, _, _) in v.iter() { 6756855e09eSopenharmony_ci h.insert(error_to_u32(c), color + 31); 6766855e09eSopenharmony_ci color = color + 1 % 7; 6776855e09eSopenharmony_ci } 6786855e09eSopenharmony_ci 6796855e09eSopenharmony_ci h 6806855e09eSopenharmony_ci} 6816855e09eSopenharmony_ci 6826855e09eSopenharmony_cipub fn code_from_offset(v: &[(ErrorKind, usize, usize)], offset: usize) -> Option<u32> { 6836855e09eSopenharmony_ci let mut acc: Option<(u32, usize, usize)> = None; 6846855e09eSopenharmony_ci for &(ref ek, s, e) in v.iter() { 6856855e09eSopenharmony_ci let c = error_to_u32(ek); 6866855e09eSopenharmony_ci if s <= offset && offset <= e { 6876855e09eSopenharmony_ci if let Some((_, start, end)) = acc { 6886855e09eSopenharmony_ci if start <= s && e <= end { 6896855e09eSopenharmony_ci acc = Some((c, s, e)); 6906855e09eSopenharmony_ci } 6916855e09eSopenharmony_ci } else { 6926855e09eSopenharmony_ci acc = Some((c, s, e)); 6936855e09eSopenharmony_ci } 6946855e09eSopenharmony_ci } 6956855e09eSopenharmony_ci } 6966855e09eSopenharmony_ci if let Some((code, _, _)) = acc { 6976855e09eSopenharmony_ci return Some(code); 6986855e09eSopenharmony_ci } else { 6996855e09eSopenharmony_ci return None; 7006855e09eSopenharmony_ci } 7016855e09eSopenharmony_ci} 7026855e09eSopenharmony_ci 7036855e09eSopenharmony_ci#[cfg(feature = "alloc")] 7046855e09eSopenharmony_cipub fn reset_color(v: &mut Vec<u8>) { 7056855e09eSopenharmony_ci v.push(0x1B); 7066855e09eSopenharmony_ci v.push(b'['); 7076855e09eSopenharmony_ci v.push(0); 7086855e09eSopenharmony_ci v.push(b'm'); 7096855e09eSopenharmony_ci} 7106855e09eSopenharmony_ci 7116855e09eSopenharmony_ci#[cfg(feature = "alloc")] 7126855e09eSopenharmony_cipub fn write_color(v: &mut Vec<u8>, color: u8) { 7136855e09eSopenharmony_ci v.push(0x1B); 7146855e09eSopenharmony_ci v.push(b'['); 7156855e09eSopenharmony_ci v.push(1); 7166855e09eSopenharmony_ci v.push(b';'); 7176855e09eSopenharmony_ci let s = color.to_string(); 7186855e09eSopenharmony_ci let bytes = s.as_bytes(); 7196855e09eSopenharmony_ci v.extend(bytes.iter().cloned()); 7206855e09eSopenharmony_ci v.push(b'm'); 7216855e09eSopenharmony_ci} 7226855e09eSopenharmony_ci 7236855e09eSopenharmony_ci#[cfg(feature = "std")] 7246855e09eSopenharmony_ci#[cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))] 7256855e09eSopenharmony_cipub fn print_codes(colors: &HashMap<u32, u8>, names: &HashMap<u32, &str>) -> String { 7266855e09eSopenharmony_ci let mut v = Vec::new(); 7276855e09eSopenharmony_ci for (code, &color) in colors { 7286855e09eSopenharmony_ci if let Some(&s) = names.get(code) { 7296855e09eSopenharmony_ci let bytes = s.as_bytes(); 7306855e09eSopenharmony_ci write_color(&mut v, color); 7316855e09eSopenharmony_ci v.extend(bytes.iter().cloned()); 7326855e09eSopenharmony_ci } else { 7336855e09eSopenharmony_ci let s = code.to_string(); 7346855e09eSopenharmony_ci let bytes = s.as_bytes(); 7356855e09eSopenharmony_ci write_color(&mut v, color); 7366855e09eSopenharmony_ci v.extend(bytes.iter().cloned()); 7376855e09eSopenharmony_ci } 7386855e09eSopenharmony_ci reset_color(&mut v); 7396855e09eSopenharmony_ci v.push(b' '); 7406855e09eSopenharmony_ci } 7416855e09eSopenharmony_ci reset_color(&mut v); 7426855e09eSopenharmony_ci 7436855e09eSopenharmony_ci String::from_utf8_lossy(&v[..]).into_owned() 7446855e09eSopenharmony_ci} 7456855e09eSopenharmony_ci 7466855e09eSopenharmony_ci#[cfg(feature = "std")] 7476855e09eSopenharmony_cipub fn print_offsets(input: &[u8], from: usize, offsets: &[(ErrorKind, usize, usize)]) -> String { 7486855e09eSopenharmony_ci let mut v = Vec::with_capacity(input.len() * 3); 7496855e09eSopenharmony_ci let mut i = from; 7506855e09eSopenharmony_ci let chunk_size = 8; 7516855e09eSopenharmony_ci let mut current_code: Option<u32> = None; 7526855e09eSopenharmony_ci let mut current_code2: Option<u32> = None; 7536855e09eSopenharmony_ci 7546855e09eSopenharmony_ci let colors = generate_colors(&offsets); 7556855e09eSopenharmony_ci 7566855e09eSopenharmony_ci for chunk in input.chunks(chunk_size) { 7576855e09eSopenharmony_ci let s = format!("{:08x}", i); 7586855e09eSopenharmony_ci for &ch in s.as_bytes().iter() { 7596855e09eSopenharmony_ci v.push(ch); 7606855e09eSopenharmony_ci } 7616855e09eSopenharmony_ci v.push(b'\t'); 7626855e09eSopenharmony_ci 7636855e09eSopenharmony_ci let mut k = i; 7646855e09eSopenharmony_ci let mut l = i; 7656855e09eSopenharmony_ci for &byte in chunk { 7666855e09eSopenharmony_ci if let Some(code) = code_from_offset(&offsets, k) { 7676855e09eSopenharmony_ci if let Some(current) = current_code { 7686855e09eSopenharmony_ci if current != code { 7696855e09eSopenharmony_ci reset_color(&mut v); 7706855e09eSopenharmony_ci current_code = Some(code); 7716855e09eSopenharmony_ci if let Some(&color) = colors.get(&code) { 7726855e09eSopenharmony_ci write_color(&mut v, color); 7736855e09eSopenharmony_ci } 7746855e09eSopenharmony_ci } 7756855e09eSopenharmony_ci } else { 7766855e09eSopenharmony_ci current_code = Some(code); 7776855e09eSopenharmony_ci if let Some(&color) = colors.get(&code) { 7786855e09eSopenharmony_ci write_color(&mut v, color); 7796855e09eSopenharmony_ci } 7806855e09eSopenharmony_ci } 7816855e09eSopenharmony_ci } 7826855e09eSopenharmony_ci v.push(CHARS[(byte >> 4) as usize]); 7836855e09eSopenharmony_ci v.push(CHARS[(byte & 0xf) as usize]); 7846855e09eSopenharmony_ci v.push(b' '); 7856855e09eSopenharmony_ci k = k + 1; 7866855e09eSopenharmony_ci } 7876855e09eSopenharmony_ci 7886855e09eSopenharmony_ci reset_color(&mut v); 7896855e09eSopenharmony_ci 7906855e09eSopenharmony_ci if chunk_size > chunk.len() { 7916855e09eSopenharmony_ci for _ in 0..(chunk_size - chunk.len()) { 7926855e09eSopenharmony_ci v.push(b' '); 7936855e09eSopenharmony_ci v.push(b' '); 7946855e09eSopenharmony_ci v.push(b' '); 7956855e09eSopenharmony_ci } 7966855e09eSopenharmony_ci } 7976855e09eSopenharmony_ci v.push(b'\t'); 7986855e09eSopenharmony_ci 7996855e09eSopenharmony_ci for &byte in chunk { 8006855e09eSopenharmony_ci if let Some(code) = code_from_offset(&offsets, l) { 8016855e09eSopenharmony_ci if let Some(current) = current_code2 { 8026855e09eSopenharmony_ci if current != code { 8036855e09eSopenharmony_ci reset_color(&mut v); 8046855e09eSopenharmony_ci current_code2 = Some(code); 8056855e09eSopenharmony_ci if let Some(&color) = colors.get(&code) { 8066855e09eSopenharmony_ci write_color(&mut v, color); 8076855e09eSopenharmony_ci } 8086855e09eSopenharmony_ci } 8096855e09eSopenharmony_ci } else { 8106855e09eSopenharmony_ci current_code2 = Some(code); 8116855e09eSopenharmony_ci if let Some(&color) = colors.get(&code) { 8126855e09eSopenharmony_ci write_color(&mut v, color); 8136855e09eSopenharmony_ci } 8146855e09eSopenharmony_ci } 8156855e09eSopenharmony_ci } 8166855e09eSopenharmony_ci if (byte >= 32 && byte <= 126) || byte >= 128 { 8176855e09eSopenharmony_ci v.push(byte); 8186855e09eSopenharmony_ci } else { 8196855e09eSopenharmony_ci v.push(b'.'); 8206855e09eSopenharmony_ci } 8216855e09eSopenharmony_ci l = l + 1; 8226855e09eSopenharmony_ci } 8236855e09eSopenharmony_ci reset_color(&mut v); 8246855e09eSopenharmony_ci 8256855e09eSopenharmony_ci v.push(b'\n'); 8266855e09eSopenharmony_ci i = i + chunk_size; 8276855e09eSopenharmony_ci } 8286855e09eSopenharmony_ci 8296855e09eSopenharmony_ci String::from_utf8_lossy(&v[..]).into_owned() 8306855e09eSopenharmony_ci} 8316855e09eSopenharmony_ci*/ 832