@@ -89,202 +89,13 @@ pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_str
8989pub use parser:: { Parser , Delimiter , Delimiters , SourcePosition } ;
9090pub use unicode_range:: UnicodeRange ;
9191
92- /// Expands to an expression equivalent to a `match` with string patterns,
93- /// but matching is case-insensitive in the ASCII range.
94- ///
95- /// Requirements:
96- ///
97- /// * The `cssparser_macros` crate must also be imported at the crate root
98- /// * The patterns must not contain ASCII upper case letters. (They must be already be lower-cased.)
99- ///
100- /// # Example
101- ///
102- /// ```rust
103- /// #[macro_use] extern crate cssparser;
104- /// #[macro_use] extern crate cssparser_macros;
105- ///
106- /// # fn main() {} // Make doctest not wrap everythig in its own main
107- /// # fn dummy(function_name: &String) { let _ =
108- /// match_ignore_ascii_case! { &function_name,
109- /// "rgb" => parse_rgb(..),
110- /// "rgba" => parse_rgba(..),
111- /// "hsl" => parse_hsl(..),
112- /// "hsla" => parse_hsla(..),
113- /// _ => Err("unknown function")
114- /// }
115- /// # ;}
116- /// # use std::ops::RangeFull;
117- /// # fn parse_rgb(_: RangeFull) -> Result<(), &'static str> { Err("") }
118- /// # fn parse_rgba(_: RangeFull) -> Result<(), &'static str> { Err("") }
119- /// # fn parse_hsl(_: RangeFull) -> Result<(), &'static str> { Err("") }
120- /// # fn parse_hsla(_: RangeFull) -> Result<(), &'static str> { Err("") }
121- /// ```
122- #[ macro_export]
123- macro_rules! match_ignore_ascii_case {
124- // parse the last case plus the fallback
125- ( @inner $value: expr, ( $string: expr => $result: expr, _ => $fallback: expr) -> ( $( $parsed: tt) * ) ) => {
126- match_ignore_ascii_case!( @inner $value, ( ) -> ( $( $parsed) * ( $string => $result) ) $fallback)
127- } ;
92+ #[ doc( hidden) ] pub use macros:: _internal__to_lowercase;
12893
129- // parse a case (not the last one)
130- ( @inner $value: expr, ( $string: expr => $result: expr, $( $rest: tt) * ) -> ( $( $parsed: tt) * ) ) => {
131- match_ignore_ascii_case!( @inner $value, ( $( $rest) * ) -> ( $( $parsed) * ( $string => $result) ) )
132- } ;
133-
134- // finished parsing
135- ( @inner $value: expr, ( ) -> ( $( ( $string: expr => $result: expr) ) * ) $fallback: expr ) => {
136- {
137- _cssparser_internal__pretend_proc_macro! {
138- cssparser__assert_ascii_lowercase!( $( $string ) + )
139- }
140-
141- {
142- _cssparser_internal__to_lowercase!( $value => lowercase, $( $string) ,+) ;
143- match lowercase {
144- $(
145- Some ( $string) => $result,
146- ) +
147- _ => $fallback
148- }
149- }
150- }
151- } ;
152-
153- // entry point, start parsing
154- ( $value: expr, $( $rest: tt) * ) => {
155- match_ignore_ascii_case!( @inner $value, ( $( $rest) * ) -> ( ) )
156- } ;
157- }
158-
159- /// Define a function `$name(&str) -> Option<&'static $ValueType>`
160- ///
161- /// The function finds a match for the input string
162- /// in a [`phf` map](https://github.com/sfackler/rust-phf)
163- /// and returns a reference to the corresponding value.
164- /// Matching is case-insensitive in the ASCII range.
165- ///
166- /// The `phf` and `cssparser_macros` crates must also be imported at the crate root
167- ///
168- /// ## Example:
169- ///
170- /// ```rust
171- /// extern crate phf;
172- /// #[macro_use] extern crate cssparser;
173- /// #[macro_use] extern crate cssparser_macros;
174- ///
175- /// # fn main() {} // Make doctest not wrap everythig in its own main
176- ///
177- /// fn color_rgb(input: &str) -> Option<(u8, u8, u8)> {
178- /// ascii_case_insensitive_phf_map! {
179- /// keyword -> (u8, u8, u8) = {
180- /// "red" => (255, 0, 0),
181- /// "green" => (0, 255, 0),
182- /// "blue" => (0, 0, 255),
183- /// }
184- /// }
185- /// keyword(input).cloned()
186- /// }
187- #[ macro_export]
188- macro_rules! ascii_case_insensitive_phf_map {
189- ( $name: ident -> $ValueType: ty = { $( $key: expr => $value: expr, ) * } ) => {
190- fn $name( input: & str ) -> Option <& ' static $ValueType> {
191- _cssparser_internal__pretend_proc_macro! {
192- cssparser__phf_map!( ( $ValueType) $( $key ( $value) ) + )
193- }
194-
195- {
196- _cssparser_internal__to_lowercase!( input => lowercase, $( $key) ,+) ;
197- lowercase. and_then( |s| MAP . get( s) )
198- }
199- }
200- }
201- }
202-
203- /// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
204- ///
205- /// **This macro is not part of the public API. It can change or be removed between any versions.**
206- ///
207- /// * Check at compile-time that none of the `$string`s contain ASCII uppercase letters
208- /// * Define a local variable named `$output` to the result of calling `_internal__to_lowercase`
209- /// with a stack-allocated buffer as long as the longest `$string`.
210- #[ macro_export]
211- #[ doc( hidden) ]
212- macro_rules! _cssparser_internal__to_lowercase {
213- ( $input: expr => $output: ident, $( $string: expr) ,+) => {
214- _cssparser_internal__pretend_proc_macro! {
215- cssparser__max_len!( $( $string ) + )
216- }
217-
218- // mem::uninitialized() is ok because `buffer` is only used in `_internal__to_lowercase`,
219- // which initializes with `copy_from_slice` the part of the buffer it uses,
220- // before it uses it.
221- #[ allow( unsafe_code) ]
222- // MAX_LENGTH is generated by cssparser__max_len
223- let mut buffer: [ u8 ; MAX_LENGTH ] = unsafe {
224- :: std:: mem:: uninitialized( )
225- } ;
226- let input: & str = $input;
227- let $output = $crate:: _internal__to_lowercase( & mut buffer, input) ;
228- }
229- }
230-
231- /// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
232- ///
233- /// **This macro is not part of the public API. It can change or be removed between any versions.**
234- #[ macro_export]
235- #[ doc( hidden) ]
236- macro_rules! _cssparser_internal__pretend_proc_macro {
237- ( $macro_name: ident ! ( $( $tt: tt) * ) ) => {
238- #[ derive( $macro_name) ]
239- #[ allow( unused) ]
240- enum Dummy {
241- Input = ( 0 , stringify!( $( $tt ) * ) ) . 0
242- }
243- }
244- }
245-
246- /// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
247- ///
248- /// **This function is not part of the public API. It can change or be removed between any verisons.**
249- ///
250- /// Return `input`, lower-cased, unless larger than `buffer`
251- /// which is used temporary space for lower-casing a copy of `input` if necessary.
252- #[ doc( hidden) ]
253- #[ allow( non_snake_case) ]
254- pub fn _internal__to_lowercase < ' a > ( buffer : & ' a mut [ u8 ] , input : & ' a str ) -> Option < & ' a str > {
255- if let Some ( buffer) = buffer. get_mut ( ..input. len ( ) ) {
256- if let Some ( first_uppercase) = input. bytes ( ) . position ( |byte| matches ! ( byte, b'A' ...b'Z' ) ) {
257- buffer. copy_from_slice ( input. as_bytes ( ) ) ;
258- std:: ascii:: AsciiExt :: make_ascii_lowercase ( & mut buffer[ first_uppercase..] ) ;
259- // `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
260- // then lowercased (which preserves UTF-8 well-formedness)
261- unsafe {
262- Some ( :: std:: str:: from_utf8_unchecked ( buffer) )
263- }
264- } else {
265- // Input is already lower-case
266- Some ( input)
267- }
268- } else {
269- // Input is longer than buffer, which has the length of the longest expected string:
270- // none of the expected strings would match.
271- None
272- }
273- }
94+ #[ macro_use]
95+ mod macros;
27496
27597mod rules_and_declarations;
27698
277- #[ cfg( feature = "dummy_match_byte" ) ]
278- macro_rules! match_byte {
279- ( $value: expr, $( $rest: tt) * ) => {
280- match $value {
281- $(
282- $rest
283- ) +
284- }
285- } ;
286- }
287-
28899#[ cfg( feature = "dummy_match_byte" ) ]
289100mod tokenizer;
290101
0 commit comments