Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 330dacf

Browse files
authored
subscriber: impl fmt::Display for filter::Targets (#2343)
## Motivation There's currently a `fmt::Display` impl for `EnvFilter` that emits an equiovalent filter string that can be parsed back into an `EnvFilter`, but the `Targets` filter does not have a `fmt::Display` impl. We ought to have one, especially to make using `Targets` with `clap` v4.0 easier. ## Solution This branch adds a `fmt::Display` impl for `filter::Targets`. The implementation is pretty straightforward. I also added tests that a `Targets`' `fmt::Display` output can be parsed back into a filter that's equivalent to the original.
1 parent 1497179 commit 330dacf

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

tracing-subscriber/src/filter/targets.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
#[cfg(not(feature = "std"))]
1717
use alloc::string::String;
1818
use core::{
19+
fmt,
1920
iter::{Extend, FilterMap, FromIterator},
2021
slice,
2122
str::FromStr,
@@ -488,6 +489,20 @@ impl<'a> IntoIterator for &'a Targets {
488489
}
489490
}
490491

492+
impl fmt::Display for Targets {
493+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494+
let mut directives = self.0.directives();
495+
if let Some(directive) = directives.next() {
496+
write!(f, "{}", directive)?;
497+
for directive in directives {
498+
write!(f, ",{}", directive)?;
499+
}
500+
}
501+
502+
Ok(())
503+
}
504+
}
505+
491506
/// An owning iterator over the [target]-[level] pairs of a `Targets` filter.
492507
///
493508
/// This struct is created by the `IntoIterator` trait implementation of [`Targets`].
@@ -778,4 +793,42 @@ mod tests {
778793
crate2=debug,crate3=trace,crate3::mod2::mod1=off",
779794
);
780795
}
796+
797+
/// Test that the `fmt::Display` implementation for `Targets` emits a string
798+
/// that can itself be parsed as a `Targets`, and that the parsed `Targets`
799+
/// is equivalent to the original one.
800+
#[test]
801+
fn display_roundtrips() {
802+
fn test_roundtrip(s: &str) {
803+
let filter = expect_parse(s);
804+
// we don't assert that the display output is equivalent to the
805+
// original parsed filter string, because the `Display` impl always
806+
// uses lowercase level names and doesn't use the
807+
// target-without-level shorthand syntax. while they may not be
808+
// textually equivalent, though, they should still *parse* to the
809+
// same filter.
810+
let formatted = filter.to_string();
811+
let filter2 = match dbg!(&formatted).parse::<Targets>() {
812+
Ok(filter) => filter,
813+
Err(e) => panic!(
814+
"failed to parse formatted filter string {:?}: {}",
815+
formatted, e
816+
),
817+
};
818+
assert_eq!(filter, filter2);
819+
}
820+
821+
test_roundtrip("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off");
822+
test_roundtrip(
823+
"crate1::mod1=ERROR,crate1::mod2=WARN,crate1::mod2::mod3=INFO,\
824+
crate2=DEBUG,crate3=TRACE,crate3::mod2::mod1=OFF",
825+
);
826+
test_roundtrip(
827+
"crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\
828+
crate2=debug,crate3=trace,crate3::mod2::mod1=off",
829+
);
830+
test_roundtrip("crate1::mod1,crate1::mod2,info");
831+
test_roundtrip("crate1");
832+
test_roundtrip("info");
833+
}
781834
}

0 commit comments

Comments
 (0)