winnow/combinator/debug/
mod.rs

1#![cfg_attr(feature = "debug", allow(clippy::std_instead_of_core))]
2
3#[cfg(feature = "debug")]
4mod internals;
5
6use crate::error::ErrMode;
7use crate::stream::Stream;
8use crate::Parser;
9
10/// Trace the execution of the parser
11///
12/// Note that [`Parser::context`] also provides high level trace information.
13///
14/// See [tutorial][crate::_tutorial::chapter_8] for more details.
15///
16/// # Example
17///
18/// ```rust
19/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
20/// # use winnow::token::take_while;
21/// # use winnow::stream::AsChar;
22/// # use winnow::prelude::*;
23/// use winnow::combinator::trace;
24///
25/// fn short_alpha<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> {
26///   trace("short_alpha",
27///     take_while(3..=6, AsChar::is_alpha)
28///   ).parse_next(s)
29/// }
30///
31/// assert_eq!(short_alpha.parse_peek(b"latin123"), Ok((&b"123"[..], &b"latin"[..])));
32/// assert_eq!(short_alpha.parse_peek(b"lengthy"), Ok((&b"y"[..], &b"length"[..])));
33/// assert_eq!(short_alpha.parse_peek(b"latin"), Ok((&b""[..], &b"latin"[..])));
34/// assert_eq!(short_alpha.parse_peek(b"ed"), Err(ErrMode::Backtrack(InputError::new(&b"ed"[..], ErrorKind::Slice))));
35/// assert_eq!(short_alpha.parse_peek(b"12345"), Err(ErrMode::Backtrack(InputError::new(&b"12345"[..], ErrorKind::Slice))));
36/// ```
37#[cfg_attr(not(feature = "debug"), allow(unused_variables))]
38#[cfg_attr(not(feature = "debug"), allow(unused_mut))]
39#[cfg_attr(not(feature = "debug"), inline(always))]
40pub fn trace<I: Stream, O, E>(
41    name: impl crate::lib::std::fmt::Display,
42    parser: impl Parser<I, O, E>,
43) -> impl Parser<I, O, E> {
44    #[cfg(feature = "debug")]
45    {
46        internals::Trace::new(parser, name)
47    }
48    #[cfg(not(feature = "debug"))]
49    {
50        parser
51    }
52}
53
54#[cfg_attr(not(feature = "debug"), allow(unused_variables))]
55pub(crate) fn trace_result<T, E>(
56    name: impl crate::lib::std::fmt::Display,
57    res: &Result<T, ErrMode<E>>,
58) {
59    #[cfg(feature = "debug")]
60    {
61        let depth = internals::Depth::existing();
62        let severity = internals::Severity::with_result(res);
63        internals::result(*depth, &name, severity);
64    }
65}
66
67pub(crate) struct DisplayDebug<D>(pub(crate) D);
68
69impl<D: crate::lib::std::fmt::Debug> crate::lib::std::fmt::Display for DisplayDebug<D> {
70    fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
71        write!(f, "{:?}", self.0)
72    }
73}
74
75#[test]
76#[cfg(feature = "std")]
77#[cfg_attr(miri, ignore)]
78#[cfg(unix)]
79#[cfg(feature = "debug")]
80fn example() {
81    use term_transcript::{test::TestConfig, ShellOptions};
82
83    let path = snapbox::cmd::compile_example("string", ["--features=debug"]).unwrap();
84
85    let current_dir = path.parent().unwrap();
86    let cmd = path.file_name().unwrap();
87    // HACK: term_transcript doesn't allow non-UTF8 paths
88    let cmd = format!("./{}", cmd.to_string_lossy());
89
90    TestConfig::new(
91        ShellOptions::default()
92            .with_current_dir(current_dir)
93            .with_env("CLICOLOR_FORCE", "1"),
94    )
95    .test("assets/trace.svg", [cmd.as_str()]);
96}