Skip to content

Commit 50ed753

Browse files
author
Martijn Groeneveldt
committed
Merge branch 'implement-std-error' of github.com:dutchmartin/rust-cssparser into implement-std-error
2 parents e3b07d8 + a1f9e6d commit 50ed753

File tree

2 files changed

+61
-55
lines changed

2 files changed

+61
-55
lines changed

src/macros.rs

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
use std::mem::MaybeUninit;
5+
// See docs of the `procedural-masquerade` crate.
6+
define_invoke_proc_macro!(cssparser_internal__invoke_proc_macro);
67

78
/// Expands to a `match` expression with string patterns,
89
/// matching case-insensitively in the ASCII range.
@@ -34,21 +35,18 @@ use std::mem::MaybeUninit;
3435
macro_rules! match_ignore_ascii_case {
3536
( $input:expr, $( $match_body:tt )* ) => {
3637
{
37-
// This dummy module works around the feature gate
38-
// `error[E0658]: procedural macros cannot be expanded to statements`
39-
// by forcing the macro to be in an item context
40-
// rather than expression/statement context,
41-
// even though the macro only expands to items.
42-
mod cssparser_internal {
43-
cssparser_internal__assert_ascii_lowercase__max_len! {
44-
match x { $( $match_body )* }
45-
}
38+
cssparser_internal__invoke_proc_macro! {
39+
cssparser_internal__assert_ascii_lowercase__max_len!( $( $match_body )* )
4640
}
47-
cssparser_internal__to_lowercase!($input, cssparser_internal::MAX_LENGTH => lowercase);
48-
// "A" is a short string that we know is different for every string pattern,
49-
// since we’ve verified that none of them include ASCII upper case letters.
50-
match lowercase.unwrap_or("A") {
51-
$( $match_body )*
41+
42+
{
43+
// MAX_LENGTH is generated by cssparser_internal__assert_ascii_lowercase__max_len
44+
cssparser_internal__to_lowercase!($input, MAX_LENGTH => lowercase);
45+
// "A" is a short string that we know is different for every string pattern,
46+
// since we’ve verified that none of them include ASCII upper case letters.
47+
match lowercase.unwrap_or("A") {
48+
$( $match_body )*
49+
}
5250
}
5351
}
5452
};
@@ -80,21 +78,23 @@ macro_rules! match_ignore_ascii_case {
8078
/// }
8179
#[macro_export]
8280
macro_rules! ascii_case_insensitive_phf_map {
83-
($name: ident -> $ValueType: ty = { $( $key: tt => $value: expr ),+ }) => {
84-
ascii_case_insensitive_phf_map!($name -> $ValueType = { $( $key => $value, )+ })
81+
($name: ident -> $ValueType: ty = { $( $key: expr => $value: expr ),* }) => {
82+
ascii_case_insensitive_phf_map!($name -> $ValueType = { $( $key => $value, )* })
8583
};
86-
($name: ident -> $ValueType: ty = { $( $key: tt => $value: expr, )+ }) => {
84+
($name: ident -> $ValueType: ty = { $( $key: expr => $value: expr, )* }) => {
8785
pub fn $name(input: &str) -> Option<&'static $ValueType> {
88-
// This dummy module works around a feature gate,
89-
// see comment on the similar module in `match_ignore_ascii_case!` above.
90-
mod cssparser_internal {
91-
use $crate::_internal__phf::{Map, phf_map};
92-
#[allow(unused)] use super::*;
93-
cssparser_internal__max_len!( $( $key )+ );
94-
cssparser_internal__phf_map!( $ValueType $( $key $value )+ );
86+
cssparser_internal__invoke_proc_macro! {
87+
cssparser_internal__phf_map!( ($ValueType) $( $key ($value) )+ )
88+
}
89+
90+
{
91+
cssparser_internal__invoke_proc_macro! {
92+
cssparser_internal__max_len!( $( $key )+ )
93+
}
94+
// MAX_LENGTH is generated by cssparser_internal__max_len
95+
cssparser_internal__to_lowercase!(input, MAX_LENGTH => lowercase);
96+
lowercase.and_then(|s| MAP.get(s))
9597
}
96-
cssparser_internal__to_lowercase!(input, cssparser_internal::MAX_LENGTH => lowercase);
97-
lowercase.and_then(|s| cssparser_internal::MAP.get(s))
9898
}
9999
}
100100
}
@@ -110,16 +110,38 @@ macro_rules! ascii_case_insensitive_phf_map {
110110
#[doc(hidden)]
111111
macro_rules! cssparser_internal__to_lowercase {
112112
($input: expr, $BUFFER_SIZE: expr => $output: ident) => {
113+
let mut buffer;
114+
// Safety: `buffer` is only used in `_internal__to_lowercase`,
115+
// which initializes with `copy_from_slice` the part of the buffer it uses,
116+
// before it uses it.
113117
#[allow(unsafe_code)]
114-
let mut buffer = unsafe {
115-
::std::mem::MaybeUninit::<[::std::mem::MaybeUninit<u8>; $BUFFER_SIZE]>::uninit()
116-
.assume_init()
117-
};
118+
let buffer = unsafe { cssparser_internal__uninit!(buffer, $BUFFER_SIZE) };
118119
let input: &str = $input;
119-
let $output = $crate::_internal__to_lowercase(&mut buffer, input);
120+
let $output = $crate::_internal__to_lowercase(buffer, input);
120121
};
121122
}
122123

124+
#[cfg(has_std__mem__MaybeUninit)]
125+
#[macro_export]
126+
#[doc(hidden)]
127+
macro_rules! cssparser_internal__uninit {
128+
($buffer: ident, $BUFFER_SIZE: expr) => {{
129+
$buffer = ::std::mem::MaybeUninit::<[u8; $BUFFER_SIZE]>::uninit();
130+
&mut *($buffer.as_mut_ptr())
131+
}};
132+
}
133+
134+
// FIXME: remove this when we require Rust 1.36
135+
#[cfg(not(has_std__mem__MaybeUninit))]
136+
#[macro_export]
137+
#[doc(hidden)]
138+
macro_rules! cssparser_internal__uninit {
139+
($buffer: ident, $BUFFER_SIZE: expr) => {{
140+
$buffer = ::std::mem::uninitialized::<[u8; $BUFFER_SIZE]>();
141+
&mut $buffer
142+
}};
143+
}
144+
123145
/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
124146
///
125147
/// **This function is not part of the public API. It can change or be removed between any verisons.**
@@ -128,28 +150,14 @@ macro_rules! cssparser_internal__to_lowercase {
128150
/// Otherwise, return `input` ASCII-lowercased, using `buffer` as temporary space if necessary.
129151
#[doc(hidden)]
130152
#[allow(non_snake_case)]
131-
pub fn _internal__to_lowercase<'a>(
132-
buffer: &'a mut [MaybeUninit<u8>],
133-
input: &'a str,
134-
) -> Option<&'a str> {
153+
pub fn _internal__to_lowercase<'a>(buffer: &'a mut [u8], input: &'a str) -> Option<&'a str> {
135154
if let Some(buffer) = buffer.get_mut(..input.len()) {
136155
if let Some(first_uppercase) = input.bytes().position(|byte| matches!(byte, b'A'..=b'Z')) {
137-
unsafe {
138-
// This cast doesn’t change the pointer’s validity
139-
// since `u8` has the same layout as `MaybeUninit<u8>`:
140-
let input_bytes = &*(input.as_bytes() as *const [u8] as *const [MaybeUninit<u8>]);
141-
142-
buffer.copy_from_slice(&*input_bytes);
143-
144-
// Same as above re layout, plus these bytes have been initialized:
145-
let buffer = &mut *(buffer as *mut [MaybeUninit<u8>] as *mut [u8]);
146-
147-
buffer[first_uppercase..].make_ascii_lowercase();
148-
// `buffer` was initialized to a copy of `input`
149-
// (which is `&str` so well-formed UTF-8)
150-
// then ASCII-lowercased (which preserves UTF-8 well-formedness):
151-
Some(::std::str::from_utf8_unchecked(buffer))
152-
}
156+
buffer.copy_from_slice(input.as_bytes());
157+
buffer[first_uppercase..].make_ascii_lowercase();
158+
// `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
159+
// then lowercased (which preserves UTF-8 well-formedness)
160+
unsafe { Some(::std::str::from_utf8_unchecked(buffer)) }
153161
} else {
154162
// Input is already lower-case
155163
Some(input)

src/rules_and_declarations.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,7 @@ where
268268
let start = self.input.state();
269269
// FIXME: remove intermediate variable when lifetimes are non-lexical
270270
let ident = match self.input.next_including_whitespace_and_comments() {
271-
Ok(&Token::WhiteSpace(_)) | Ok(&Token::Comment(_)) | Ok(&Token::Semicolon) => {
272-
continue
273-
}
271+
Ok(&Token::WhiteSpace(_)) | Ok(&Token::Comment(_)) | Ok(&Token::Semicolon) => continue,
274272
Ok(&Token::Ident(ref name)) => Ok(Ok(name.clone())),
275273
Ok(&Token::AtKeyword(ref name)) => Ok(Err(name.clone())),
276274
Ok(token) => Err(token.clone()),

0 commit comments

Comments
 (0)