1 //! Metadata describing trace data.
2 use super::{callsite, field}
;
6 sync
::atomic
::{AtomicUsize, Ordering}
,
9 /// Metadata describing a [span] or [event].
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
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.
21 /// In addition, the following optional metadata describing the source code
22 /// location where the span or event originated _may_ be provided:
24 /// - The [line number]
25 /// - The [module path]
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.
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.
36 /// <div class="information">
37 /// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></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.
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.
65 /// The part of the system that the span that this metadata describes
69 /// The level of verbosity of the described span.
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>,
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>,
80 /// The line number in the source code file where the span occurred, or
81 /// `None` if this could not be determined.
84 /// The names of the key-value fields attached to the described span or
86 fields
: field
::FieldSet
,
88 /// The kind of the callsite.
92 /// Indicates whether the callsite is a span or event.
93 #[derive(Clone, Debug, Eq, PartialEq)]
94 pub struct Kind(KindInner
);
96 /// Describes the level of verbosity of a span or event.
97 #[derive(Clone, Debug, PartialEq, Eq)]
98 pub struct Level(LevelInner
);
100 /// A filter comparable to a verbosity `Level`.
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.
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
110 #[derive(Clone, Eq, PartialEq)]
111 pub struct LevelFilter(Option
<Level
>);
113 /// Indicates that a string could not be parsed to a valid level.
114 #[derive(Clone, Debug)]
115 pub struct ParseLevelFilterError(());
117 static MAX_LEVEL
: AtomicUsize
= AtomicUsize
::new(LevelFilter
::OFF_USIZE
);
119 // ===== impl Metadata =====
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.
128 file
: Option
<&'a
str>,
130 module_path
: Option
<&'a
str>,
131 fields
: field
::FieldSet
,
146 /// Returns the names of the fields on the described span or event.
147 pub fn fields(&self) -> &field
::FieldSet
{
151 /// Returns the level of verbosity of the described span or event.
152 pub fn level(&self) -> &Level
{
156 /// Returns the name of the span.
157 pub fn name(&self) -> &'
static str {
161 /// Returns a string describing the part of the system where the span or
162 /// event that this metadata describes occurred.
164 /// Typically, this is the module path, but alternate targets may be set
165 /// when spans or events are constructed.
166 pub fn target(&self) -> &'a
str {
170 /// Returns the path to the Rust module where the span occurred, or
171 /// `None` if the module path is unknown.
172 pub fn module_path(&self) -> Option
<&'a
str> {
176 /// Returns the name of the source code file where the span
177 /// occurred, or `None` if the file is unknown
178 pub fn file(&self) -> Option
<&'a
str> {
182 /// Returns the line number in the source code file where the span
183 /// occurred, or `None` if the line number is unknown.
184 pub fn line(&self) -> Option
<u32> {
188 /// Returns an opaque `Identifier` that uniquely identifies the callsite
189 /// this `Metadata` originated from.
191 pub fn callsite(&self) -> callsite
::Identifier
{
192 self.fields
.callsite()
195 /// Returns true if the callsite kind is `Event`.
196 pub fn is_event(&self) -> bool
{
200 /// Return true if the callsite kind is `Span`.
201 pub fn is_span(&self) -> bool
{
206 impl<'a
> fmt
::Debug
for Metadata
<'a
> {
207 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
);
213 if let Some(path
) = self.module_path() {
214 meta
.field("module_path", &path
);
217 match (self.file(), self.line()) {
218 (Some(file
), Some(line
)) => {
219 meta
.field("location", &format_args
!("{}:{}", file
, line
));
221 (Some(file
), None
) => {
222 meta
.field("file", &format_args
!("{}", file
));
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
);
232 meta
.field("fields", &format_args
!("{}", self.fields
))
233 .field("callsite", &self.callsite())
234 .field("kind", &self.kind
)
239 #[derive(Clone, Debug, Eq, PartialEq)]
247 pub const EVENT
: Kind
= Kind(KindInner
::Event
);
250 pub const SPAN
: Kind
= Kind(KindInner
::Span
);
252 /// Return true if the callsite kind is `Span`
253 pub fn is_span(&self) -> bool
{
255 Kind(KindInner
::Span
) => true,
260 /// Return true if the callsite kind is `Event`
261 pub fn is_event(&self) -> bool
{
263 Kind(KindInner
::Event
) => true,
269 // ===== impl Level =====
272 /// The "error" level.
274 /// Designates very serious errors.
275 pub const ERROR
: Level
= Level(LevelInner
::Error
);
276 /// The "warn" level.
278 /// Designates hazardous situations.
279 pub const WARN
: Level
= Level(LevelInner
::Warn
);
280 /// The "info" level.
282 /// Designates useful information.
283 pub const INFO
: Level
= Level(LevelInner
::Info
);
284 /// The "debug" level.
286 /// Designates lower priority information.
287 pub const DEBUG
: Level
= Level(LevelInner
::Debug
);
288 /// The "trace" level.
290 /// Designates very low priority, often extremely verbose, information.
291 pub const TRACE
: Level
= Level(LevelInner
::Trace
);
294 impl fmt
::Display
for Level
{
295 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
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"),
306 #[cfg(feature = "std")]
307 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
308 impl crate::stdlib
::error
::Error
for ParseLevelError {}
310 impl FromStr
for Level
{
311 type Err
= ParseLevelError
;
312 fn from_str(s
: &str) -> Result
<Self, ParseLevelError
> {
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: () }
),
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: () }
),
335 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
337 /// The "trace" level.
339 /// Designates very low priority, often extremely verbose, information.
341 /// The "debug" level.
343 /// Designates lower priority information.
345 /// The "info" level.
347 /// Designates useful information.
349 /// The "warn" level.
351 /// Designates hazardous situations.
353 /// The "error" level.
355 /// Designates very serious errors.
359 // === impl LevelFilter ===
361 impl From
<Level
> for LevelFilter
{
363 fn from(level
: Level
) -> Self {
364 Self::from_level(level
)
368 impl From
<Option
<Level
>> for LevelFilter
{
370 fn from(level
: Option
<Level
>) -> Self {
375 impl Into
<Option
<Level
>> for LevelFilter
{
377 fn into(self) -> Option
<Level
> {
385 /// Designates that trace instrumentation should be completely disabled.
386 pub const OFF
: LevelFilter
= LevelFilter(None
);
387 /// The "error" level.
389 /// Designates very serious errors.
390 pub const ERROR
: LevelFilter
= LevelFilter
::from_level(Level
::ERROR
);
391 /// The "warn" level.
393 /// Designates hazardous situations.
394 pub const WARN
: LevelFilter
= LevelFilter
::from_level(Level
::WARN
);
395 /// The "info" level.
397 /// Designates useful information.
398 pub const INFO
: LevelFilter
= LevelFilter
::from_level(Level
::INFO
);
399 /// The "debug" level.
401 /// Designates lower priority information.
402 pub const DEBUG
: LevelFilter
= LevelFilter
::from_level(Level
::DEBUG
);
403 /// The "trace" level.
405 /// Designates very low priority, often extremely verbose, information.
406 pub const TRACE
: LevelFilter
= LevelFilter(Some(Level
::TRACE
));
408 /// Returns a `LevelFilter` that enables spans and events with verbosity up
409 /// to and including `level`.
410 pub const fn from_level(level
: Level
) -> Self {
414 /// Returns the most verbose [`Level`] that this filter accepts, or `None`
415 /// if it is [`OFF`].
417 /// [`Level`]: ../struct.Level.html
418 /// [`OFF`]: #associatedconstant.OFF
419 pub const fn into_level(self) -> Option
<Level
> {
423 // These consts are necessary because `as` casts are not allowed as
425 const ERROR_USIZE
: usize = LevelInner
::Error
as usize;
426 const WARN_USIZE
: usize = LevelInner
::Warn
as usize;
427 const INFO_USIZE
: usize = LevelInner
::Info
as usize;
428 const DEBUG_USIZE
: usize = LevelInner
::Debug
as usize;
429 const TRACE_USIZE
: usize = LevelInner
::Trace
as usize;
430 // Using the value of the last variant + 1 ensures that we match the value
431 // for `Option::None` as selected by the niche optimization for
432 // `LevelFilter`. If this is the case, converting a `usize` value into a
433 // `LevelFilter` (in `LevelFilter::current`) will be an identity conversion,
434 // rather than generating a lookup table.
435 const OFF_USIZE
: usize = LevelInner
::Error
as usize + 1;
437 /// Returns a `LevelFilter` that matches the most verbose [`Level`] that any
438 /// currently active [`Subscriber`] will enable.
440 /// User code should treat this as a *hint*. If a given span or event has a
441 /// level *higher* than the returned `LevelFilter`, it will not be enabled.
442 /// However, if the level is less than or equal to this value, the span or
443 /// event is *not* guaranteed to be enabled; the subscriber will still
444 /// filter each callsite individually.
446 /// Therefore, comparing a given span or event's level to the returned
447 /// `LevelFilter` **can** be used for determining if something is
448 /// *disabled*, but **should not** be used for determining if something is
451 /// [`Level`]: ../struct.Level.html
452 /// [`Subscriber`]: ../../trait.Subscriber.html
454 pub fn current() -> Self {
455 match MAX_LEVEL
.load(Ordering
::Relaxed
) {
456 Self::ERROR_USIZE
=> Self::ERROR
,
457 Self::WARN_USIZE
=> Self::WARN
,
458 Self::INFO_USIZE
=> Self::INFO
,
459 Self::DEBUG_USIZE
=> Self::DEBUG
,
460 Self::TRACE_USIZE
=> Self::TRACE
,
461 Self::OFF_USIZE
=> Self::OFF
,
462 #[cfg(debug_assertions)]
463 unknown
=> unreachable
!(
464 "/!\\ `LevelFilter` representation seems to have changed! /!\\ \n\
465 This is a bug (and it's pretty bad). Please contact the `tracing` \
466 maintainers. Thank you and I'm sorry.\n \
467 The offending repr was: {:?}",
470 #[cfg(not(debug_assertions))]
472 // Using `unreachable_unchecked` here (rather than
473 // `unreachable!()`) is necessary to ensure that rustc generates
474 // an identity conversion from integer -> discriminant, rather
475 // than generating a lookup table. We want to ensure this
476 // function is a single `mov` instruction (on x86) if at all
477 // possible, because it is called *every* time a span/event
478 // callsite is hit; and it is (potentially) the only code in the
479 // hottest path for skipping a majority of callsites when level
480 // filtering is in use.
482 // safety: This branch is only truly unreachable if we guarantee
483 // that no values other than the possible enum discriminants
484 // will *ever* be present. The `AtomicUsize` is initialized to
485 // the `OFF` value. It is only set by the `set_max` function,
486 // which takes a `LevelFilter` as a parameter. This restricts
487 // the inputs to `set_max` to the set of valid discriminants.
488 // Therefore, **as long as `MAX_VALUE` is only ever set by
489 // `set_max`**, this is safe.
490 crate::stdlib
::hint
::unreachable_unchecked()
495 pub(crate) fn set_max(LevelFilter(level
): LevelFilter
) {
496 let val
= match level
{
497 Some(Level(level
)) => level
as usize,
498 None
=> Self::OFF_USIZE
,
501 // using an AcqRel swap ensures an ordered relationship of writes to the
503 MAX_LEVEL
.swap(val
, Ordering
::AcqRel
);
507 impl fmt
::Display
for LevelFilter
{
508 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
510 LevelFilter
::OFF
=> f
.pad("off"),
511 LevelFilter
::ERROR
=> f
.pad("error"),
512 LevelFilter
::WARN
=> f
.pad("warn"),
513 LevelFilter
::INFO
=> f
.pad("info"),
514 LevelFilter
::DEBUG
=> f
.pad("debug"),
515 LevelFilter
::TRACE
=> f
.pad("trace"),
520 impl fmt
::Debug
for LevelFilter
{
521 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
523 LevelFilter
::OFF
=> f
.pad("LevelFilter::OFF"),
524 LevelFilter
::ERROR
=> f
.pad("LevelFilter::ERROR"),
525 LevelFilter
::WARN
=> f
.pad("LevelFilter::WARN"),
526 LevelFilter
::INFO
=> f
.pad("LevelFilter::INFO"),
527 LevelFilter
::DEBUG
=> f
.pad("LevelFilter::DEBUG"),
528 LevelFilter
::TRACE
=> f
.pad("LevelFilter::TRACE"),
533 impl FromStr
for LevelFilter
{
534 type Err
= ParseLevelFilterError
;
535 fn from_str(from
: &str) -> Result
<Self, Self::Err
> {
536 from
.parse
::<usize>()
538 .and_then(|num
| match num
{
539 0 => Some(LevelFilter
::OFF
),
540 1 => Some(LevelFilter
::ERROR
),
541 2 => Some(LevelFilter
::WARN
),
542 3 => Some(LevelFilter
::INFO
),
543 4 => Some(LevelFilter
::DEBUG
),
544 5 => Some(LevelFilter
::TRACE
),
547 .or_else(|| match from
{
548 "" => Some(LevelFilter
::ERROR
),
549 s
if s
.eq_ignore_ascii_case("error") => Some(LevelFilter
::ERROR
),
550 s
if s
.eq_ignore_ascii_case("warn") => Some(LevelFilter
::WARN
),
551 s
if s
.eq_ignore_ascii_case("info") => Some(LevelFilter
::INFO
),
552 s
if s
.eq_ignore_ascii_case("debug") => Some(LevelFilter
::DEBUG
),
553 s
if s
.eq_ignore_ascii_case("trace") => Some(LevelFilter
::TRACE
),
554 s
if s
.eq_ignore_ascii_case("off") => Some(LevelFilter
::OFF
),
557 .ok_or_else(|| ParseLevelFilterError(()))
561 /// Returned if parsing a `Level` fails.
563 pub struct ParseLevelError
{
567 impl fmt
::Display
for ParseLevelError
{
568 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
570 "error parsing level: expected one of \"error\", \"warn\", \
571 \"info\", \"debug\", \"trace\", or a number 1-5",
576 impl fmt
::Display
for ParseLevelFilterError
{
577 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
579 "error parsing level filter: expected one of \"off\", \"error\", \
580 \"warn\", \"info\", \"debug\", \"trace\", or a number 0-5",
585 #[cfg(feature = "std")]
586 impl std
::error
::Error
for ParseLevelFilterError {}
588 // ==== Level and LevelFilter comparisons ====
590 // /!\ BIG, IMPORTANT WARNING /!\
591 // Do NOT mess with these implementations! They are hand-written for a reason!
593 // Since comparing `Level`s and `LevelFilter`s happens in a *very* hot path
594 // (potentially, every time a span or event macro is hit, regardless of whether
595 // or not is enabled), we *need* to ensure that these comparisons are as fast as
596 // possible. Therefore, we have some requirements:
598 // 1. We want to do our best to ensure that rustc will generate integer-integer
599 // comparisons wherever possible.
601 // The derived `Ord`/`PartialOrd` impls for `LevelFilter` will not do this,
602 // because `LevelFilter`s are represented by `Option<Level>`, rather than as
603 // a separate `#[repr(usize)]` enum. This was (unfortunately) necessary for
604 // backwards-compatibility reasons, as the `tracing` crate's original
605 // version of `LevelFilter` defined `const fn` conversions between `Level`s
606 // and `LevelFilter`, so we're stuck with the `Option<Level>` repr.
607 // Therefore, we need hand-written `PartialOrd` impls that cast both sides of
608 // the comparison to `usize`s, to force the compiler to generate integer
611 // 2. The hottest `Level`/`LevelFilter` comparison, the one that happens every
612 // time a callsite is hit, occurs *within the `tracing` crate's macros*.
613 // This means that the comparison is happening *inside* a crate that
614 // *depends* on `tracing-core`, not in `tracing-core` itself. The compiler
615 // will only inline function calls across crate boundaries if the called
616 // function is annotated with an `#[inline]` attribute, and we *definitely*
617 // want the comparison functions to be inlined: as previously mentioned, they
618 // should compile down to a single integer comparison on release builds, and
619 // it seems really sad to push an entire stack frame to call a function
620 // consisting of one `cmp` instruction!
622 // Therefore, we need to ensure that all the comparison methods have
623 // `#[inline]` or `#[inline(always)]` attributes. It's not sufficient to just
624 // add the attribute to `partial_cmp` in a manual implementation of the
625 // trait, since it's the comparison operators (`lt`, `le`, `gt`, and `ge`)
626 // that will actually be *used*, and the default implementation of *those*
627 // methods, which calls `partial_cmp`, does not have an inline annotation.
629 // 3. We need the comparisons to be inverted. The discriminants for the
630 // `LevelInner` enum are assigned in "backwards" order, with `TRACE` having
631 // the *lowest* value. However, we want `TRACE` to compare greater-than all
634 // Why are the numeric values inverted? In order to ensure that `LevelFilter`
635 // (which, as previously mentioned, *has* to be internally represented by an
636 // `Option<Level>`) compiles down to a single integer value. This is
637 // necessary for storing the global max in an `AtomicUsize`, and for ensuring
638 // that we use fast integer-integer comparisons, as mentioned previously. In
639 // order to ensure this, we exploit the niche optimization. The niche
640 // optimization for `Option<{enum with a numeric repr}>` will choose
641 // `(HIGHEST_DISCRIMINANT_VALUE + 1)` as the representation for `None`.
642 // Therefore, the integer representation of `LevelFilter::OFF` (which is
643 // `None`) will be the number 5. `OFF` must compare higher than every other
644 // level in order for it to filter as expected. Since we want to use a single
645 // `cmp` instruction, we can't special-case the integer value of `OFF` to
646 // compare higher, as that will generate more code. Instead, we need it to be
647 // on one end of the enum, with `ERROR` on the opposite end, so we assign the
648 // value 0 to `ERROR`.
650 // This *does* mean that when parsing `LevelFilter`s or `Level`s from
651 // `String`s, the integer values are inverted, but that doesn't happen in a
654 // Note that we manually invert the comparisons by swapping the left-hand and
655 // right-hand side. Using `Ordering::reverse` generates significantly worse
656 // code (per Matt Godbolt's Compiler Explorer).
658 // Anyway, that's a brief history of why this code is the way it is. Don't
659 // change it unless you know what you're doing.
661 impl PartialEq
<LevelFilter
> for Level
{
663 fn eq(&self, other
: &LevelFilter
) -> bool
{
664 self.0 as usize == filter_as_usize(&other
.0)
668 impl PartialOrd
for Level
{
670 fn partial_cmp(&self, other
: &Level
) -> Option
<cmp
::Ordering
> {
671 Some(self.cmp(other
))
675 fn lt(&self, other
: &Level
) -> bool
{
676 (other
.0 as usize) < (self.0 as usize)
680 fn le(&self, other
: &Level
) -> bool
{
681 (other
.0 as usize) <= (self.0 as usize)
685 fn gt(&self, other
: &Level
) -> bool
{
686 (other
.0 as usize) > (self.0 as usize)
690 fn ge(&self, other
: &Level
) -> bool
{
691 (other
.0 as usize) >= (self.0 as usize)
697 fn cmp(&self, other
: &Self) -> cmp
::Ordering
{
698 (other
.0 as usize).cmp(&(self.0 as usize))
702 impl PartialOrd
<LevelFilter
> for Level
{
704 fn partial_cmp(&self, other
: &LevelFilter
) -> Option
<cmp
::Ordering
> {
705 Some(filter_as_usize(&other
.0).cmp(&(self.0 as usize)))
709 fn lt(&self, other
: &LevelFilter
) -> bool
{
710 filter_as_usize(&other
.0) < (self.0 as usize)
714 fn le(&self, other
: &LevelFilter
) -> bool
{
715 filter_as_usize(&other
.0) <= (self.0 as usize)
719 fn gt(&self, other
: &LevelFilter
) -> bool
{
720 filter_as_usize(&other
.0) > (self.0 as usize)
724 fn ge(&self, other
: &LevelFilter
) -> bool
{
725 filter_as_usize(&other
.0) >= (self.0 as usize)
730 fn filter_as_usize(x
: &Option
<Level
>) -> usize {
732 Some(Level(f
)) => *f
as usize,
733 None
=> LevelFilter
::OFF_USIZE
,
737 impl PartialEq
<Level
> for LevelFilter
{
739 fn eq(&self, other
: &Level
) -> bool
{
740 filter_as_usize(&self.0) == other
.0 as usize
744 impl PartialOrd
for LevelFilter
{
746 fn partial_cmp(&self, other
: &LevelFilter
) -> Option
<cmp
::Ordering
> {
747 Some(self.cmp(other
))
751 fn lt(&self, other
: &LevelFilter
) -> bool
{
752 filter_as_usize(&other
.0) < filter_as_usize(&self.0)
756 fn le(&self, other
: &LevelFilter
) -> bool
{
757 filter_as_usize(&other
.0) <= filter_as_usize(&self.0)
761 fn gt(&self, other
: &LevelFilter
) -> bool
{
762 filter_as_usize(&other
.0) > filter_as_usize(&self.0)
766 fn ge(&self, other
: &LevelFilter
) -> bool
{
767 filter_as_usize(&other
.0) >= filter_as_usize(&self.0)
771 impl Ord
for LevelFilter
{
773 fn cmp(&self, other
: &Self) -> cmp
::Ordering
{
774 filter_as_usize(&other
.0).cmp(&filter_as_usize(&self.0))
778 impl PartialOrd
<Level
> for LevelFilter
{
780 fn partial_cmp(&self, other
: &Level
) -> Option
<cmp
::Ordering
> {
781 Some((other
.0 as usize).cmp(&filter_as_usize(&self.0)))
785 fn lt(&self, other
: &Level
) -> bool
{
786 (other
.0 as usize) < filter_as_usize(&self.0)
790 fn le(&self, other
: &Level
) -> bool
{
791 (other
.0 as usize) <= filter_as_usize(&self.0)
795 fn gt(&self, other
: &Level
) -> bool
{
796 (other
.0 as usize) > filter_as_usize(&self.0)
800 fn ge(&self, other
: &Level
) -> bool
{
801 (other
.0 as usize) >= filter_as_usize(&self.0)
808 use crate::stdlib
::mem
;
811 fn level_from_str() {
812 assert_eq
!("error".parse
::<Level
>().unwrap(), Level
::ERROR
);
813 assert_eq
!("4".parse
::<Level
>().unwrap(), Level
::DEBUG
);
814 assert
!("0".parse
::<Level
>().is_err())
818 fn filter_level_conversion() {
820 (LevelFilter
::OFF
, None
),
821 (LevelFilter
::ERROR
, Some(Level
::ERROR
)),
822 (LevelFilter
::WARN
, Some(Level
::WARN
)),
823 (LevelFilter
::INFO
, Some(Level
::INFO
)),
824 (LevelFilter
::DEBUG
, Some(Level
::DEBUG
)),
825 (LevelFilter
::TRACE
, Some(Level
::TRACE
)),
827 for (filter
, level
) in mapping
.iter() {
828 assert_eq
!(filter
.clone().into_level(), *level
);
831 let actual
: LevelFilter
= level
.clone().into();
832 assert_eq
!(actual
, *filter
);
835 let actual
: LevelFilter
= None
.into();
836 assert_eq
!(actual
, *filter
);
843 fn level_filter_is_usize_sized() {
845 mem
::size_of
::<LevelFilter
>(),
846 mem
::size_of
::<usize>(),
847 "`LevelFilter` is no longer `usize`-sized! global MAX_LEVEL may now be invalid!"
852 fn level_filter_reprs() {
854 (LevelFilter
::OFF
, LevelInner
::Error
as usize + 1),
855 (LevelFilter
::ERROR
, LevelInner
::Error
as usize),
856 (LevelFilter
::WARN
, LevelInner
::Warn
as usize),
857 (LevelFilter
::INFO
, LevelInner
::Info
as usize),
858 (LevelFilter
::DEBUG
, LevelInner
::Debug
as usize),
859 (LevelFilter
::TRACE
, LevelInner
::Trace
as usize),
861 for &(ref filter
, expected
) in &mapping
{
863 // safety: The entire purpose of this test is to assert that the
864 // actual repr matches what we expect it to be --- we're testing
865 // that *other* unsafe code is sound using the transmuted value.
866 // We're not going to do anything with it that might be unsound.
867 mem
::transmute
::<_
, usize>(filter
.clone())
869 assert_eq
!(expected
, repr
, "repr changed for {:?}", filter
)