@@ -20,13 +20,13 @@ pub fn derive_enum_flags(input: proc_macro::TokenStream) -> proc_macro::TokenStr
20
20
}
21
21
}
22
22
23
- fn max_value_of ( ty : & str ) -> Option < usize > {
23
+ fn max_value_of ( ty : & str ) -> Option < u64 > {
24
24
match ty {
25
- "u8" => Some ( u8:: max_value ( ) as usize ) ,
26
- "u16" => Some ( u16:: max_value ( ) as usize ) ,
27
- "u32" => Some ( u32:: max_value ( ) as usize ) ,
28
- "u64" => Some ( u64:: max_value ( ) as usize ) ,
29
- "usize" => Some ( usize:: max_value ( ) ) ,
25
+ "u8" => Some ( u8:: max_value ( ) as u64 ) ,
26
+ "u16" => Some ( u16:: max_value ( ) as u64 ) ,
27
+ "u32" => Some ( u32:: max_value ( ) as u64 ) ,
28
+ "u64" => Some ( u64:: max_value ( ) as u64 ) ,
29
+ "usize" => Some ( usize:: max_value ( ) as u64 ) ,
30
30
_ => None ,
31
31
}
32
32
}
@@ -85,39 +85,36 @@ fn gen_enumflags(ident: &Ident, item: &DeriveInput, data: &DataEnum) -> TokenStr
85
85
. map ( |d| fold_expr ( & d. 1 ) ) . expect ( "No discriminant" ) )
86
86
. collect ( ) ;
87
87
let variants_len = flag_values. len ( ) ;
88
- assert ! ( flag_values. iter( ) . all( |& v| v != 0 ) , "Null flag is not allowed" ) ;
89
88
let names = flag_values. iter ( ) . map ( |_| & ident) ;
90
89
let ty = extract_repr ( & item. attrs ) . unwrap_or ( Ident :: new ( "usize" , span) ) ;
91
- let max_flag_value = flag_values. iter ( ) . max ( ) . unwrap ( ) ;
92
90
let max_allowed_value = max_value_of ( & ty. to_string ( ) ) . expect ( & format ! ( "{} is not supported" , ty) ) ;
93
- assert ! (
94
- * max_flag_value as usize <= max_allowed_value,
95
- format!(
96
- "Value '0b{val:b}' is too big for an {ty}" ,
97
- val = max_flag_value,
98
- ty = ty
99
- )
100
- ) ;
101
- let wrong_flag_values: & Vec < _ > = & flag_values
102
- . iter ( )
103
- . zip ( variants. clone ( ) )
104
- . filter ( |& ( & val, _) | flag_values. iter ( ) . filter ( |& & v| v & val != 0 ) . count ( ) > 1 )
105
- . map ( |( value, variant) | {
106
- format ! (
107
- "{name}::{variant} = 0b{value:b}" ,
108
- name = ident,
109
- variant = variant,
110
- value = value
111
- )
112
- } )
113
- . collect ( ) ;
114
- assert ! (
115
- wrong_flag_values. is_empty( ) ,
116
- format!(
117
- "The following flags are not unique: {data:?}" ,
118
- data = wrong_flag_values
119
- )
120
- ) ;
91
+
92
+ let mut flags_seen = 0 ;
93
+ for ( & flag, variant) in flag_values. iter ( ) . zip ( variants. clone ( ) ) {
94
+ if flag > max_allowed_value {
95
+ panic ! ( "Value {:#b} is too big for an {}" ,
96
+ flag, ty
97
+ ) ;
98
+ } else if flag == 0 || !flag. is_power_of_two ( ) {
99
+ panic ! ( "Each flag must have exactly one bit set, and {ident}::{variant} = {flag:#b} doesn't" ,
100
+ ident = ident,
101
+ variant = variant,
102
+ flag = flag
103
+ ) ;
104
+ } else if flags_seen & flag != 0 {
105
+ panic ! ( "Flag {} collides with {}" ,
106
+ variant,
107
+ flag_values. iter( )
108
+ . zip( variants. clone( ) )
109
+ . find( |( & other_flag, _) | flag == other_flag)
110
+ . unwrap( )
111
+ . 1
112
+ ) ;
113
+ }
114
+
115
+ flags_seen |= flag;
116
+ }
117
+
121
118
let std_path = quote_spanned ! ( span=> :: enumflags2:: _internal:: core) ;
122
119
quote_spanned ! {
123
120
span =>
0 commit comments