@@ -52,6 +52,7 @@ use core::iter::FromIterator;
52
52
mod details {
53
53
use core:: ops:: { BitAnd , BitOr , BitXor , Not } ;
54
54
use core:: cmp:: PartialOrd ;
55
+ use core:: fmt:: { self , Debug } ;
55
56
56
57
pub trait BitFlagNum
57
58
: Default
@@ -69,21 +70,56 @@ mod details {
69
70
impl BitFlagNum for u32 { }
70
71
impl BitFlagNum for u64 { }
71
72
impl BitFlagNum for usize { }
72
- }
73
73
74
- use details:: BitFlagNum ;
74
+ // Format an iterator of flags into "A | B | etc"
75
+ pub ( crate ) struct FlagFormatter < I > ( pub I ) ;
76
+
77
+ impl < T : Debug , I : Clone + Iterator < Item =T > > Debug for FlagFormatter < I > {
78
+ fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
79
+ let mut iter = self . 0 . clone ( ) ;
80
+ if let Some ( val) = iter. next ( ) {
81
+ write ! ( fmt, "{:?}" , val) ?
82
+ }
83
+ for val in iter {
84
+ write ! ( fmt, " | {:?}" , val) ?
85
+ }
86
+ Ok ( ( ) )
87
+ }
88
+ }
75
89
76
- /// A trait automatically implemented by `derive(EnumFlags)` on `T` to enable debug printing of
77
- /// `BitFlags<T>`. This is necessary because the names of the variants are needed.
78
- #[ doc( hidden) ]
79
- pub trait BitFlagsFmt
80
- where
81
- Self : RawBitFlags ,
82
- {
83
- /// The implementation of Debug redirects here.
84
- fn fmt ( flags : BitFlags < Self > , f : & mut fmt:: Formatter ) -> fmt:: Result ;
90
+ // A formatter that obeys format arguments but falls back to binary when
91
+ // no explicit format is requested. Supports {:08?}, {:08x?}, etc.
92
+ pub ( crate ) struct DebugBinaryFormatter < ' a , F > ( pub & ' a F ) ;
93
+
94
+ impl < ' a , F : fmt:: Debug + fmt:: Binary + ' a > fmt:: Debug for DebugBinaryFormatter < ' a , F > {
95
+ fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
96
+ // Check if {:x?} or {:X?} was used; this is determined via the
97
+ // discriminator of core::fmt::FlagV1::{DebugLowerHex, DebugUpperHex},
98
+ // which is not an accessible type: https://github.com/rust-lang/rust/blob/d65e272a9fe3e61aa5f229c5358e35a909435575/src/libcore/fmt/mod.rs#L306
99
+ // See also: https://github.com/rust-lang/rfcs/pull/2226
100
+ #[ allow( deprecated) ]
101
+ let format_hex = fmt. flags ( ) & ( 3 << 4 ) != 0 ;
102
+
103
+ if format_hex {
104
+ // fmt::Debug machinery handles everything properly
105
+ if !fmt. alternate ( ) {
106
+ write ! ( fmt, "0x" ) ?
107
+ }
108
+ fmt:: Debug :: fmt ( self . 0 , fmt)
109
+ } else {
110
+ // Fall back to binary otheriwse but retain all other arguments
111
+ // such as padding, alignment, etc.
112
+ if !fmt. alternate ( ) {
113
+ write ! ( fmt, "0b" ) ?
114
+ }
115
+ fmt:: Binary :: fmt ( self . 0 , fmt)
116
+ }
117
+ }
118
+ }
85
119
}
86
120
121
+ use details:: BitFlagNum ;
122
+
87
123
/// A trait automatically implemented by `derive(EnumFlags)` to make the enum a valid type parameter
88
124
/// for BitFlags.
89
125
#[ doc( hidden) ]
@@ -99,6 +135,13 @@ pub trait RawBitFlags: Copy + Clone + 'static {
99
135
100
136
/// Return a slice that contains each variant exactly one.
101
137
fn flag_list ( ) -> & ' static [ Self ] ;
138
+
139
+ /// Return the name of the type for debug formatting purposes.
140
+ ///
141
+ /// This is typically `BitFlags<EnumName>`
142
+ fn bitflags_type_name ( ) -> & ' static str {
143
+ "BitFlags"
144
+ }
102
145
}
103
146
104
147
/// Represents a set of flags of some type `T`.
@@ -111,10 +154,17 @@ pub struct BitFlags<T: RawBitFlags> {
111
154
112
155
impl < T > fmt:: Debug for BitFlags < T >
113
156
where
114
- T : RawBitFlags + BitFlagsFmt ,
157
+ T : RawBitFlags + fmt:: Debug ,
158
+ T :: Type : fmt:: Binary + fmt:: Debug ,
115
159
{
116
160
fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
117
- T :: fmt ( self . clone ( ) , fmt)
161
+ let mut debug = fmt. debug_tuple ( T :: bitflags_type_name ( ) ) ;
162
+ debug. field ( & details:: DebugBinaryFormatter ( & self . bits ( ) ) ) ;
163
+ if !self . is_empty ( ) {
164
+ let iter = T :: flag_list ( ) . iter ( ) . filter ( |& & flag| self . contains ( flag) ) ;
165
+ debug. field ( & details:: FlagFormatter ( iter) ) ;
166
+ }
167
+ debug. finish ( )
118
168
}
119
169
}
120
170
0 commit comments