11use std:: {
22 fmt:: { self , Debug } ,
3- mem,
4- mem:: { align_of, size_of} ,
53 str:: FromStr ,
64 sync:: atomic:: Ordering ,
75} ;
86
9- use crate :: { utils :: const_assert , Error } ;
7+ use crate :: Error ;
108
119pub ( crate ) const LOG_LEVEL_NAMES : [ & str ; Level :: count ( ) ] =
1210 [ "critical" , "error" , "warn" , "info" , "debug" , "trace" ] ;
@@ -188,11 +186,24 @@ impl FromStr for Level {
188186 }
189187}
190188
189+ #[ repr( u16 ) ]
190+ #[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug , bytemuck:: NoUninit ) ]
191+ enum LevelFilterDiscriminant {
192+ Off ,
193+ Equal ,
194+ NotEqual ,
195+ MoreSevere ,
196+ MoreSevereEqual ,
197+ MoreVerbose ,
198+ MoreVerboseEqual ,
199+ All ,
200+ }
201+
191202/// Represents log level logical filter conditions.
192203///
193204/// Use [`LevelFilter::test`] method to check if a [`Level`] satisfies the
194205/// filter condition.
195- #[ repr( u16 , align( 4 ) ) ]
206+ #[ repr( align( 4 ) ) ]
196207#[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
197208pub enum LevelFilter {
198209 /// Disables all levels.
@@ -277,13 +288,17 @@ impl LevelFilter {
277288 }
278289
279290 #[ must_use]
280- fn discriminant ( & self ) -> u16 {
281- // SAFETY:
282- // Because `LevelFilter` is marked `repr(u16)`, its layout is a `repr(C)`
283- // `union` between `repr(C)` structs, each of which has the `u16` discriminant
284- // as its first field, so we can read the discriminant without offsetting the
285- // pointer.
286- unsafe { * <* const _ >:: from ( self ) . cast :: < u16 > ( ) }
291+ fn discriminant ( & self ) -> LevelFilterDiscriminant {
292+ match self {
293+ Self :: Off => LevelFilterDiscriminant :: Off ,
294+ Self :: Equal ( _) => LevelFilterDiscriminant :: Equal ,
295+ Self :: NotEqual ( _) => LevelFilterDiscriminant :: NotEqual ,
296+ Self :: MoreSevere ( _) => LevelFilterDiscriminant :: MoreSevere ,
297+ Self :: MoreSevereEqual ( _) => LevelFilterDiscriminant :: MoreSevereEqual ,
298+ Self :: MoreVerbose ( _) => LevelFilterDiscriminant :: MoreVerbose ,
299+ Self :: MoreVerboseEqual ( _) => LevelFilterDiscriminant :: MoreVerboseEqual ,
300+ Self :: All => LevelFilterDiscriminant :: All ,
301+ }
287302 }
288303
289304 #[ must_use]
@@ -312,11 +327,17 @@ impl From<log::LevelFilter> for LevelFilter {
312327
313328// Atomic
314329
315- // This struct must have the same memory layout as `LevelFilter`.
330+ // This is a version of `LevelFilter` that does not contain uninitialized bytes.
331+ // For variants like `LevelFilter::{Off,All}`, since they have no field, their
332+ // field memory space is treated as uninitialized bytes. `Atomic<T>` from the
333+ // `atomic` crate uses `std::mem::transmute`, and its operations on
334+ // uninitialized bytes are undefined behavior. Therefore, we created this
335+ // `LevelFilterLayout` type, where uninitialized bytes are filled with
336+ // `UNDEFINED_FALLBACK`, enabling safe atomic operations.
316337#[ repr( C , align( 4 ) ) ]
317338#[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug , bytemuck:: NoUninit ) ]
318339struct LevelFilterLayout {
319- discriminant : u16 , // Keep the type in sync with the repr of `LevelFilter`
340+ discriminant : LevelFilterDiscriminant ,
320341 level : Level ,
321342}
322343
@@ -326,8 +347,6 @@ impl LevelFilterLayout {
326347
327348impl From < LevelFilter > for LevelFilterLayout {
328349 fn from ( value : LevelFilter ) -> Self {
329- // Use `mem::transmute` here is undefined behavior, because `LevelFilter`
330- // contains uninitialized bytes.
331350 Self {
332351 discriminant : value. discriminant ( ) ,
333352 level : value. level ( ) . unwrap_or ( Self :: UNDEFINED_FALLBACK ) ,
@@ -336,22 +355,20 @@ impl From<LevelFilter> for LevelFilterLayout {
336355}
337356
338357impl From < LevelFilterLayout > for LevelFilter {
339- fn from ( inner : LevelFilterLayout ) -> Self {
340- // SAFETY:
341- // - Repr of `LevelFilter` is C union.
342- // - Repr of `LevelFilterLayout` is C struct, it has the same memory layout as
343- // `LevelFilter`.
344- // - `LevelFilterLayout` doesn't contain uninitialized bytes.
345- unsafe { mem:: transmute :: < _ , LevelFilter > ( inner) }
358+ fn from ( layout : LevelFilterLayout ) -> Self {
359+ match layout. discriminant {
360+ LevelFilterDiscriminant :: Off => Self :: Off ,
361+ LevelFilterDiscriminant :: Equal => Self :: Equal ( layout. level ) ,
362+ LevelFilterDiscriminant :: NotEqual => Self :: NotEqual ( layout. level ) ,
363+ LevelFilterDiscriminant :: MoreSevere => Self :: MoreSevere ( layout. level ) ,
364+ LevelFilterDiscriminant :: MoreSevereEqual => Self :: MoreSevereEqual ( layout. level ) ,
365+ LevelFilterDiscriminant :: MoreVerbose => Self :: MoreVerbose ( layout. level ) ,
366+ LevelFilterDiscriminant :: MoreVerboseEqual => Self :: MoreVerboseEqual ( layout. level ) ,
367+ LevelFilterDiscriminant :: All => Self :: All ,
368+ }
346369 }
347370}
348371
349- // If these assertions are not satisfied, `mem::transmute` may result in
350- // undefined behavior.
351- const_assert ! ( size_of:: <Level >( ) * 2 == size_of:: <LevelFilter >( ) ) ;
352- const_assert ! ( align_of:: <LevelFilterLayout >( ) == align_of:: <LevelFilter >( ) ) ;
353- const_assert ! ( size_of:: <LevelFilterLayout >( ) == size_of:: <LevelFilter >( ) ) ;
354-
355372/// Atomic version of [`LevelFilter`] which can be safely shared between
356373/// threads.
357374pub struct AtomicLevelFilter {
@@ -410,11 +427,15 @@ impl Debug for AtomicLevelFilter {
410427
411428#[ cfg( test) ]
412429mod tests {
430+ use std:: mem:: size_of;
431+
413432 use super :: * ;
433+ use crate :: utils:: const_assert;
414434
415435 const_assert ! ( atomic:: Atomic :: <Level >:: is_lock_free( ) ) ;
416436 const_assert ! ( atomic:: Atomic :: <LevelFilter >:: is_lock_free( ) ) ;
417437 const_assert ! ( atomic:: Atomic :: <LevelFilterLayout >:: is_lock_free( ) ) ;
438+ const_assert ! ( size_of:: <Level >( ) * 2 == size_of:: <LevelFilter >( ) ) ;
418439
419440 #[ test]
420441 fn from_usize ( ) {
0 commit comments