Skip to content

Commit d517090

Browse files
committed
Move macro_rules! macros into their own file.
1 parent 54cb055 commit d517090

File tree

2 files changed

+201
-192
lines changed

2 files changed

+201
-192
lines changed

src/lib.rs

Lines changed: 3 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -89,202 +89,13 @@ pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_str
8989
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition};
9090
pub 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

27597
mod 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")]
289100
mod tokenizer;
290101

0 commit comments

Comments
 (0)