Skip to content

Commit c1e6008

Browse files
committed
Optimize
1 parent c111314 commit c1e6008

8 files changed

Lines changed: 73 additions & 53 deletions

File tree

Cargo.lock

Lines changed: 8 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libs/css/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }
99
[dependencies]
1010
phf = { version = "0.13", features = ["macros"] }
1111
serde = { version = "1.0.228", features = ["derive"] }
12-
regex = "1.12.3"
12+
regex-lite = "0.1"
1313
bimap = { version = "0.6.3" }
1414

1515
[dev-dependencies]

libs/css/src/constant.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashMap;
22

33
use phf::{phf_map, phf_set};
4-
use regex::Regex;
4+
use regex_lite::Regex;
55
use std::sync::LazyLock;
66

77
pub(super) static SELECTOR_ORDER_MAP: LazyLock<HashMap<String, u8>> = LazyLock::new(|| {

libs/css/src/lib.rs

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -200,48 +200,59 @@ pub fn keyframes_to_keyframes_name(keyframes: &str, filename: Option<&str>) -> S
200200
}
201201
}
202202

203+
/// ASCII lookup table for selector encoding. `None` means pass through (alphanumeric, `-`, `_`)
204+
/// or fall through to the Unicode escape path.
205+
const SELECTOR_ENCODE: [Option<&str>; 128] = {
206+
let mut table: [Option<&str>; 128] = [None; 128];
207+
table[b'&' as usize] = Some("_a_");
208+
table[b':' as usize] = Some("_c_");
209+
table[b'(' as usize] = Some("_lp_");
210+
table[b')' as usize] = Some("_rp_");
211+
table[b'[' as usize] = Some("_lb_");
212+
table[b']' as usize] = Some("_rb_");
213+
table[b'=' as usize] = Some("_eq_");
214+
table[b'>' as usize] = Some("_gt_");
215+
table[b'<' as usize] = Some("_lt_");
216+
table[b'~' as usize] = Some("_tl_");
217+
table[b'+' as usize] = Some("_pl_");
218+
table[b' ' as usize] = Some("_s_");
219+
table[b'*' as usize] = Some("_st_");
220+
table[b'.' as usize] = Some("_d_");
221+
table[b'#' as usize] = Some("_h_");
222+
table[b',' as usize] = Some("_cm_");
223+
table[b'"' as usize] = Some("_dq_");
224+
table[b'\'' as usize] = Some("_sq_");
225+
table[b'/' as usize] = Some("_sl_");
226+
table[b'\\' as usize] = Some("_bs_");
227+
table[b'%' as usize] = Some("_pc_");
228+
table[b'^' as usize] = Some("_cr_");
229+
table[b'$' as usize] = Some("_dl_");
230+
table[b'|' as usize] = Some("_pp_");
231+
table[b'@' as usize] = Some("_at_");
232+
table[b'!' as usize] = Some("_ex_");
233+
table[b'?' as usize] = Some("_qm_");
234+
table[b';' as usize] = Some("_sc_");
235+
table[b'{' as usize] = Some("_lc_");
236+
table[b'}' as usize] = Some("_rc_");
237+
table
238+
};
239+
203240
fn encode_selector(selector: &str) -> String {
204-
let mut result = String::with_capacity(selector.len() * 2);
241+
use std::fmt::Write;
242+
let mut result = String::with_capacity(selector.len() * 3);
205243
for c in selector.chars() {
206-
match c {
207-
'&' => result.push_str("_a_"),
208-
':' => result.push_str("_c_"),
209-
'(' => result.push_str("_lp_"),
210-
')' => result.push_str("_rp_"),
211-
'[' => result.push_str("_lb_"),
212-
']' => result.push_str("_rb_"),
213-
'=' => result.push_str("_eq_"),
214-
'>' => result.push_str("_gt_"),
215-
'<' => result.push_str("_lt_"),
216-
'~' => result.push_str("_tl_"),
217-
'+' => result.push_str("_pl_"),
218-
' ' => result.push_str("_s_"),
219-
'*' => result.push_str("_st_"),
220-
'.' => result.push_str("_d_"),
221-
'#' => result.push_str("_h_"),
222-
',' => result.push_str("_cm_"),
223-
'"' => result.push_str("_dq_"),
224-
'\'' => result.push_str("_sq_"),
225-
'/' => result.push_str("_sl_"),
226-
'\\' => result.push_str("_bs_"),
227-
'%' => result.push_str("_pc_"),
228-
'^' => result.push_str("_cr_"),
229-
'$' => result.push_str("_dl_"),
230-
'|' => result.push_str("_pp_"),
231-
'@' => result.push_str("_at_"),
232-
'!' => result.push_str("_ex_"),
233-
'?' => result.push_str("_qm_"),
234-
';' => result.push_str("_sc_"),
235-
'{' => result.push_str("_lc_"),
236-
'}' => result.push_str("_rc_"),
237-
'-' => result.push('-'),
238-
'_' => result.push('_'),
239-
_ if c.is_ascii_alphanumeric() => result.push(c),
240-
_ => {
241-
result.push_str("_u");
242-
result.push_str(&format!("{:04x}", c as u32));
243-
result.push('_');
244+
if c.is_ascii() {
245+
let byte = c as u8;
246+
if let Some(encoded) = SELECTOR_ENCODE[byte as usize] {
247+
result.push_str(encoded);
248+
} else if c.is_ascii_alphanumeric() || c == '-' || c == '_' {
249+
result.push(c);
250+
} else {
251+
// ASCII but not in table and not alphanumeric/-/_
252+
let _ = write!(result, "_u{:04x}_", c as u32);
244253
}
254+
} else {
255+
let _ = write!(result, "_u{:04x}_", c as u32);
245256
}
246257
}
247258
result

libs/css/src/optimize_value.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub fn optimize_value(value: &str) -> String {
4343
ret = s;
4444
}
4545
}
46-
let replaced = F_RGBA_RE.replace_all(&ret, |c: &regex::Captures| {
46+
let replaced = F_RGBA_RE.replace_all(&ret, |c: &regex_lite::Captures| {
4747
let r = c[1].parse::<i32>().unwrap();
4848
let g = c[2].parse::<i32>().unwrap();
4949
let b = c[3].parse::<i32>().unwrap();
@@ -59,7 +59,7 @@ pub fn optimize_value(value: &str) -> String {
5959
if let std::borrow::Cow::Owned(s) = replaced {
6060
ret = s;
6161
}
62-
let replaced = F_RGB_RE.replace_all(&ret, |c: &regex::Captures| {
62+
let replaced = F_RGB_RE.replace_all(&ret, |c: &regex_lite::Captures| {
6363
let r = c[1].parse::<i32>().unwrap();
6464
let g = c[2].parse::<i32>().unwrap();
6565
let b = c[3].parse::<i32>().unwrap();
@@ -69,7 +69,8 @@ pub fn optimize_value(value: &str) -> String {
6969
ret = s;
7070
}
7171
if ret.contains('#') {
72-
let replaced = COLOR_HASH.replace_all(&ret, |c: &regex::Captures| optimize_color(&c[1]));
72+
let replaced =
73+
COLOR_HASH.replace_all(&ret, |c: &regex_lite::Captures| optimize_color(&c[1]));
7374
if let std::borrow::Cow::Owned(s) = replaced {
7475
ret = s;
7576
}

libs/sheet/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition = "2024"
77
css = { path = "../css" }
88
serde = { version = "1.0.228", features = ["derive"] }
99
serde_json = "1.0.149"
10-
regex = "1.12.3"
10+
regex-lite = "0.1"
1111
extractor = { path = "../extractor" }
1212

1313
[dev-dependencies]

libs/sheet/benches/my_benchmark.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use criterion::{Criterion, criterion_group, criterion_main};
2-
use regex::Regex;
2+
use regex_lite::Regex;
33
use std::hint::black_box;
44
use std::sync::LazyLock;
55

@@ -8,7 +8,7 @@ static VAR_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\$\w+").unwrap())
88
fn convert_theme_variable_value_a(value: &str) -> String {
99
if value.contains("$") {
1010
VAR_RE
11-
.replace_all(value, |caps: &regex::Captures| {
11+
.replace_all(value, |caps: &regex_lite::Captures| {
1212
format!("var(--{})", &caps[0][1..])
1313
})
1414
.to_string()
@@ -19,7 +19,7 @@ fn convert_theme_variable_value_a(value: &str) -> String {
1919

2020
fn convert_theme_variable_value_b(value: &str) -> String {
2121
VAR_RE
22-
.replace_all(value, |caps: &regex::Captures| {
22+
.replace_all(value, |caps: &regex_lite::Captures| {
2323
format!("var(--{})", &caps[0][1..])
2424
})
2525
.to_string()

libs/sheet/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use css::{
88
use extractor::extract_style::ExtractStyleProperty;
99
use extractor::extract_style::extract_style_value::ExtractStyleValue;
1010
use extractor::extract_style::style_property::StyleProperty;
11-
use regex::Regex;
11+
use regex_lite::Regex;
1212
use serde::de::Error;
1313
use serde::{Deserialize, Deserializer, Serialize};
1414
use std::borrow::Cow;
@@ -112,7 +112,7 @@ fn convert_theme_variable_value(value: &str) -> Cow<'_, str> {
112112
if value.contains('$') {
113113
Cow::Owned(
114114
VAR_RE
115-
.replace_all(value, |caps: &regex::Captures| {
115+
.replace_all(value, |caps: &regex_lite::Captures| {
116116
format!("var(--{})", &caps[0][1..].replace('.', "-"))
117117
})
118118
.into_owned(),
@@ -488,7 +488,9 @@ impl StyleSheet {
488488
map: &BTreeMap<u8, HashSet<StyleSheetProperty>>,
489489
layered_styles: &mut BTreeMap<String, Vec<(String, String, String)>>, // layer -> Vec<(selector, property, value)>
490490
) -> String {
491-
let mut current_css = String::new();
491+
// Estimate ~64 bytes per property for pre-allocation
492+
let prop_count: usize = map.values().map(|s| s.len()).sum();
493+
let mut current_css = String::with_capacity(prop_count * 64);
492494
for (level, props) in map.iter() {
493495
let (mut global_props, rest): (Vec<_>, Vec<_>) = props
494496
.iter()

0 commit comments

Comments
 (0)