Skip to content

Commit bc313df

Browse files
committed
Make phf for color matching optional
Signed-off-by: Nico Burns <nico@nicoburns.com>
1 parent 9d39c9e commit bc313df

4 files changed

Lines changed: 74 additions & 10 deletions

File tree

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ encoding_rs = "0.8"
2323
cssparser-macros = { path = "./macros", version = "0.6.1", optional = true }
2424
dtoa-short = "0.3"
2525
itoa = "1.0"
26-
phf = { version = "0.13.1", features = ["macros"] }
26+
phf = { version = "0.13.1", features = ["macros"], optional = true }
2727
serde = { version = "1.0", features = ["derive"], optional = true }
2828
malloc_size_of = { version = "0.1", default-features = false, optional = true }
2929
smallvec = "1.0"
@@ -33,9 +33,10 @@ inherits = "release"
3333
debug = true
3434

3535
[features]
36-
default = ["fast_match_byte"]
36+
default = ["fast_match_byte", "fast_match_color"]
3737
bench = []
3838
fast_match_byte = ["dep:cssparser-macros"]
39+
fast_match_color = ["dep:phf"]
3940
# Useful for skipping tests when execution is slow, e.g., under miri
4041
skip_long_tests = []
4142

src/color.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ pub fn parse_hash_color(value: &[u8]) -> Result<(u8, u8, u8, f32), ()> {
172172
})
173173
}
174174

175-
ascii_case_insensitive_phf_map! {
175+
ascii_case_insensitive_map! {
176176
named_colors -> (u8, u8, u8) = {
177177
"black" => (0, 0, 0),
178178
"silver" => (192, 192, 192),

src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,6 @@ mod mac {
116116
}
117117
}
118118

119-
#[doc(hidden)]
120-
pub use phf as _cssparser_internal_phf;
121-
122119
#[macro_use]
123120
mod macros;
124121

src/macros.rs

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ macro_rules! match_ignore_ascii_case {
7575
};
7676
}
7777

78+
#[cfg(not(feature = "fast_match_color"))]
79+
#[macro_export]
7880
/// Define a function `$name(&str) -> Option<&'static $ValueType>`
7981
///
8082
/// The function finds a match for the input string
@@ -100,13 +102,77 @@ macro_rules! match_ignore_ascii_case {
100102
/// ```
101103
///
102104
/// You can also iterate over the map entries by using `keywords::entries()`.
105+
macro_rules! ascii_case_insensitive_map {
106+
($name: ident -> $ValueType: ty = { $( $key: tt => $value: expr ),+ }) => {
107+
ascii_case_insensitive_phf_map!($name -> $ValueType = { $( $key => $value, )+ })
108+
};
109+
($name: ident -> $ValueType: ty = { $( $key: tt => $value: expr, )+ }) => {
110+
111+
// While the obvious choice for this would be an inner module, it's not possible to
112+
// reference from types from there, see:
113+
// <https://github.com/rust-lang/rust/issues/114369>
114+
//
115+
// So we abuse a struct with static associated functions instead.
116+
#[allow(non_camel_case_types)]
117+
struct $name;
118+
impl $name {
119+
#[allow(dead_code)]
120+
fn entries() -> impl Iterator<Item = (&'static &'static str, &'static $ValueType)> {
121+
[ $((&$key, &$value),)* ].iter().copied()
122+
}
123+
124+
fn get(input: &str) -> Option<&'static $ValueType> {
125+
$crate::match_ignore_ascii_case!(input,
126+
$($key => Some(&$value),)*
127+
_ => None,
128+
)
129+
}
130+
}
131+
}
132+
}
133+
134+
#[cfg(feature = "fast_match_color")]
135+
#[macro_export]
136+
/// Define a function `$name(&str) -> Option<&'static $ValueType>`
137+
///
138+
/// The function finds a match for the input string
139+
/// in a [`phf` map](https://github.com/sfackler/rust-phf)
140+
/// and returns a reference to the corresponding value.
141+
/// Matching is case-insensitive in the ASCII range.
142+
///
143+
/// ## Example:
144+
///
145+
/// ```rust
146+
/// # fn main() {} // Make doctest not wrap everything in its own main
147+
///
148+
/// fn color_rgb(input: &str) -> Option<(u8, u8, u8)> {
149+
/// cssparser::ascii_case_insensitive_map! {
150+
/// static KEYWORDS : (u8, u8, u8) = {
151+
/// "red" => (255, 0, 0),
152+
/// "green" => (0, 255, 0),
153+
/// "blue" => (0, 0, 255),
154+
/// }
155+
/// }
156+
/// KEYWORDS::get(input).cloned()
157+
/// }
158+
/// ```
159+
///
160+
/// You can also iterate over the map entries by using `keywords::entries()`.
161+
macro_rules! ascii_case_insensitive_map {
162+
($($any:tt)+) => {
163+
$crate::ascii_case_insensitive_phf_map!($($any)+);
164+
};
165+
}
166+
167+
/// Fast implementation of `ascii_case_insensitive_map!` using a phf map.
168+
/// See `ascii_case_insensitive_map!` above for docs
169+
#[cfg(feature = "fast_match_color")]
103170
#[macro_export]
104171
macro_rules! ascii_case_insensitive_phf_map {
105172
($name: ident -> $ValueType: ty = { $( $key: tt => $value: expr ),+ }) => {
106173
ascii_case_insensitive_phf_map!($name -> $ValueType = { $( $key => $value, )+ })
107174
};
108175
($name: ident -> $ValueType: ty = { $( $key: tt => $value: expr, )+ }) => {
109-
use $crate::_cssparser_internal_phf as phf;
110176

111177
#[inline(always)]
112178
const fn const_usize_max(a: usize, b: usize) -> usize {
@@ -126,7 +192,7 @@ macro_rules! ascii_case_insensitive_phf_map {
126192
maxlen
127193
};
128194

129-
static MAP: phf::Map<&'static str, $ValueType> = phf::phf_map! {
195+
static __MAP: ::phf::Map<&'static str, $ValueType> = ::phf::phf_map! {
130196
$(
131197
$key => $value,
132198
)*
@@ -142,12 +208,12 @@ macro_rules! ascii_case_insensitive_phf_map {
142208
impl $name {
143209
#[allow(dead_code)]
144210
fn entries() -> impl Iterator<Item = (&'static &'static str, &'static $ValueType)> {
145-
MAP.entries()
211+
__MAP.entries()
146212
}
147213

148214
fn get(input: &str) -> Option<&'static $ValueType> {
149215
$crate::_cssparser_internal_to_lowercase!(input, MAX_LENGTH => lowercase);
150-
MAP.get(lowercase?)
216+
__MAP.get(lowercase?)
151217
}
152218
}
153219
}

0 commit comments

Comments
 (0)