1 //! Metadata describing trace data.
2 use super::{callsite, field};
3 use crate::stdlib::{
4     cmp, fmt,
5     str::FromStr,
6     sync::atomic::{AtomicUsize, Ordering},
7 };
8 
9 /// Metadata describing a [span] or [event].
10 ///
11 /// All spans and events have the following metadata:
12 /// - A [name], represented as a static string.
13 /// - A [target], a string that categorizes part of the system where the span
14 ///   or event occurred. The `tracing` macros default to using the module
15 ///   path where the span or event originated as the target, but it may be
16 ///   overridden.
17 /// - A [verbosity level].
18 /// - The names of the [fields] defined by the span or event.
19 /// - Whether the metadata corresponds to a span or event.
20 ///
21 /// In addition, the following optional metadata describing the source code
22 /// location where the span or event originated _may_ be provided:
23 /// - The [file name]
24 /// - The [line number]
25 /// - The [module path]
26 ///
27 /// Metadata is used by [`Subscriber`]s when filtering spans and events, and it
28 /// may also be used as part of their data payload.
29 ///
30 /// When created by the `event!` or `span!` macro, the metadata describing a
31 /// particular event or span is constructed statically and exists as a single
32 /// static instance. Thus, the overhead of creating the metadata is
33 /// _significantly_ lower than that of creating the actual span. Therefore,
34 /// filtering is based on metadata, rather than on the constructed span.
35 ///
36 /// <div class="information">
37 ///     <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
38 /// </div>
39 /// <div class="example-wrap" style="display:inline-block">
40 /// <pre class="ignore" style="white-space:normal;font:inherit;">
41 /// <strong>Note</strong>: Although instances of <code>Metadata</code> cannot
42 /// be compared directly, they provide a method <a href="struct.Metadata.html#method.id">
43 /// <code>id</code></a>, returning an opaque <a href="../callsite/struct.Identifier.html">
44 /// callsite identifier</a>  which uniquely identifies the callsite where the metadata
45 /// originated. This can be used to determine if two <code>Metadata</code> correspond to
46 /// the same callsite.
47 /// </pre></div>
48 ///
49 /// [span]: ../span/index.html
50 /// [event]: ../event/index.html
51 /// [name]: #method.name
52 /// [target]: #method.target
53 /// [fields]: #method.fields
54 /// [verbosity level]: #method.level
55 /// [file name]: #method.file
56 /// [line number]: #method.line
57 /// [module path]: #method.module
58 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
59 /// [`id`]: struct.Metadata.html#method.id
60 /// [callsite identifier]: ../callsite/struct.Identifier.html
61 pub struct Metadata<'a> {
62     /// The name of the span described by this metadata.
63     name: &'static str,
64 
65     /// The part of the system that the span that this metadata describes
66     /// occurred in.
67     target: &'a str,
68 
69     /// The level of verbosity of the described span.
70     level: Level,
71 
72     /// The name of the Rust module where the span occurred, or `None` if this
73     /// could not be determined.
74     module_path: Option<&'a str>,
75 
76     /// The name of the source code file where the span occurred, or `None` if
77     /// this could not be determined.
78     file: Option<&'a str>,
79 
80     /// The line number in the source code file where the span occurred, or
81     /// `None` if this could not be determined.
82     line: Option<u32>,
83 
84     /// The names of the key-value fields attached to the described span or
85     /// event.
86     fields: field::FieldSet,
87 
88     /// The kind of the callsite.
89     kind: Kind,
90 }
91 
92 /// Indicates whether the callsite is a span or event.
93 #[derive(Clone, Debug, Eq, PartialEq)]
94 pub struct Kind(KindInner);
95 
96 /// Describes the level of verbosity of a span or event.
97 #[derive(Clone, Debug, PartialEq, Eq)]
98 pub struct Level(LevelInner);
99 
100 /// A filter comparable to a verbosity `Level`.
101 ///
102 /// If a `Level` is considered less than a `LevelFilter`, it should be
103 /// considered disabled; if greater than or equal to the `LevelFilter`, that
104 /// level is enabled.
105 ///
106 /// Note that this is essentially identical to the `Level` type, but with the
107 /// addition of an `OFF` level that completely disables all trace
108 /// instrumentation.
109 #[repr(transparent)]
110 #[derive(Clone, Eq, PartialEq)]
111 pub struct LevelFilter(Option<Level>);
112 
113 /// Indicates that a string could not be parsed to a valid level.
114 #[derive(Clone, Debug)]
115 pub struct ParseLevelFilterError(());
116 
117 static MAX_LEVEL: AtomicUsize = AtomicUsize::new(LevelFilter::OFF_USIZE);
118 
119 // ===== impl Metadata =====
120 
121 impl<'a> Metadata<'a> {
122     /// Construct new metadata for a span or event, with a name, target, level, field
123     /// names, and optional source code location.
new( name: &'static str, target: &'a str, level: Level, file: Option<&'a str>, line: Option<u32>, module_path: Option<&'a str>, fields: field::FieldSet, kind: Kind, ) -> Self124     pub const fn new(
125         name: &'static str,
126         target: &'a str,
127         level: Level,
128         file: Option<&'a str>,
129         line: Option<u32>,
130         module_path: Option<&'a str>,
131         fields: field::FieldSet,
132         kind: Kind,
133     ) -> Self {
134         Metadata {
135             name,
136             target,
137             level,
138             module_path,
139             file,
140             line,
141             fields,
142             kind,
143         }
144     }
145 
146     /// Returns the names of the fields on the described span or event.
fields(&self) -> &field::FieldSet147     pub fn fields(&self) -> &field::FieldSet {
148         &self.fields
149     }
150 
151     /// Returns the level of verbosity of the described span or event.
level(&self) -> &Level152     pub fn level(&self) -> &Level {
153         &self.level
154     }
155 
156     /// Returns the name of the span.
name(&self) -> &'static str157     pub fn name(&self) -> &'static str {
158         self.name
159     }
160 
161     /// Returns a string describing the part of the system where the span or
162     /// event that this metadata describes occurred.
163     ///
164     /// Typically, this is the module path, but alternate targets may be set
165     /// when spans or events are constructed.
target(&self) -> &'a str166     pub fn target(&self) -> &'a str {
167         self.target
168     }
169 
170     /// Returns the path to the Rust module where the span occurred, or
171     /// `None` if the module path is unknown.
module_path(&self) -> Option<&'a str>172     pub fn module_path(&self) -> Option<&'a str> {
173         self.module_path
174     }
175 
176     /// Returns the name of the source code file where the span
177     /// occurred, or `None` if the file is unknown
file(&self) -> Option<&'a str>178     pub fn file(&self) -> Option<&'a str> {
179         self.file
180     }
181 
182     /// Returns the line number in the source code file where the span
183     /// occurred, or `None` if the line number is unknown.
line(&self) -> Option<u32>184     pub fn line(&self) -> Option<u32> {
185         self.line
186     }
187 
188     /// Returns an opaque `Identifier` that uniquely identifies the callsite
189     /// this `Metadata` originated from.
190     #[inline]
callsite(&self) -> callsite::Identifier191     pub fn callsite(&self) -> callsite::Identifier {
192         self.fields.callsite()
193     }
194 
195     /// Returns true if the callsite kind is `Event`.
is_event(&self) -> bool196     pub fn is_event(&self) -> bool {
197         self.kind.is_event()
198     }
199 
200     /// Return true if the callsite kind is `Span`.
is_span(&self) -> bool201     pub fn is_span(&self) -> bool {
202         self.kind.is_span()
203     }
204 }
205 
206 impl<'a> fmt::Debug for Metadata<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result207     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208         let mut meta = f.debug_struct("Metadata");
209         meta.field("name", &self.name)
210             .field("target", &self.target)
211             .field("level", &self.level);
212 
213         if let Some(path) = self.module_path() {
214             meta.field("module_path", &path);
215         }
216 
217         match (self.file(), self.line()) {
218             (Some(file), Some(line)) => {
219                 meta.field("location", &format_args!("{}:{}", file, line));
220             }
221             (Some(file), None) => {
222                 meta.field("file", &format_args!("{}", file));
223             }
224 
225             // Note: a line num with no file is a kind of weird case that _probably_ never occurs...
226             (None, Some(line)) => {
227                 meta.field("line", &line);
228             }
229             (None, None) => {}
230         };
231 
232         meta.field("fields", &format_args!("{}", self.fields))
233             .field("callsite", &self.callsite())
234             .field("kind", &self.kind)
235             .finish()
236     }
237 }
238 
239 #[derive(Clone, Debug, Eq, PartialEq)]
240 enum KindInner {
241     Event,
242     Span,
243 }
244 
245 impl Kind {
246     /// `Event` callsite
247     pub const EVENT: Kind = Kind(KindInner::Event);
248 
249     /// `Span` callsite
250     pub const SPAN: Kind = Kind(KindInner::Span);
251 
252     /// Return true if the callsite kind is `Span`
is_span(&self) -> bool253     pub fn is_span(&self) -> bool {
254         match self {
255             Kind(KindInner::Span) => true,
256             _ => false,
257         }
258     }
259 
260     /// Return true if the callsite kind is `Event`
is_event(&self) -> bool261     pub fn is_event(&self) -> bool {
262         match self {
263             Kind(KindInner::Event) => true,
264             _ => false,
265         }
266     }
267 }
268 
269 // ===== impl Level =====
270 
271 impl Level {
272     /// The "error" level.
273     ///
274     /// Designates very serious errors.
275     pub const ERROR: Level = Level(LevelInner::Error);
276     /// The "warn" level.
277     ///
278     /// Designates hazardous situations.
279     pub const WARN: Level = Level(LevelInner::Warn);
280     /// The "info" level.
281     ///
282     /// Designates useful information.
283     pub const INFO: Level = Level(LevelInner::Info);
284     /// The "debug" level.
285     ///
286     /// Designates lower priority information.
287     pub const DEBUG: Level = Level(LevelInner::Debug);
288     /// The "trace" level.
289     ///
290     /// Designates very low priority, often extremely verbose, information.
291     pub const TRACE: Level = Level(LevelInner::Trace);
292 }
293 
294 impl fmt::Display for Level {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result295     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296         match *self {
297             Level::TRACE => f.pad("TRACE"),
298             Level::DEBUG => f.pad("DEBUG"),
299             Level::INFO => f.pad("INFO"),
300             Level::WARN => f.pad("WARN"),
301             Level::ERROR => f.pad("ERROR"),
302         }
303     }
304 }
305 
306 #[cfg(feature = "std")]
307 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
308 impl crate::stdlib::error::Error for ParseLevelError {}
309 
310 impl FromStr for Level {
311     type Err = ParseLevelError;
from_str(s: &str) -> Result<Self, ParseLevelError>312     fn from_str(s: &str) -> Result<Self, ParseLevelError> {
313         s.parse::<usize>()
314             .map_err(|_| ParseLevelError { _p: () })
315             .and_then(|num| match num {
316                 1 => Ok(Level::ERROR),
317                 2 => Ok(Level::WARN),
318                 3 => Ok(Level::INFO),
319                 4 => Ok(Level::DEBUG),
320                 5 => Ok(Level::TRACE),
321                 _ => Err(ParseLevelError { _p: () }),
322             })
323             .or_else(|_| match s {
324                 s if s.eq_ignore_ascii_case("error") => Ok(Level::ERROR),
325                 s if s.eq_ignore_ascii_case("warn") => Ok(Level::WARN),
326                 s if s.eq_ignore_ascii_case("info") => Ok(Level::INFO),
327                 s if s.eq_ignore_ascii_case("debug") => Ok(Level::DEBUG),
328                 s if s.eq_ignore_ascii_case("trace") => Ok(Level::TRACE),
329                 _ => Err(ParseLevelError { _p: () }),
330             })
331     }
332 }
333 
334 #[repr(usize)]
335 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
336 enum LevelInner {
337     /// The "trace" level.
338     ///
339     /// Designates very low priority, often extremely verbose, information.
340     Trace = 0,
341     /// The "debug" level.
342     ///
343     /// Designates lower priority information.
344     Debug = 1,
345     /// The "info" level.
346     ///
347     /// Designates useful information.
348     Info = 2,
349     /// The "warn" level.
350     ///
351     /// Designates hazardous situations.
352     Warn = 3,
353     /// The "error" level.
354     ///
355     /// Designates very serious errors.
356     Error = 4,
357 }
358 
359 // === impl LevelFilter ===
360 
361 impl From<Level> for LevelFilter {
362     #[inline]
from(level: Level) -> Self363     fn from(level: Level) -> Self {
364         Self::from_level(level)
365     }
366 }
367 
368 impl Into<Option<Level>> for LevelFilter {
369     #[inline]
into(self) -> Option<Level>370     fn into(self) -> Option<Level> {
371         self.into_level()
372     }
373 }
374 
375 impl LevelFilter {
376     /// The "off" level.
377     ///
378     /// Designates that trace instrumentation should be completely disabled.
379     pub const OFF: LevelFilter = LevelFilter(None);
380     /// The "error" level.
381     ///
382     /// Designates very serious errors.
383     pub const ERROR: LevelFilter = LevelFilter::from_level(Level::ERROR);
384     /// The "warn" level.
385     ///
386     /// Designates hazardous situations.
387     pub const WARN: LevelFilter = LevelFilter::from_level(Level::WARN);
388     /// The "info" level.
389     ///
390     /// Designates useful information.
391     pub const INFO: LevelFilter = LevelFilter::from_level(Level::INFO);
392     /// The "debug" level.
393     ///
394     /// Designates lower priority information.
395     pub const DEBUG: LevelFilter = LevelFilter::from_level(Level::DEBUG);
396     /// The "trace" level.
397     ///
398     /// Designates very low priority, often extremely verbose, information.
399     pub const TRACE: LevelFilter = LevelFilter(Some(Level::TRACE));
400 
401     /// Returns a `LevelFilter` that enables spans and events with verbosity up
402     /// to and including `level`.
from_level(level: Level) -> Self403     pub const fn from_level(level: Level) -> Self {
404         Self(Some(level))
405     }
406 
407     /// Returns the most verbose [`Level`] that this filter accepts, or `None`
408     /// if it is [`OFF`].
409     ///
410     /// [`Level`]: ../struct.Level.html
411     /// [`OFF`]: #associatedconstant.OFF
into_level(self) -> Option<Level>412     pub const fn into_level(self) -> Option<Level> {
413         self.0
414     }
415 
416     // These consts are necessary because `as` casts are not allowed as
417     // match patterns.
418     const ERROR_USIZE: usize = LevelInner::Error as usize;
419     const WARN_USIZE: usize = LevelInner::Warn as usize;
420     const INFO_USIZE: usize = LevelInner::Info as usize;
421     const DEBUG_USIZE: usize = LevelInner::Debug as usize;
422     const TRACE_USIZE: usize = LevelInner::Trace as usize;
423     // Using the value of the last variant + 1 ensures that we match the value
424     // for `Option::None` as selected by the niche optimization for
425     // `LevelFilter`. If this is the case, converting a `usize` value into a
426     // `LevelFilter` (in `LevelFilter::current`) will be an identity conversion,
427     // rather than generating a lookup table.
428     const OFF_USIZE: usize = LevelInner::Error as usize + 1;
429 
430     /// Returns a `LevelFilter` that matches the most verbose [`Level`] that any
431     /// currently active [`Subscriber`] will enable.
432     ///
433     /// User code should treat this as a *hint*. If a given span or event has a
434     /// level *higher* than the returned `LevelFilter`, it will not be enabled.
435     /// However, if the level is less than or equal to this value, the span or
436     /// event is *not* guaranteed to be enabled; the subscriber will still
437     /// filter each callsite individually.
438     ///
439     /// Therefore, comparing a given span or event's level to the returned
440     /// `LevelFilter` **can** be used for determining if something is
441     /// *disabled*, but **should not** be used for determining if something is
442     /// *enabled*.`
443     ///
444     /// [`Level`]: ../struct.Level.html
445     /// [`Subscriber`]: ../../trait.Subscriber.html
446     #[inline(always)]
current() -> Self447     pub fn current() -> Self {
448         match MAX_LEVEL.load(Ordering::Relaxed) {
449             Self::ERROR_USIZE => Self::ERROR,
450             Self::WARN_USIZE => Self::WARN,
451             Self::INFO_USIZE => Self::INFO,
452             Self::DEBUG_USIZE => Self::DEBUG,
453             Self::TRACE_USIZE => Self::TRACE,
454             Self::OFF_USIZE => Self::OFF,
455             #[cfg(debug_assertions)]
456             unknown => unreachable!(
457                 "/!\\ `LevelFilter` representation seems to have changed! /!\\ \n\
458                 This is a bug (and it's pretty bad). Please contact the `tracing` \
459                 maintainers. Thank you and I'm sorry.\n \
460                 The offending repr was: {:?}",
461                 unknown,
462             ),
463             #[cfg(not(debug_assertions))]
464             _ => unsafe {
465                 // Using `unreachable_unchecked` here (rather than
466                 // `unreachable!()`) is necessary to ensure that rustc generates
467                 // an identity conversion from integer -> discriminant, rather
468                 // than generating a lookup table. We want to ensure this
469                 // function is a single `mov` instruction (on x86) if at all
470                 // possible, because it is called *every* time a span/event
471                 // callsite is hit; and it is (potentially) the only code in the
472                 // hottest path for skipping a majority of callsites when level
473                 // filtering is in use.
474                 //
475                 // safety: This branch is only truly unreachable if we guarantee
476                 // that no values other than the possible enum discriminants
477                 // will *ever* be present. The `AtomicUsize` is initialized to
478                 // the `OFF` value. It is only set by the `set_max` function,
479                 // which takes a `LevelFilter` as a parameter. This restricts
480                 // the inputs to `set_max` to the set of valid discriminants.
481                 // Therefore, **as long as `MAX_VALUE` is only ever set by
482                 // `set_max`**, this is safe.
483                 crate::stdlib::hint::unreachable_unchecked()
484             },
485         }
486     }
487 
set_max(LevelFilter(level): LevelFilter)488     pub(crate) fn set_max(LevelFilter(level): LevelFilter) {
489         let val = match level {
490             Some(Level(level)) => level as usize,
491             None => Self::OFF_USIZE,
492         };
493 
494         // using an AcqRel swap ensures an ordered relationship of writes to the
495         // max level.
496         MAX_LEVEL.swap(val, Ordering::AcqRel);
497     }
498 }
499 
500 impl fmt::Display for LevelFilter {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result501     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502         match *self {
503             LevelFilter::OFF => f.pad("off"),
504             LevelFilter::ERROR => f.pad("error"),
505             LevelFilter::WARN => f.pad("warn"),
506             LevelFilter::INFO => f.pad("info"),
507             LevelFilter::DEBUG => f.pad("debug"),
508             LevelFilter::TRACE => f.pad("trace"),
509         }
510     }
511 }
512 
513 impl fmt::Debug for LevelFilter {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result514     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
515         match *self {
516             LevelFilter::OFF => f.pad("LevelFilter::OFF"),
517             LevelFilter::ERROR => f.pad("LevelFilter::ERROR"),
518             LevelFilter::WARN => f.pad("LevelFilter::WARN"),
519             LevelFilter::INFO => f.pad("LevelFilter::INFO"),
520             LevelFilter::DEBUG => f.pad("LevelFilter::DEBUG"),
521             LevelFilter::TRACE => f.pad("LevelFilter::TRACE"),
522         }
523     }
524 }
525 
526 impl FromStr for LevelFilter {
527     type Err = ParseLevelFilterError;
from_str(from: &str) -> Result<Self, Self::Err>528     fn from_str(from: &str) -> Result<Self, Self::Err> {
529         from.parse::<usize>()
530             .ok()
531             .and_then(|num| match num {
532                 0 => Some(LevelFilter::OFF),
533                 1 => Some(LevelFilter::ERROR),
534                 2 => Some(LevelFilter::WARN),
535                 3 => Some(LevelFilter::INFO),
536                 4 => Some(LevelFilter::DEBUG),
537                 5 => Some(LevelFilter::TRACE),
538                 _ => None,
539             })
540             .or_else(|| match from {
541                 "" => Some(LevelFilter::ERROR),
542                 s if s.eq_ignore_ascii_case("error") => Some(LevelFilter::ERROR),
543                 s if s.eq_ignore_ascii_case("warn") => Some(LevelFilter::WARN),
544                 s if s.eq_ignore_ascii_case("info") => Some(LevelFilter::INFO),
545                 s if s.eq_ignore_ascii_case("debug") => Some(LevelFilter::DEBUG),
546                 s if s.eq_ignore_ascii_case("trace") => Some(LevelFilter::TRACE),
547                 s if s.eq_ignore_ascii_case("off") => Some(LevelFilter::OFF),
548                 _ => None,
549             })
550             .ok_or_else(|| ParseLevelFilterError(()))
551     }
552 }
553 
554 /// Returned if parsing a `Level` fails.
555 #[derive(Debug)]
556 pub struct ParseLevelError {
557     _p: (),
558 }
559 
560 impl fmt::Display for ParseLevelError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result561     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
562         f.pad(
563             "error parsing level: expected one of \"error\", \"warn\", \
564              \"info\", \"debug\", \"trace\", or a number 1-5",
565         )
566     }
567 }
568 
569 impl fmt::Display for ParseLevelFilterError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result570     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571         f.pad(
572             "error parsing level filter: expected one of \"off\", \"error\", \
573             \"warn\", \"info\", \"debug\", \"trace\", or a number 0-5",
574         )
575     }
576 }
577 
578 #[cfg(feature = "std")]
579 impl std::error::Error for ParseLevelFilterError {}
580 
581 // ==== Level and LevelFilter comparisons ====
582 
583 // /!\ BIG, IMPORTANT WARNING /!\
584 // Do NOT mess with these implementations! They are hand-written for a reason!
585 //
586 // Since comparing `Level`s and `LevelFilter`s happens in a *very* hot path
587 // (potentially, every time a span or event macro is hit, regardless of whether
588 // or not is enabled), we *need* to ensure that these comparisons are as fast as
589 // possible. Therefore, we have some requirements:
590 //
591 // 1. We want to do our best to ensure that rustc will generate integer-integer
592 //    comparisons wherever possible.
593 //
594 //    The derived `Ord`/`PartialOrd` impls for `LevelFilter` will not do this,
595 //    because `LevelFilter`s are represented by `Option<Level>`, rather than as
596 //    a separate `#[repr(usize)]` enum. This was (unfortunately) necessary for
597 //    backwards-compatibility reasons, as the  `tracing` crate's original
598 //    version of `LevelFilter` defined `const fn` conversions between `Level`s
599 //    and `LevelFilter`, so we're stuck with the `Option<Level>` repr.
600 //    Therefore, we need hand-written `PartialOrd` impls that cast both sides of
601 //    the comparison to `usize`s, to force the compiler to generate integer
602 //    compares.
603 //
604 // 2. The hottest `Level`/`LevelFilter` comparison, the one that happens every
605 //    time a callsite is hit, occurs *within the `tracing` crate's macros*.
606 //    This means that the comparison is happening *inside* a crate that
607 //    *depends* on `tracing-core`, not in `tracing-core` itself. The compiler
608 //    will only inline function calls across crate boundaries if the called
609 //    function is annotated with an `#[inline]` attribute, and we *definitely*
610 //    want the comparison functions to be inlined: as previously mentioned, they
611 //    should compile down to a single integer comparison on release builds, and
612 //    it seems really sad to push an entire stack frame to call a function
613 //    consisting of one `cmp` instruction!
614 //
615 //    Therefore, we need to ensure that all the comparison methods have
616 //    `#[inline]` or `#[inline(always)]` attributes. It's not sufficient to just
617 //    add the attribute to `partial_cmp` in a manual implementation of the
618 //    trait, since it's the comparison operators (`lt`, `le`, `gt`, and `ge`)
619 //    that will actually be *used*, and the default implementation of *those*
620 //    methods, which calls `partial_cmp`, does not have an inline annotation.
621 //
622 // 3. We need the comparisons to be inverted. The discriminants for the
623 //    `LevelInner` enum are assigned in "backwards" order, with `TRACE` having
624 //    the *lowest* value. However, we want `TRACE` to compare greater-than all
625 //    other levels.
626 //
627 //    Why are the numeric values inverted? In order to ensure that `LevelFilter`
628 //    (which, as previously mentioned, *has* to be internally represented by an
629 //    `Option<Level>`) compiles down to a single integer value. This is
630 //    necessary for storing the global max in an `AtomicUsize`, and for ensuring
631 //    that we use fast integer-integer comparisons, as mentioned previously. In
632 //    order to ensure this, we exploit the niche optimization. The niche
633 //    optimization for `Option<{enum with a numeric repr}>` will choose
634 //    `(HIGHEST_DISCRIMINANT_VALUE + 1)` as the representation for `None`.
635 //    Therefore, the integer representation of `LevelFilter::OFF` (which is
636 //    `None`) will be the number 5. `OFF` must compare higher than every other
637 //    level in order for it to filter as expected. Since we want to use a single
638 //    `cmp` instruction, we can't special-case the integer value of `OFF` to
639 //    compare higher, as that will generate more code. Instead, we need it to be
640 //    on one end of the enum, with `ERROR` on the opposite end, so we assign the
641 //    value 0 to `ERROR`.
642 //
643 //    This *does* mean that when parsing `LevelFilter`s or `Level`s from
644 //    `String`s, the integer values are inverted, but that doesn't happen in a
645 //    hot path.
646 //
647 //    Note that we manually invert the comparisons by swapping the left-hand and
648 //    right-hand side. Using `Ordering::reverse` generates significantly worse
649 //    code (per Matt Godbolt's Compiler Explorer).
650 //
651 // Anyway, that's a brief history of why this code is the way it is. Don't
652 // change it unless you know what you're doing.
653 
654 impl PartialEq<LevelFilter> for Level {
655     #[inline(always)]
eq(&self, other: &LevelFilter) -> bool656     fn eq(&self, other: &LevelFilter) -> bool {
657         self.0 as usize == filter_as_usize(&other.0)
658     }
659 }
660 
661 impl PartialOrd for Level {
662     #[inline(always)]
partial_cmp(&self, other: &Level) -> Option<cmp::Ordering>663     fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
664         Some(self.cmp(other))
665     }
666 
667     #[inline(always)]
lt(&self, other: &Level) -> bool668     fn lt(&self, other: &Level) -> bool {
669         (other.0 as usize) < (self.0 as usize)
670     }
671 
672     #[inline(always)]
le(&self, other: &Level) -> bool673     fn le(&self, other: &Level) -> bool {
674         (other.0 as usize) <= (self.0 as usize)
675     }
676 
677     #[inline(always)]
gt(&self, other: &Level) -> bool678     fn gt(&self, other: &Level) -> bool {
679         (other.0 as usize) > (self.0 as usize)
680     }
681 
682     #[inline(always)]
ge(&self, other: &Level) -> bool683     fn ge(&self, other: &Level) -> bool {
684         (other.0 as usize) >= (self.0 as usize)
685     }
686 }
687 
688 impl Ord for Level {
689     #[inline(always)]
cmp(&self, other: &Self) -> cmp::Ordering690     fn cmp(&self, other: &Self) -> cmp::Ordering {
691         (other.0 as usize).cmp(&(self.0 as usize))
692     }
693 }
694 
695 impl PartialOrd<LevelFilter> for Level {
696     #[inline(always)]
partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering>697     fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
698         Some(filter_as_usize(&other.0).cmp(&(self.0 as usize)))
699     }
700 
701     #[inline(always)]
lt(&self, other: &LevelFilter) -> bool702     fn lt(&self, other: &LevelFilter) -> bool {
703         filter_as_usize(&other.0) < (self.0 as usize)
704     }
705 
706     #[inline(always)]
le(&self, other: &LevelFilter) -> bool707     fn le(&self, other: &LevelFilter) -> bool {
708         filter_as_usize(&other.0) <= (self.0 as usize)
709     }
710 
711     #[inline(always)]
gt(&self, other: &LevelFilter) -> bool712     fn gt(&self, other: &LevelFilter) -> bool {
713         filter_as_usize(&other.0) > (self.0 as usize)
714     }
715 
716     #[inline(always)]
ge(&self, other: &LevelFilter) -> bool717     fn ge(&self, other: &LevelFilter) -> bool {
718         filter_as_usize(&other.0) >= (self.0 as usize)
719     }
720 }
721 
722 #[inline(always)]
filter_as_usize(x: &Option<Level>) -> usize723 fn filter_as_usize(x: &Option<Level>) -> usize {
724     match x {
725         Some(Level(f)) => *f as usize,
726         None => LevelFilter::OFF_USIZE,
727     }
728 }
729 
730 impl PartialEq<Level> for LevelFilter {
731     #[inline(always)]
eq(&self, other: &Level) -> bool732     fn eq(&self, other: &Level) -> bool {
733         filter_as_usize(&self.0) == other.0 as usize
734     }
735 }
736 
737 impl PartialOrd for LevelFilter {
738     #[inline(always)]
partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering>739     fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
740         Some(self.cmp(other))
741     }
742 
743     #[inline(always)]
lt(&self, other: &LevelFilter) -> bool744     fn lt(&self, other: &LevelFilter) -> bool {
745         filter_as_usize(&other.0) < filter_as_usize(&self.0)
746     }
747 
748     #[inline(always)]
le(&self, other: &LevelFilter) -> bool749     fn le(&self, other: &LevelFilter) -> bool {
750         filter_as_usize(&other.0) <= filter_as_usize(&self.0)
751     }
752 
753     #[inline(always)]
gt(&self, other: &LevelFilter) -> bool754     fn gt(&self, other: &LevelFilter) -> bool {
755         filter_as_usize(&other.0) > filter_as_usize(&self.0)
756     }
757 
758     #[inline(always)]
ge(&self, other: &LevelFilter) -> bool759     fn ge(&self, other: &LevelFilter) -> bool {
760         filter_as_usize(&other.0) >= filter_as_usize(&self.0)
761     }
762 }
763 
764 impl Ord for LevelFilter {
765     #[inline(always)]
cmp(&self, other: &Self) -> cmp::Ordering766     fn cmp(&self, other: &Self) -> cmp::Ordering {
767         filter_as_usize(&other.0).cmp(&filter_as_usize(&self.0))
768     }
769 }
770 
771 impl PartialOrd<Level> for LevelFilter {
772     #[inline(always)]
partial_cmp(&self, other: &Level) -> Option<cmp::Ordering>773     fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
774         Some((other.0 as usize).cmp(&filter_as_usize(&self.0)))
775     }
776 
777     #[inline(always)]
lt(&self, other: &Level) -> bool778     fn lt(&self, other: &Level) -> bool {
779         (other.0 as usize) < filter_as_usize(&self.0)
780     }
781 
782     #[inline(always)]
le(&self, other: &Level) -> bool783     fn le(&self, other: &Level) -> bool {
784         (other.0 as usize) <= filter_as_usize(&self.0)
785     }
786 
787     #[inline(always)]
gt(&self, other: &Level) -> bool788     fn gt(&self, other: &Level) -> bool {
789         (other.0 as usize) > filter_as_usize(&self.0)
790     }
791 
792     #[inline(always)]
ge(&self, other: &Level) -> bool793     fn ge(&self, other: &Level) -> bool {
794         (other.0 as usize) >= filter_as_usize(&self.0)
795     }
796 }
797 
798 #[cfg(test)]
799 mod tests {
800     use super::*;
801     use crate::stdlib::mem;
802 
803     #[test]
level_from_str()804     fn level_from_str() {
805         assert_eq!("error".parse::<Level>().unwrap(), Level::ERROR);
806         assert_eq!("4".parse::<Level>().unwrap(), Level::DEBUG);
807         assert!("0".parse::<Level>().is_err())
808     }
809 
810     #[test]
filter_level_conversion()811     fn filter_level_conversion() {
812         let mapping = [
813             (LevelFilter::OFF, None),
814             (LevelFilter::ERROR, Some(Level::ERROR)),
815             (LevelFilter::WARN, Some(Level::WARN)),
816             (LevelFilter::INFO, Some(Level::INFO)),
817             (LevelFilter::DEBUG, Some(Level::DEBUG)),
818             (LevelFilter::TRACE, Some(Level::TRACE)),
819         ];
820         for (filter, level) in mapping.iter() {
821             assert_eq!(filter.clone().into_level(), *level);
822             if let Some(level) = level {
823                 assert_eq!(LevelFilter::from_level(level.clone()), *filter);
824             }
825         }
826     }
827 
828     #[test]
level_filter_is_usize_sized()829     fn level_filter_is_usize_sized() {
830         assert_eq!(
831             mem::size_of::<LevelFilter>(),
832             mem::size_of::<usize>(),
833             "`LevelFilter` is no longer `usize`-sized! global MAX_LEVEL may now be invalid!"
834         )
835     }
836 
837     #[test]
level_filter_reprs()838     fn level_filter_reprs() {
839         let mapping = [
840             (LevelFilter::OFF, LevelInner::Error as usize + 1),
841             (LevelFilter::ERROR, LevelInner::Error as usize),
842             (LevelFilter::WARN, LevelInner::Warn as usize),
843             (LevelFilter::INFO, LevelInner::Info as usize),
844             (LevelFilter::DEBUG, LevelInner::Debug as usize),
845             (LevelFilter::TRACE, LevelInner::Trace as usize),
846         ];
847         for &(ref filter, expected) in &mapping {
848             let repr = unsafe {
849                 // safety: The entire purpose of this test is to assert that the
850                 // actual repr matches what we expect it to be --- we're testing
851                 // that *other* unsafe code is sound using the transmuted value.
852                 // We're not going to do anything with it that might be unsound.
853                 mem::transmute::<_, usize>(filter.clone())
854             };
855             assert_eq!(expected, repr, "repr changed for {:?}", filter)
856         }
857     }
858 }
859