1use matchers::Pattern;
2use std::{
3 cmp::Ordering,
4 error::Error,
5 fmt::{self, Write},
6 str::FromStr,
7 sync::{
8 atomic::{AtomicBool, Ordering::*},
9 Arc,
10 },
11};
12
13use super::{FieldMap, LevelFilter};
14use tracing_core::field::{Field, Visit};
15
16#[derive(Clone, Debug, Eq, PartialEq)]
17pub(crate) struct Match {
18 pub(crate) name: String, pub(crate) value: Option<ValueMatch>,
20}
21
22#[derive(Debug, Eq, PartialEq)]
23pub(crate) struct CallsiteMatch {
24 pub(crate) fields: FieldMap<ValueMatch>,
25 pub(crate) level: LevelFilter,
26}
27
28#[derive(Debug)]
29pub(crate) struct SpanMatch {
30 fields: FieldMap<(ValueMatch, AtomicBool)>,
31 level: LevelFilter,
32 has_matched: AtomicBool,
33}
34
35pub(crate) struct MatchVisitor<'a> {
36 inner: &'a SpanMatch,
37}
38
39#[derive(Debug, Clone)]
40pub(crate) enum ValueMatch {
41 Bool(bool),
43 F64(f64),
45 U64(u64),
47 I64(i64),
49 NaN,
51 Debug(MatchDebug),
53 Pat(Box<MatchPattern>),
56}
57
58impl Eq for ValueMatch {}
59
60impl PartialEq for ValueMatch {
61 fn eq(&self, other: &Self) -> bool {
62 use ValueMatch::*;
63 match (self, other) {
64 (Bool(a), Bool(b)) => a.eq(b),
65 (F64(a), F64(b)) => {
66 debug_assert!(!a.is_nan());
67 debug_assert!(!b.is_nan());
68
69 a.eq(b)
70 }
71 (U64(a), U64(b)) => a.eq(b),
72 (I64(a), I64(b)) => a.eq(b),
73 (NaN, NaN) => true,
74 (Pat(a), Pat(b)) => a.eq(b),
75 _ => false,
76 }
77 }
78}
79
80impl Ord for ValueMatch {
81 fn cmp(&self, other: &Self) -> Ordering {
82 use ValueMatch::*;
83 match (self, other) {
84 (Bool(this), Bool(that)) => this.cmp(that),
85 (Bool(_), _) => Ordering::Less,
86
87 (F64(this), F64(that)) => this
88 .partial_cmp(that)
89 .expect("`ValueMatch::F64` may not contain `NaN` values"),
90 (F64(_), Bool(_)) => Ordering::Greater,
91 (F64(_), _) => Ordering::Less,
92
93 (NaN, NaN) => Ordering::Equal,
94 (NaN, Bool(_)) | (NaN, F64(_)) => Ordering::Greater,
95 (NaN, _) => Ordering::Less,
96
97 (U64(this), U64(that)) => this.cmp(that),
98 (U64(_), Bool(_)) | (U64(_), F64(_)) | (U64(_), NaN) => Ordering::Greater,
99 (U64(_), _) => Ordering::Less,
100
101 (I64(this), I64(that)) => this.cmp(that),
102 (I64(_), Bool(_)) | (I64(_), F64(_)) | (I64(_), NaN) | (I64(_), U64(_)) => {
103 Ordering::Greater
104 }
105 (I64(_), _) => Ordering::Less,
106
107 (Pat(this), Pat(that)) => this.cmp(that),
108 (Pat(_), _) => Ordering::Greater,
109
110 (Debug(this), Debug(that)) => this.cmp(that),
111 (Debug(_), _) => Ordering::Greater,
112 }
113 }
114}
115
116impl PartialOrd for ValueMatch {
117 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
118 Some(self.cmp(other))
119 }
120}
121
122#[derive(Debug, Clone)]
127pub(crate) struct MatchPattern {
128 pub(crate) matcher: Pattern,
129 pattern: Arc<str>,
130}
131
132#[derive(Debug, Clone)]
137pub(crate) struct MatchDebug {
138 pattern: Arc<str>,
139}
140
141#[derive(Clone, Debug)]
143#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))]
144pub struct BadName {
145 name: String,
146}
147
148impl Match {
151 pub(crate) fn has_value(&self) -> bool {
152 self.value.is_some()
153 }
154
155 pub(crate) fn name(&self) -> String {
157 self.name.clone()
158 }
159
160 pub(crate) fn parse(s: &str, regex: bool) -> Result<Self, Box<dyn Error + Send + Sync>> {
161 let mut parts = s.split('=');
162 let name = parts
163 .next()
164 .ok_or_else(|| BadName {
165 name: "".to_string(),
166 })?
167 .to_string();
169 let value = parts
170 .next()
171 .map(|part| match regex {
172 true => ValueMatch::parse_regex(part),
173 false => Ok(ValueMatch::parse_non_regex(part)),
174 })
175 .transpose()?;
176 Ok(Match { name, value })
177 }
178}
179
180impl fmt::Display for Match {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 fmt::Display::fmt(&self.name, f)?;
183 if let Some(ref value) = self.value {
184 write!(f, "={}", value)?;
185 }
186 Ok(())
187 }
188}
189
190impl Ord for Match {
191 fn cmp(&self, other: &Self) -> Ordering {
192 let has_value = match (self.value.as_ref(), other.value.as_ref()) {
197 (Some(_), None) => Ordering::Greater,
198 (None, Some(_)) => Ordering::Less,
199 _ => Ordering::Equal,
200 };
201 has_value
209 .then_with(|| self.name.cmp(&other.name))
210 .then_with(|| self.value.cmp(&other.value))
211 }
212}
213
214impl PartialOrd for Match {
215 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
216 Some(self.cmp(other))
217 }
218}
219
220fn value_match_f64(v: f64) -> ValueMatch {
223 if v.is_nan() {
224 ValueMatch::NaN
225 } else {
226 ValueMatch::F64(v)
227 }
228}
229
230impl ValueMatch {
231 fn parse_regex(s: &str) -> Result<Self, matchers::Error> {
238 s.parse::<bool>()
239 .map(ValueMatch::Bool)
240 .or_else(|_| s.parse::<u64>().map(ValueMatch::U64))
241 .or_else(|_| s.parse::<i64>().map(ValueMatch::I64))
242 .or_else(|_| s.parse::<f64>().map(value_match_f64))
243 .or_else(|_| {
244 s.parse::<MatchPattern>()
245 .map(|p| ValueMatch::Pat(Box::new(p)))
246 })
247 }
248
249 fn parse_non_regex(s: &str) -> Self {
256 s.parse::<bool>()
257 .map(ValueMatch::Bool)
258 .or_else(|_| s.parse::<u64>().map(ValueMatch::U64))
259 .or_else(|_| s.parse::<i64>().map(ValueMatch::I64))
260 .or_else(|_| s.parse::<f64>().map(value_match_f64))
261 .unwrap_or_else(|_| ValueMatch::Debug(MatchDebug::new(s)))
262 }
263}
264
265impl fmt::Display for ValueMatch {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 match self {
268 ValueMatch::Bool(ref inner) => fmt::Display::fmt(inner, f),
269 ValueMatch::F64(ref inner) => fmt::Display::fmt(inner, f),
270 ValueMatch::NaN => fmt::Display::fmt(&f64::NAN, f),
271 ValueMatch::I64(ref inner) => fmt::Display::fmt(inner, f),
272 ValueMatch::U64(ref inner) => fmt::Display::fmt(inner, f),
273 ValueMatch::Debug(ref inner) => fmt::Display::fmt(inner, f),
274 ValueMatch::Pat(ref inner) => fmt::Display::fmt(inner, f),
275 }
276 }
277}
278
279impl FromStr for MatchPattern {
282 type Err = matchers::Error;
283 fn from_str(s: &str) -> Result<Self, Self::Err> {
284 let matcher = s.parse::<Pattern>()?;
285 Ok(Self {
286 matcher,
287 pattern: s.to_owned().into(),
288 })
289 }
290}
291
292impl fmt::Display for MatchPattern {
293 #[inline]
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 fmt::Display::fmt(&*self.pattern, f)
296 }
297}
298
299impl AsRef<str> for MatchPattern {
300 #[inline]
301 fn as_ref(&self) -> &str {
302 self.pattern.as_ref()
303 }
304}
305
306impl MatchPattern {
307 #[inline]
308 fn str_matches(&self, s: &impl AsRef<str>) -> bool {
309 self.matcher.matches(s)
310 }
311
312 #[inline]
313 fn debug_matches(&self, d: &impl fmt::Debug) -> bool {
314 self.matcher.debug_matches(d)
315 }
316
317 pub(super) fn into_debug_match(self) -> MatchDebug {
318 MatchDebug {
319 pattern: self.pattern,
320 }
321 }
322}
323
324impl PartialEq for MatchPattern {
325 #[inline]
326 fn eq(&self, other: &Self) -> bool {
327 self.pattern == other.pattern
328 }
329}
330
331impl Eq for MatchPattern {}
332
333impl PartialOrd for MatchPattern {
334 #[inline]
335 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
336 Some(self.pattern.cmp(&other.pattern))
337 }
338}
339
340impl Ord for MatchPattern {
341 #[inline]
342 fn cmp(&self, other: &Self) -> Ordering {
343 self.pattern.cmp(&other.pattern)
344 }
345}
346
347impl MatchDebug {
350 fn new(s: &str) -> Self {
351 Self {
352 pattern: s.to_owned().into(),
353 }
354 }
355
356 #[inline]
357 fn debug_matches(&self, d: &impl fmt::Debug) -> bool {
358 struct Matcher<'a> {
368 pattern: &'a str,
369 }
370
371 impl fmt::Write for Matcher<'_> {
372 fn write_str(&mut self, s: &str) -> fmt::Result {
373 if s.len() > self.pattern.len() {
376 return Err(fmt::Error);
377 }
378
379 if self.pattern.starts_with(s) {
384 self.pattern = &self.pattern[s.len()..];
385 return Ok(());
386 }
387
388 Err(fmt::Error)
393 }
394 }
395 let mut matcher = Matcher {
396 pattern: &self.pattern,
397 };
398
399 write!(matcher, "{:?}", d).is_ok()
403 }
404}
405
406impl fmt::Display for MatchDebug {
407 #[inline]
408 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
409 fmt::Display::fmt(&*self.pattern, f)
410 }
411}
412
413impl AsRef<str> for MatchDebug {
414 #[inline]
415 fn as_ref(&self) -> &str {
416 self.pattern.as_ref()
417 }
418}
419
420impl PartialEq for MatchDebug {
421 #[inline]
422 fn eq(&self, other: &Self) -> bool {
423 self.pattern == other.pattern
424 }
425}
426
427impl Eq for MatchDebug {}
428
429impl PartialOrd for MatchDebug {
430 #[inline]
431 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
432 Some(self.pattern.cmp(&other.pattern))
433 }
434}
435
436impl Ord for MatchDebug {
437 #[inline]
438 fn cmp(&self, other: &Self) -> Ordering {
439 self.pattern.cmp(&other.pattern)
440 }
441}
442
443impl Error for BadName {}
446
447impl fmt::Display for BadName {
448 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
449 write!(f, "invalid field name `{}`", self.name)
450 }
451}
452
453impl CallsiteMatch {
454 pub(crate) fn to_span_match(&self) -> SpanMatch {
455 let fields = self
456 .fields
457 .iter()
458 .map(|(k, v)| (k.clone(), (v.clone(), AtomicBool::new(false))))
459 .collect();
460 SpanMatch {
461 fields,
462 level: self.level,
463 has_matched: AtomicBool::new(false),
464 }
465 }
466}
467
468impl SpanMatch {
469 pub(crate) fn visitor(&self) -> MatchVisitor<'_> {
470 MatchVisitor { inner: self }
471 }
472
473 #[inline]
474 pub(crate) fn is_matched(&self) -> bool {
475 if self.has_matched.load(Acquire) {
476 return true;
477 }
478 self.is_matched_slow()
479 }
480
481 #[inline(never)]
482 fn is_matched_slow(&self) -> bool {
483 let matched = self
484 .fields
485 .values()
486 .all(|(_, matched)| matched.load(Acquire));
487 if matched {
488 self.has_matched.store(true, Release);
489 }
490 matched
491 }
492
493 #[inline]
494 pub(crate) fn filter(&self) -> Option<LevelFilter> {
495 if self.is_matched() {
496 Some(self.level)
497 } else {
498 None
499 }
500 }
501}
502
503impl Visit for MatchVisitor<'_> {
504 fn record_f64(&mut self, field: &Field, value: f64) {
505 match self.inner.fields.get(field) {
506 Some((ValueMatch::NaN, ref matched)) if value.is_nan() => {
507 matched.store(true, Release);
508 }
509 Some((ValueMatch::F64(ref e), ref matched))
510 if (value - *e).abs() < f64::EPSILON =>
511 {
512 matched.store(true, Release);
513 }
514 _ => {}
515 }
516 }
517
518 fn record_i64(&mut self, field: &Field, value: i64) {
519 use std::convert::TryInto;
520
521 match self.inner.fields.get(field) {
522 Some((ValueMatch::I64(ref e), ref matched)) if value == *e => {
523 matched.store(true, Release);
524 }
525 Some((ValueMatch::U64(ref e), ref matched)) if Ok(value) == (*e).try_into() => {
526 matched.store(true, Release);
527 }
528 _ => {}
529 }
530 }
531
532 fn record_u64(&mut self, field: &Field, value: u64) {
533 match self.inner.fields.get(field) {
534 Some((ValueMatch::U64(ref e), ref matched)) if value == *e => {
535 matched.store(true, Release);
536 }
537 _ => {}
538 }
539 }
540
541 fn record_bool(&mut self, field: &Field, value: bool) {
542 match self.inner.fields.get(field) {
543 Some((ValueMatch::Bool(ref e), ref matched)) if value == *e => {
544 matched.store(true, Release);
545 }
546 _ => {}
547 }
548 }
549
550 fn record_str(&mut self, field: &Field, value: &str) {
551 match self.inner.fields.get(field) {
552 Some((ValueMatch::Pat(ref e), ref matched)) if e.str_matches(&value) => {
553 matched.store(true, Release);
554 }
555 Some((ValueMatch::Debug(ref e), ref matched)) if e.debug_matches(&value) => {
556 matched.store(true, Release)
557 }
558 _ => {}
559 }
560 }
561
562 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
563 match self.inner.fields.get(field) {
564 Some((ValueMatch::Pat(ref e), ref matched)) if e.debug_matches(&value) => {
565 matched.store(true, Release);
566 }
567 Some((ValueMatch::Debug(ref e), ref matched)) if e.debug_matches(&value) => {
568 matched.store(true, Release)
569 }
570 _ => {}
571 }
572 }
573}
574
575#[cfg(test)]
576mod tests {
577 use super::*;
578 #[derive(Debug)]
579 #[allow(dead_code)]
580 struct MyStruct {
581 answer: usize,
582 question: &'static str,
583 }
584
585 #[test]
586 fn debug_struct_match() {
587 let my_struct = MyStruct {
588 answer: 42,
589 question: "life, the universe, and everything",
590 };
591
592 let pattern = "MyStruct { answer: 42, question: \"life, the universe, and everything\" }";
593
594 assert_eq!(
595 format!("{:?}", my_struct),
596 pattern,
597 "`MyStruct`'s `Debug` impl doesn't output the expected string"
598 );
599
600 let matcher = MatchDebug {
601 pattern: pattern.into(),
602 };
603 assert!(matcher.debug_matches(&my_struct))
604 }
605
606 #[test]
607 fn debug_struct_not_match() {
608 let my_struct = MyStruct {
609 answer: 42,
610 question: "what shall we have for lunch?",
611 };
612
613 let pattern = "MyStruct { answer: 42, question: \"life, the universe, and everything\" }";
614
615 assert_eq!(
616 format!("{:?}", my_struct),
617 "MyStruct { answer: 42, question: \"what shall we have for lunch?\" }",
618 "`MyStruct`'s `Debug` impl doesn't output the expected string"
619 );
620
621 let matcher = MatchDebug {
622 pattern: pattern.into(),
623 };
624 assert!(!matcher.debug_matches(&my_struct))
625 }
626}