diff --git a/src/parser.rs b/src/parser.rs index 82ec4b00..a7cab1f2 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -380,6 +380,10 @@ macro_rules! expect { } } +/// A list of arbitrary substitution functions. Should be lowercase ascii. +/// See https://drafts.csswg.org/css-values-5/#arbitrary-substitution +pub type ArbitrarySubstitutionFunctions<'a> = &'a [&'static str]; + impl<'i: 't, 't> Parser<'i, 't> { /// Create a new parser #[inline] @@ -546,19 +550,23 @@ impl<'i: 't, 't> Parser<'i, 't> { self.at_start_of = state.at_start_of; } - /// Start looking for `var()` / `env()` functions. (See the - /// `.seen_var_or_env_functions()` method.) + /// Start looking for arbitrary substitution functions like `var()` / `env()` functions. + /// (See the `.seen_arbitrary_substitution_functions()` method.) #[inline] - pub fn look_for_var_or_env_functions(&mut self) { - self.input.tokenizer.look_for_var_or_env_functions() + pub fn look_for_arbitrary_substitution_functions( + &mut self, + fns: ArbitrarySubstitutionFunctions<'i>, + ) { + self.input + .tokenizer + .look_for_arbitrary_substitution_functions(fns) } - /// Return whether a `var()` or `env()` function has been seen by the - /// tokenizer since either `look_for_var_or_env_functions` was called, and - /// stop looking. + /// Return whether a relevant function has been seen by the tokenizer since + /// `look_for_arbitrary_substitution_functions` was called, and stop looking. #[inline] - pub fn seen_var_or_env_functions(&mut self) -> bool { - self.input.tokenizer.seen_var_or_env_functions() + pub fn seen_arbitrary_substitution_functions(&mut self) -> bool { + self.input.tokenizer.seen_arbitrary_substitution_functions() } /// The old name of `try_parse`, which requires raw identifiers in the Rust 2018 edition. diff --git a/src/size_of_tests.rs b/src/size_of_tests.rs index edd2b439..7f4b85fa 100644 --- a/src/size_of_tests.rs +++ b/src/size_of_tests.rs @@ -42,8 +42,8 @@ size_of_test!(token, Token, 32); size_of_test!(std_cow_str, std::borrow::Cow<'static, str>, 24, 32); size_of_test!(cow_rc_str, CowRcStr, 16); -size_of_test!(tokenizer, crate::tokenizer::Tokenizer, 72); -size_of_test!(parser_input, crate::parser::ParserInput, 136); +size_of_test!(tokenizer, crate::tokenizer::Tokenizer, 96); +size_of_test!(parser_input, crate::parser::ParserInput, 160); size_of_test!(parser, crate::parser::Parser, 16); size_of_test!(source_position, crate::SourcePosition, 8); size_of_test!(parser_state, crate::ParserState, 24); diff --git a/src/tests.rs b/src/tests.rs index 339b5ac3..0c2acbe8 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -7,6 +7,9 @@ extern crate test; use serde_json::{json, Map, Value}; +#[cfg(feature = "bench")] +use crate::parser::ArbitrarySubstitutionFunctions; + #[cfg(feature = "bench")] use self::test::Bencher; @@ -795,20 +798,25 @@ fn delimiter_from_byte(b: &mut Bencher) { #[cfg(feature = "bench")] const BACKGROUND_IMAGE: &str = include_str!("big-data-url.css"); +#[cfg(feature = "bench")] +const ARBITRARY_SUBSTITUTION_FUNCTIONS: ArbitrarySubstitutionFunctions = &["var", "env"]; + #[cfg(feature = "bench")] #[bench] fn unquoted_url(b: &mut Bencher) { b.iter(|| { let mut input = ParserInput::new(BACKGROUND_IMAGE); let mut input = Parser::new(&mut input); - input.look_for_var_or_env_functions(); + input.look_for_arbitrary_substitution_functions(ARBITRARY_SUBSTITUTION_FUNCTIONS); let result = input.try_parse(|input| input.expect_url()); assert!(result.is_ok()); - input.seen_var_or_env_functions(); - (result.is_ok(), input.seen_var_or_env_functions()) + ( + result.is_ok(), + input.seen_arbitrary_substitution_functions(), + ) }) } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 68c1b10f..65562766 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -6,7 +6,7 @@ use self::Token::*; use crate::cow_rc_str::CowRcStr; -use crate::parser::ParserState; +use crate::parser::{ArbitrarySubstitutionFunctions, ParserState}; use std::char; use std::ops::Range; @@ -215,15 +215,15 @@ pub struct Tokenizer<'a> { /// of UTF-16 characters. current_line_start_position: usize, current_line_number: u32, - var_or_env_functions: SeenStatus, + arbitrary_substitution_functions: SeenStatus<'a>, source_map_url: Option<&'a str>, source_url: Option<&'a str>, } #[derive(Copy, Clone, PartialEq, Eq)] -enum SeenStatus { +enum SeenStatus<'a> { DontCare, - LookingForThem, + LookingForThem(ArbitrarySubstitutionFunctions<'a>), SeenAtLeastOne, } @@ -235,30 +235,33 @@ impl<'a> Tokenizer<'a> { position: 0, current_line_start_position: 0, current_line_number: 0, - var_or_env_functions: SeenStatus::DontCare, + arbitrary_substitution_functions: SeenStatus::DontCare, source_map_url: None, source_url: None, } } #[inline] - pub fn look_for_var_or_env_functions(&mut self) { - self.var_or_env_functions = SeenStatus::LookingForThem; + pub fn look_for_arbitrary_substitution_functions( + &mut self, + fns: ArbitrarySubstitutionFunctions<'a>, + ) { + self.arbitrary_substitution_functions = SeenStatus::LookingForThem(fns); } #[inline] - pub fn seen_var_or_env_functions(&mut self) -> bool { - let seen = self.var_or_env_functions == SeenStatus::SeenAtLeastOne; - self.var_or_env_functions = SeenStatus::DontCare; + pub fn seen_arbitrary_substitution_functions(&mut self) -> bool { + let seen = self.arbitrary_substitution_functions == SeenStatus::SeenAtLeastOne; + self.arbitrary_substitution_functions = SeenStatus::DontCare; seen } #[inline] pub fn see_function(&mut self, name: &str) { - if self.var_or_env_functions == SeenStatus::LookingForThem - && (name.eq_ignore_ascii_case("var") || name.eq_ignore_ascii_case("env")) - { - self.var_or_env_functions = SeenStatus::SeenAtLeastOne; + if let SeenStatus::LookingForThem(fns) = self.arbitrary_substitution_functions { + if fns.iter().any(|a| name.eq_ignore_ascii_case(a)) { + self.arbitrary_substitution_functions = SeenStatus::SeenAtLeastOne; + } } }