From 1851ef9d3c393fd5d21e71fcc7e1020a96b6e9a3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 21 Aug 2026 13:52:54 +0200 Subject: [PATCH 1/4] Use a plain array of `MaybeUninit` Signed-off-by: Simon Sapin --- src/lib.rs | 4 +--- src/macros.rs | 12 +----------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 60d59f83..0f48c1f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,9 +70,7 @@ fn parse_border_spacing(_context: &ParserContext, input: &mut Parser) pub use crate::cow_rc_str::CowRcStr; pub use crate::from_bytes::{stylesheet_encoding, EncodingSupport}; #[doc(hidden)] -pub use crate::macros::{ - _cssparser_internal_create_uninit_array, _cssparser_internal_to_lowercase, -}; +pub use crate::macros::_cssparser_internal_to_lowercase; pub use crate::nth::parse_nth; pub use crate::parser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind}; pub use crate::parser::{Delimiter, Delimiters, Parser, ParserInput, ParserState}; diff --git a/src/macros.rs b/src/macros.rs index 81dc223a..2b9c88ad 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -217,16 +217,6 @@ macro_rules! ascii_case_insensitive_phf_map { } } -/// Create a new array of MaybeUninit items, in an uninitialized state. -#[inline(always)] -pub fn _cssparser_internal_create_uninit_array() -> [MaybeUninit; N] { - unsafe { - // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. - // See: https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html#method.uninit_array - MaybeUninit::<[MaybeUninit; N]>::uninit().assume_init() - } -} - /// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros. /// /// **This macro is not part of the public API. It can change or be removed between any versions.** @@ -238,7 +228,7 @@ pub fn _cssparser_internal_create_uninit_array() -> [MaybeUninit #[doc(hidden)] macro_rules! _cssparser_internal_to_lowercase { ($input: expr, $BUFFER_SIZE: expr => $output: ident) => { - let mut buffer = $crate::_cssparser_internal_create_uninit_array::<{ $BUFFER_SIZE }>(); + let mut buffer = [const { core::mem::MaybeUninit::::uninit() }; $BUFFER_SIZE]; let input: &str = $input; let $output = $crate::_cssparser_internal_to_lowercase(&mut buffer, input); }; From f1a79dd707590278aa50109e7b8b416f34f70210 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 21 Aug 2026 13:58:19 +0200 Subject: [PATCH 2/4] Inline _cssparser_internal_to_lowercase macro Signed-off-by: Simon Sapin --- src/macros.rs | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 2b9c88ad..941825c2 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -61,7 +61,8 @@ macro_rules! match_ignore_ascii_case { maxlen }; - $crate::_cssparser_internal_to_lowercase!($input, MAX_LENGTH => lowercase); + let mut buffer = [const { core::mem::MaybeUninit::::uninit() }; MAX_LENGTH]; + let lowercase = $crate::_cssparser_internal_to_lowercase(&mut buffer, $input); // "A" is a short string that we know is different for every string pattern, // since we’ve verified that none of them include ASCII upper case letters. match lowercase.unwrap_or("A") { @@ -210,30 +211,14 @@ macro_rules! ascii_case_insensitive_phf_map { } fn get(input: &str) -> Option<&'static $ValueType> { - $crate::_cssparser_internal_to_lowercase!(input, MAX_LENGTH => lowercase); - __MAP.get(lowercase?) + let mut buffer = [const { core::mem::MaybeUninit::::uninit() }; MAX_LENGTH]; + let lowercase = $crate::_cssparser_internal_to_lowercase(&mut buffer, input)?; + __MAP.get(lowercase) } } } } -/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros. -/// -/// **This macro is not part of the public API. It can change or be removed between any versions.** -/// -/// Define a local variable named `$output` -/// and assign it the result of calling `_cssparser_internal_to_lowercase` -/// with a stack-allocated buffer of length `$BUFFER_SIZE`. -#[macro_export] -#[doc(hidden)] -macro_rules! _cssparser_internal_to_lowercase { - ($input: expr, $BUFFER_SIZE: expr => $output: ident) => { - let mut buffer = [const { core::mem::MaybeUninit::::uninit() }; $BUFFER_SIZE]; - let input: &str = $input; - let $output = $crate::_cssparser_internal_to_lowercase(&mut buffer, input); - }; -} - /// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros. /// /// **This function is not part of the public API. It can change or be removed between any versions.** From f654114839780452aa435e4210c87112970e2420 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 21 Aug 2026 14:14:21 +0200 Subject: [PATCH 3/4] Prepare v0.38.0 Signed-off-by: Simon Sapin --- Cargo.toml | 2 +- color/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 25de0a19..414b4e03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cssparser" -version = "0.37.0" +version = "0.38.0" authors = ["Simon Sapin "] description = "Rust implementation of CSS Syntax Level 3" diff --git a/color/Cargo.toml b/color/Cargo.toml index 93e35b44..13153144 100644 --- a/color/Cargo.toml +++ b/color/Cargo.toml @@ -13,7 +13,7 @@ rust-version = "1.85" path = "lib.rs" [dependencies] -cssparser = { path = "..", version = "0.37", default-features = false } +cssparser = { path = "..", version = "0.38", default-features = false } serde = { version = "1.0", features = ["derive"], optional = true } [features] From 99a67bf7793bc1a669d4a4868e045c9f60226414 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 21 Aug 2026 16:41:12 +0200 Subject: [PATCH 4/4] Fix match_ignore_ascii_case! with a temporary borrow Signed-off-by: Simon Sapin --- src/macros.rs | 3 ++- src/tests.rs | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/macros.rs b/src/macros.rs index 941825c2..6038f32e 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -62,7 +62,8 @@ macro_rules! match_ignore_ascii_case { }; let mut buffer = [const { core::mem::MaybeUninit::::uninit() }; MAX_LENGTH]; - let lowercase = $crate::_cssparser_internal_to_lowercase(&mut buffer, $input); + let input: &str = $input; // Extend lifetime of temporaries + let lowercase = $crate::_cssparser_internal_to_lowercase(&mut buffer, input); // "A" is a short string that we know is different for every string pattern, // since we’ve verified that none of them include ASCII upper case letters. match lowercase.unwrap_or("A") { diff --git a/src/tests.rs b/src/tests.rs index 2f54d98b..21e8d856 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1150,6 +1150,17 @@ fn procedural_masquerade_whitespace() { } } +#[test] +fn test_match_ignore_ascii_case_with_temporary_borrow() { + fn generate_string() -> String { + "test".to_owned() + } + assert!(match_ignore_ascii_case! { &generate_string(), + "test" => true, + _ => false, + }); +} + #[test] fn parse_until_before_stops_at_delimiter_or_end_of_input() { // For all j and k, inputs[i].1[j] should parse the same as inputs[i].1[k]