2
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
4
5
- use std:: mem:: MaybeUninit ;
5
+ // See docs of the `procedural-masquerade` crate.
6
+ define_invoke_proc_macro ! ( cssparser_internal__invoke_proc_macro) ;
6
7
7
8
/// Expands to a `match` expression with string patterns,
8
9
/// matching case-insensitively in the ASCII range.
@@ -34,21 +35,18 @@ use std::mem::MaybeUninit;
34
35
macro_rules! match_ignore_ascii_case {
35
36
( $input: expr, $( $match_body: tt ) * ) => {
36
37
{
37
- // This dummy module works around the feature gate
38
- // `error[E0658]: procedural macros cannot be expanded to statements`
39
- // by forcing the macro to be in an item context
40
- // rather than expression/statement context,
41
- // even though the macro only expands to items.
42
- mod cssparser_internal {
43
- cssparser_internal__assert_ascii_lowercase__max_len! {
44
- match x { $( $match_body ) * }
45
- }
38
+ cssparser_internal__invoke_proc_macro! {
39
+ cssparser_internal__assert_ascii_lowercase__max_len!( $( $match_body ) * )
46
40
}
47
- cssparser_internal__to_lowercase!( $input, cssparser_internal:: MAX_LENGTH => lowercase) ;
48
- // "A" is a short string that we know is different for every string pattern,
49
- // since we’ve verified that none of them include ASCII upper case letters.
50
- match lowercase. unwrap_or( "A" ) {
51
- $( $match_body ) *
41
+
42
+ {
43
+ // MAX_LENGTH is generated by cssparser_internal__assert_ascii_lowercase__max_len
44
+ cssparser_internal__to_lowercase!( $input, MAX_LENGTH => lowercase) ;
45
+ // "A" is a short string that we know is different for every string pattern,
46
+ // since we’ve verified that none of them include ASCII upper case letters.
47
+ match lowercase. unwrap_or( "A" ) {
48
+ $( $match_body ) *
49
+ }
52
50
}
53
51
}
54
52
} ;
@@ -80,21 +78,23 @@ macro_rules! match_ignore_ascii_case {
80
78
/// }
81
79
#[ macro_export]
82
80
macro_rules! ascii_case_insensitive_phf_map {
83
- ( $name: ident -> $ValueType: ty = { $( $key: tt => $value: expr ) ,+ } ) => {
84
- ascii_case_insensitive_phf_map!( $name -> $ValueType = { $( $key => $value, ) + } )
81
+ ( $name: ident -> $ValueType: ty = { $( $key: expr => $value: expr ) ,* } ) => {
82
+ ascii_case_insensitive_phf_map!( $name -> $ValueType = { $( $key => $value, ) * } )
85
83
} ;
86
- ( $name: ident -> $ValueType: ty = { $( $key: tt => $value: expr, ) + } ) => {
84
+ ( $name: ident -> $ValueType: ty = { $( $key: expr => $value: expr, ) * } ) => {
87
85
pub fn $name( input: & str ) -> Option <& ' static $ValueType> {
88
- // This dummy module works around a feature gate,
89
- // see comment on the similar module in `match_ignore_ascii_case!` above.
90
- mod cssparser_internal {
91
- use $crate:: _internal__phf:: { Map , phf_map} ;
92
- #[ allow( unused) ] use super :: * ;
93
- cssparser_internal__max_len!( $( $key ) + ) ;
94
- cssparser_internal__phf_map!( $ValueType $( $key $value ) + ) ;
86
+ cssparser_internal__invoke_proc_macro! {
87
+ cssparser_internal__phf_map!( ( $ValueType) $( $key ( $value) ) + )
88
+ }
89
+
90
+ {
91
+ cssparser_internal__invoke_proc_macro! {
92
+ cssparser_internal__max_len!( $( $key ) + )
93
+ }
94
+ // MAX_LENGTH is generated by cssparser_internal__max_len
95
+ cssparser_internal__to_lowercase!( input, MAX_LENGTH => lowercase) ;
96
+ lowercase. and_then( |s| MAP . get( s) )
95
97
}
96
- cssparser_internal__to_lowercase!( input, cssparser_internal:: MAX_LENGTH => lowercase) ;
97
- lowercase. and_then( |s| cssparser_internal:: MAP . get( s) )
98
98
}
99
99
}
100
100
}
@@ -110,16 +110,38 @@ macro_rules! ascii_case_insensitive_phf_map {
110
110
#[ doc( hidden) ]
111
111
macro_rules! cssparser_internal__to_lowercase {
112
112
( $input: expr, $BUFFER_SIZE: expr => $output: ident) => {
113
+ let mut buffer;
114
+ // Safety: `buffer` is only used in `_internal__to_lowercase`,
115
+ // which initializes with `copy_from_slice` the part of the buffer it uses,
116
+ // before it uses it.
113
117
#[ allow( unsafe_code) ]
114
- let mut buffer = unsafe {
115
- :: std:: mem:: MaybeUninit :: <[ :: std:: mem:: MaybeUninit <u8 >; $BUFFER_SIZE] >:: uninit( )
116
- . assume_init( )
117
- } ;
118
+ let buffer = unsafe { cssparser_internal__uninit!( buffer, $BUFFER_SIZE) } ;
118
119
let input: & str = $input;
119
- let $output = $crate:: _internal__to_lowercase( & mut buffer, input) ;
120
+ let $output = $crate:: _internal__to_lowercase( buffer, input) ;
120
121
} ;
121
122
}
122
123
124
+ #[ cfg( has_std__mem__MaybeUninit) ]
125
+ #[ macro_export]
126
+ #[ doc( hidden) ]
127
+ macro_rules! cssparser_internal__uninit {
128
+ ( $buffer: ident, $BUFFER_SIZE: expr) => { {
129
+ $buffer = :: std:: mem:: MaybeUninit :: <[ u8 ; $BUFFER_SIZE] >:: uninit( ) ;
130
+ & mut * ( $buffer. as_mut_ptr( ) )
131
+ } } ;
132
+ }
133
+
134
+ // FIXME: remove this when we require Rust 1.36
135
+ #[ cfg( not( has_std__mem__MaybeUninit) ) ]
136
+ #[ macro_export]
137
+ #[ doc( hidden) ]
138
+ macro_rules! cssparser_internal__uninit {
139
+ ( $buffer: ident, $BUFFER_SIZE: expr) => { {
140
+ $buffer = :: std:: mem:: uninitialized:: <[ u8 ; $BUFFER_SIZE] >( ) ;
141
+ & mut $buffer
142
+ } } ;
143
+ }
144
+
123
145
/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
124
146
///
125
147
/// **This function is not part of the public API. It can change or be removed between any verisons.**
@@ -128,28 +150,14 @@ macro_rules! cssparser_internal__to_lowercase {
128
150
/// Otherwise, return `input` ASCII-lowercased, using `buffer` as temporary space if necessary.
129
151
#[ doc( hidden) ]
130
152
#[ allow( non_snake_case) ]
131
- pub fn _internal__to_lowercase < ' a > (
132
- buffer : & ' a mut [ MaybeUninit < u8 > ] ,
133
- input : & ' a str ,
134
- ) -> Option < & ' a str > {
153
+ pub fn _internal__to_lowercase < ' a > ( buffer : & ' a mut [ u8 ] , input : & ' a str ) -> Option < & ' a str > {
135
154
if let Some ( buffer) = buffer. get_mut ( ..input. len ( ) ) {
136
155
if let Some ( first_uppercase) = input. bytes ( ) . position ( |byte| matches ! ( byte, b'A' ..=b'Z' ) ) {
137
- unsafe {
138
- // This cast doesn’t change the pointer’s validity
139
- // since `u8` has the same layout as `MaybeUninit<u8>`:
140
- let input_bytes = & * ( input. as_bytes ( ) as * const [ u8 ] as * const [ MaybeUninit < u8 > ] ) ;
141
-
142
- buffer. copy_from_slice ( & * input_bytes) ;
143
-
144
- // Same as above re layout, plus these bytes have been initialized:
145
- let buffer = & mut * ( buffer as * mut [ MaybeUninit < u8 > ] as * mut [ u8 ] ) ;
146
-
147
- buffer[ first_uppercase..] . make_ascii_lowercase ( ) ;
148
- // `buffer` was initialized to a copy of `input`
149
- // (which is `&str` so well-formed UTF-8)
150
- // then ASCII-lowercased (which preserves UTF-8 well-formedness):
151
- Some ( :: std:: str:: from_utf8_unchecked ( buffer) )
152
- }
156
+ buffer. copy_from_slice ( input. as_bytes ( ) ) ;
157
+ buffer[ first_uppercase..] . make_ascii_lowercase ( ) ;
158
+ // `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
159
+ // then lowercased (which preserves UTF-8 well-formedness)
160
+ unsafe { Some ( :: std:: str:: from_utf8_unchecked ( buffer) ) }
153
161
} else {
154
162
// Input is already lower-case
155
163
Some ( input)
0 commit comments