summaryrefslogtreecommitdiffstats
path: root/vendor/winnow/src/trace/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/winnow/src/trace/mod.rs')
-rw-r--r--vendor/winnow/src/trace/mod.rs118
1 files changed, 118 insertions, 0 deletions
diff --git a/vendor/winnow/src/trace/mod.rs b/vendor/winnow/src/trace/mod.rs
new file mode 100644
index 000000000..59dafba8e
--- /dev/null
+++ b/vendor/winnow/src/trace/mod.rs
@@ -0,0 +1,118 @@
+//! Parser execution tracing
+//!
+//! By default, nothing happens and tracing gets compiled away as a no-op. To enable tracing, use
+//! `--features debug`.
+//!
+//! # Example
+//!
+//!![Trace output from string example](https://raw.githubusercontent.com/winnow-rs/winnow/main/assets/trace.svg "Example output")
+
+#[cfg(feature = "debug")]
+mod internals;
+
+use crate::error::ErrMode;
+use crate::stream::Stream;
+use crate::Parser;
+
+#[cfg(all(feature = "debug", not(feature = "std")))]
+compile_error!("`debug` requires `std`");
+
+/// Trace the execution of the parser
+///
+/// Note that [`Parser::context` also provides high level trace information.
+///
+/// See [`trace` module][self] for more details.
+///
+/// # Example
+///
+/// ```rust
+/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed, IResult};
+/// # use winnow::bytes::take_while_m_n;
+/// # use winnow::stream::AsChar;
+/// # use winnow::prelude::*;
+/// use winnow::trace::trace;
+///
+/// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> {
+/// trace("short_alpha",
+/// take_while_m_n(3, 6, AsChar::is_alpha)
+/// ).parse_next(s)
+/// }
+///
+/// assert_eq!(short_alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..])));
+/// assert_eq!(short_alpha(b"lengthy"), Ok((&b"y"[..], &b"length"[..])));
+/// assert_eq!(short_alpha(b"latin"), Ok((&b""[..], &b"latin"[..])));
+/// assert_eq!(short_alpha(b"ed"), Err(ErrMode::Backtrack(Error::new(&b"ed"[..], ErrorKind::Slice))));
+/// assert_eq!(short_alpha(b"12345"), Err(ErrMode::Backtrack(Error::new(&b"12345"[..], ErrorKind::Slice))));
+/// ```
+#[cfg_attr(not(feature = "debug"), allow(unused_variables))]
+#[cfg_attr(not(feature = "debug"), allow(unused_mut))]
+pub fn trace<I: Stream, O, E>(
+ name: impl crate::lib::std::fmt::Display,
+ mut parser: impl Parser<I, O, E>,
+) -> impl Parser<I, O, E> {
+ #[cfg(feature = "debug")]
+ {
+ let mut call_count = 0;
+ move |i: I| {
+ let depth = internals::Depth::new();
+ let original = i.clone();
+ internals::start(*depth, &name, call_count, &original);
+
+ let res = parser.parse_next(i);
+
+ let consumed = res.as_ref().ok().map(|(i, _)| {
+ if i.eof_offset() == 0 {
+ // Sometimes, an unrelated empty string is returned which can break `offset_to`
+ original.eof_offset()
+ } else {
+ original.offset_to(i)
+ }
+ });
+ let severity = internals::Severity::with_result(&res);
+ internals::end(*depth, &name, call_count, consumed, severity);
+ call_count += 1;
+
+ res
+ }
+ }
+ #[cfg(not(feature = "debug"))]
+ {
+ parser
+ }
+}
+
+#[cfg_attr(not(feature = "debug"), allow(unused_variables))]
+pub(crate) fn trace_result<T, E>(
+ name: impl crate::lib::std::fmt::Display,
+ res: &Result<T, ErrMode<E>>,
+) {
+ #[cfg(feature = "debug")]
+ {
+ let depth = internals::Depth::existing();
+ let severity = internals::Severity::with_result(res);
+ internals::result(*depth, &name, severity);
+ }
+}
+
+#[test]
+#[cfg(feature = "std")]
+#[cfg_attr(miri, ignore)]
+#[cfg(unix)]
+#[cfg(feature = "debug")]
+fn example() {
+ use term_transcript::{test::TestConfig, ShellOptions};
+
+ let path = snapbox::cmd::compile_example("string", ["--features=debug"]).unwrap();
+
+ let current_dir = path.parent().unwrap();
+ let cmd = path.file_name().unwrap();
+ // HACK: term_transcript doesn't allow non-UTF8 paths
+ let cmd = format!("./{}", cmd.to_string_lossy());
+
+ TestConfig::new(
+ ShellOptions::default()
+ .with_current_dir(current_dir)
+ .with_env("CLICOLOR_FORCE", "1"),
+ )
+ .test("assets/trace.svg", [cmd.as_str()]);
+}