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