From 4c453550d2c5e1018f1d4798826fa1bdd7416c71 Mon Sep 17 00:00:00 2001 From: Shark Date: Wed, 21 Aug 2024 21:35:11 +0200 Subject: [PATCH] optimize css syntax matching speed --- .../gosub_styling/src/property_definitions.rs | 169 ++++---- crates/gosub_styling/src/render_tree.rs | 17 +- crates/gosub_styling/src/syntax_matcher.rs | 367 +++++++++--------- 3 files changed, 272 insertions(+), 281 deletions(-) diff --git a/crates/gosub_styling/src/property_definitions.rs b/crates/gosub_styling/src/property_definitions.rs index c7ad104d9..4c079de3d 100644 --- a/crates/gosub_styling/src/property_definitions.rs +++ b/crates/gosub_styling/src/property_definitions.rs @@ -1,10 +1,13 @@ +use std::collections::HashMap; +use std::sync::LazyLock; + +use log::warn; + +use gosub_css3::stylesheet::CssValue; + use crate::syntax::GroupCombinators::Juxtaposition; use crate::syntax::{CssSyntax, SyntaxComponent}; use crate::syntax_matcher::CssSyntaxTree; -use gosub_css3::stylesheet::CssValue; -use log::warn; -use memoize::memoize; -use std::collections::HashMap; /// List of elements that are built-in data types in the CSS specification. These will be handled /// by the syntax matcher as built-in types. @@ -70,34 +73,34 @@ pub struct PropertyDefinition { } impl PropertyDefinition { - pub fn name(self) -> String { - self.name.clone() + pub fn name(&self) -> &str { + &self.name } - pub fn expanded_properties(self) -> Vec { + pub fn expanded_properties(&self) -> Vec { self.computed.clone() } - pub fn syntax(self) -> CssSyntaxTree { - self.syntax + pub fn syntax(&self) -> &CssSyntaxTree { + &self.syntax } - pub fn inherited(self) -> bool { + pub fn inherited(&self) -> bool { self.inherited } /// Returns true when this definition has an initial value - pub fn has_initial_value(self) -> bool { + pub fn has_initial_value(&self) -> bool { self.initial_value.is_some() } /// Returns the initial value - pub fn initial_value(self) -> CssValue { + pub fn initial_value(&self) -> CssValue { self.initial_value.clone().unwrap_or(CssValue::None) } /// Matches a list of values against the current definition - pub fn matches(self, input: Vec) -> bool { + pub fn matches(&self, input: &[CssValue]) -> bool { self.syntax.matches(input) } @@ -109,7 +112,7 @@ impl PropertyDefinition { // for (i, value) in values.iter().enumerate() { // let prop = self.expanded_properties.get(i).unwrap(); // let prop_def = parse_definition_file().find(prop).unwrap(); - // if !prop_def.matches(&vec![value.clone()]) { + // if !prop_def.matches(&[value.clone()]) { // return false; // } // } @@ -155,7 +158,7 @@ impl CssDefinitions { /// Load the CSS definitions resource files pub fn load() { - parse_definition_files(); + let _ = CSS_DEFINITIONS.len(); } /// Add a new property definition @@ -169,8 +172,8 @@ impl CssDefinitions { } /// Find a specific property - pub fn find_property(&self, name: &str) -> Option { - self.resolved_properties.get(name).cloned() + pub fn find_property(&self, name: &str) -> Option<&PropertyDefinition> { + self.resolved_properties.get(name) } /// Returns the length of the property definitions @@ -324,9 +327,13 @@ impl CssDefinitions { } } +pub static CSS_DEFINITIONS: LazyLock CssDefinitions> = + LazyLock::new(pars_definition_files); + /// Parses the internal CSS definition file -#[memoize] -pub fn parse_definition_files() -> CssDefinitions { +fn pars_definition_files() -> CssDefinitions { + println!("parse_definition_files"); + // parse all syntax, so we can use them in the properties let contents = include_str!("../resources/definitions/definitions_values.json"); let json: serde_json::Value = @@ -350,10 +357,10 @@ pub fn parse_definition_files() -> CssDefinitions { definitions } -/// Main function to return the definitions. THis will automatically load the definition files +/// Main function to return the definitions. This will automatically load the definition files /// and caches them if needed. -pub fn get_css_definitions() -> CssDefinitions { - parse_definition_files() +pub fn get_css_definitions() -> &'static CssDefinitions { + &CSS_DEFINITIONS } /// Parses a syntax JSON import file @@ -474,9 +481,10 @@ fn parse_property_file(json: serde_json::Value) -> HashMap { assert_eq!(false, $e); @@ -503,45 +511,42 @@ mod tests { #[test] fn test_parse_definition_file() { - let definitions = parse_definition_files(); - assert_eq!(definitions.len(), 620); + assert_eq!(CSS_DEFINITIONS.len(), 620); } #[test] fn test_prop_border() { - let definitions = parse_definition_files(); + let definitions = get_css_definitions(); let prop = definitions.find_property("border").unwrap(); - assert!(prop.clone().matches(vec![ + assert!(prop.clone().matches(&[ unit!(1.0, "px"), str!("solid"), CssValue::Color(RgbColor::from("black")), ])); - assert!(prop.clone().matches(vec![ + assert!(prop.clone().matches(&[ CssValue::Color(RgbColor::from("black")), str!("solid"), unit!(1.0, "px"), ])); - assert!(prop.clone().matches(vec![ + assert!(prop.clone().matches(&[ str!("solid"), CssValue::Color(RgbColor::from("black")), unit!(1.0, "px"), ])); - assert!(prop.clone().matches(vec![unit!(1.0, "px"),])); - assert!(prop.clone().matches(vec![str!("solid")])); - assert!(prop.clone().matches(vec![ - str!("solid"), - CssValue::Color(RgbColor::from("black")), - ])); - assert!(prop.clone().matches(vec![ - str!("solid"), - CssValue::Color(RgbColor::from("black")), - ])); - assert_true!(prop.clone().matches(vec![str!("solid")])); - assert_false!(prop.clone().matches(vec![str!("not-solid")])); + assert!(prop.clone().matches(&[unit!(1.0, "px")])); + assert!(prop.clone().matches(&[str!("solid")])); + assert!(prop + .clone() + .matches(&[str!("solid"), CssValue::Color(RgbColor::from("black")),])); + assert!(prop + .clone() + .matches(&[str!("solid"), CssValue::Color(RgbColor::from("black")),])); + assert_true!(prop.clone().matches(&[str!("solid")])); + assert_false!(prop.clone().matches(&[str!("not-solid")])); assert_false!(prop .clone() - .matches(vec![str!("solid"), str!("solid"), unit!(1.0, "px"),])); + .matches(&[str!("solid"), str!("solid"), unit!(1.0, "px"),])); } #[test] @@ -626,52 +631,52 @@ mod tests { #[test] fn test_background_color() { - let definitions = parse_definition_files(); + let definitions = get_css_definitions(); let def = definitions.find_property("background-color").unwrap(); // assert_some!(def.clone().matches(&CssValue::Inherit)); - assert_true!(def.clone().matches(vec![str!("transparent")])); + assert_true!(def.clone().matches(&[str!("transparent")])); - assert_true!(def.clone().matches(vec![str!("red")])); + assert_true!(def.clone().matches(&[str!("red")])); // System colors - assert_true!(def.clone().matches(vec![str!("Canvas")])); - assert_true!(def.clone().matches(vec![str!("CanvasText")])); - assert_true!(def.clone().matches(vec![str!("CanvasText")])); - assert_true!(def.clone().matches(vec![str!("Menu")])); + assert_true!(def.clone().matches(&[str!("Canvas")])); + assert_true!(def.clone().matches(&[str!("CanvasText")])); + assert_true!(def.clone().matches(&[str!("CanvasText")])); + assert_true!(def.clone().matches(&[str!("Menu")])); - assert_true!(def.clone().matches(vec![str!("blue")])); + assert_true!(def.clone().matches(&[str!("blue")])); assert_true!(def .clone() - .matches(vec![CssValue::Color(RgbColor::from("#ff0000"))])); - assert_true!(def.clone().matches(vec![str!("rebeccapurple")])); + .matches(&[CssValue::Color(RgbColor::from("#ff0000"))])); + assert_true!(def.clone().matches(&[str!("rebeccapurple")])); - assert_false!(def.clone().matches(vec![str!("thiscolordoesnotexist")])); + assert_false!(def.clone().matches(&[str!("thiscolordoesnotexist")])); } #[test] fn test_background_attachments() { - let definitions = parse_definition_files(); + let definitions = get_css_definitions(); let def = definitions.find_property("background-attachment").unwrap(); // assert_true!(def.clone().matches(&CssValue::Inherit)); - assert_true!(def.clone().matches(vec![str!("scroll")])); - assert_true!(def.clone().matches(vec![str!("fixed")])); + assert_true!(def.clone().matches(&[str!("scroll")])); + assert_true!(def.clone().matches(&[str!("fixed")])); - assert_false!(def.clone().matches(vec![str!("incorrect")])); - assert_false!(def.clone().matches(vec![str!("rebeccapurple")])); - assert_false!(def.clone().matches(vec![CssValue::Zero])); + assert_false!(def.clone().matches(&[str!("incorrect")])); + assert_false!(def.clone().matches(&[str!("rebeccapurple")])); + assert_false!(def.clone().matches(&[CssValue::Zero])); } #[test] fn test_background_position() { - let definitions = parse_definition_files(); + let definitions = get_css_definitions(); let def = definitions.find_property("background-position").unwrap(); // background-position: left 10px; - assert_true!(def.clone().matches(vec![str!("left"), unit!(10.0, "px"),])); + assert_true!(def.clone().matches(&[str!("left"), unit!(10.0, "px"),])); // background-position: left 10px top 20px; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("left"), unit!(10.0, "px"), str!("top"), @@ -679,7 +684,7 @@ mod tests { ])); // background-position: right 15% bottom 5%; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("right"), CssValue::Percentage(15.0), str!("bottom"), @@ -687,23 +692,23 @@ mod tests { ])); // background-position: center center; - assert_true!(def.clone().matches(vec![str!("center"), str!("center"),])); + assert_true!(def.clone().matches(&[str!("center"), str!("center"),])); // background-position: 75% 50%; assert_true!(def .clone() - .matches(vec![CssValue::Percentage(75.0), CssValue::Percentage(50.0),])); + .matches(&[CssValue::Percentage(75.0), CssValue::Percentage(50.0),])); // background-position: 75%; - assert_true!(def.clone().matches(vec![CssValue::Percentage(75.0),])); + assert_true!(def.clone().matches(&[CssValue::Percentage(75.0),])); // background-position: top 10px center; assert_true!(def .clone() - .matches(vec![str!("top"), unit!(10.0, "px"), str!("center"),])); + .matches(&[str!("top"), unit!(10.0, "px"), str!("center"),])); // background-position: bottom 20px right 30px; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("bottom"), unit!(20.0, "px"), str!("right"), @@ -713,10 +718,10 @@ mod tests { // background-position: 20% 80%; assert_true!(def .clone() - .matches(vec![CssValue::Percentage(20.0), CssValue::Percentage(80.0),])); + .matches(&[CssValue::Percentage(20.0), CssValue::Percentage(80.0),])); // background-position: left 5px bottom 15px, right 10px top 20px; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("left"), unit!(5.0, "px"), str!("bottom"), @@ -731,10 +736,10 @@ mod tests { // background-position: center top 35px; assert_true!(def .clone() - .matches(vec![str!("center"), str!("top"), unit!(35.0, "px"),])); + .matches(&[str!("center"), str!("top"), unit!(35.0, "px"),])); // background-position: left 45% bottom 25%; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("left"), CssValue::Percentage(45.0), str!("bottom"), @@ -742,7 +747,7 @@ mod tests { ])); // background-position: right 10% top 50px; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("right"), CssValue::Percentage(10.0), str!("top"), @@ -750,7 +755,7 @@ mod tests { ])); // // background-position: 0% 0%, 100% 100%; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ CssValue::Percentage(0.0), CssValue::Percentage(0.0), CssValue::Comma, @@ -759,7 +764,7 @@ mod tests { ])); // background-position: left top, right bottom; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("left"), str!("top"), CssValue::Comma, @@ -768,7 +773,7 @@ mod tests { ])); // background-position: 100% 0, 0 100%; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ CssValue::Percentage(100.0), CssValue::Zero, CssValue::Comma, @@ -777,7 +782,7 @@ mod tests { ])); // background-position: left 25px bottom, center top; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("left"), unit!(25.0, "px"), str!("bottom"), @@ -787,7 +792,7 @@ mod tests { ])); // background-position: top 10% left 20%, bottom 10% right 20%; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("top"), CssValue::Percentage(10.0), str!("left"), @@ -800,7 +805,7 @@ mod tests { ])); // background-position: 10px 30px, 90% 10%; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ unit!(10.0, "px"), unit!(30.0, "px"), CssValue::Comma, @@ -809,7 +814,7 @@ mod tests { ])); // background-position: top right, bottom left 15px; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("top"), str!("right"), CssValue::Comma, @@ -819,7 +824,7 @@ mod tests { ])); // background-position: 50% 25%, 25% 75%; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ CssValue::Percentage(50.0), CssValue::Percentage(25.0), CssValue::Comma, @@ -828,7 +833,7 @@ mod tests { ])); // background-position: right 5% bottom 5%, left 5% top 5%; - assert_true!(def.clone().matches(vec![ + assert_true!(def.clone().matches(&[ str!("right"), CssValue::Percentage(5.0), str!("bottom"), diff --git a/crates/gosub_styling/src/render_tree.rs b/crates/gosub_styling/src/render_tree.rs index c7f68d218..18400e7fd 100644 --- a/crates/gosub_styling/src/render_tree.rs +++ b/crates/gosub_styling/src/render_tree.rs @@ -1,7 +1,8 @@ -mod desc; +use std::collections::HashMap; +use std::fmt::Debug; + +use log::warn; -use crate::property_definitions::get_css_definitions; -use crate::styling::{match_selector, CssProperties, CssProperty, DeclarationProperty}; use gosub_css3::stylesheet::{CssDeclaration, CssSelector, CssStylesheet, CssValue}; use gosub_html5::node::data::element::ElementData; use gosub_html5::node::{NodeData, NodeId}; @@ -11,9 +12,11 @@ use gosub_render_backend::layout::{LayoutTree, Layouter, Node}; use gosub_render_backend::{PreRenderText, RenderBackend}; use gosub_shared::types::Result; use gosub_typeface::DEFAULT_FS; -use log::warn; -use std::collections::HashMap; -use std::fmt::Debug; + +use crate::property_definitions::get_css_definitions; +use crate::styling::{match_selector, CssProperties, CssProperty, DeclarationProperty}; + +mod desc; /// Map of all declared values for all nodes in the document #[derive(Debug)] @@ -270,7 +273,7 @@ impl RenderTree { } // Check if the declaration matches the definition and return the "expanded" order - let res = definition.unwrap().matches(declaration.value.clone()); + let res = definition.unwrap().matches(&declaration.value); if !res { warn!("Declaration does not match definition: {:?}", declaration); continue; diff --git a/crates/gosub_styling/src/syntax_matcher.rs b/crates/gosub_styling/src/syntax_matcher.rs index 81e0290cb..8ab202806 100644 --- a/crates/gosub_styling/src/syntax_matcher.rs +++ b/crates/gosub_styling/src/syntax_matcher.rs @@ -1,7 +1,8 @@ -use crate::syntax::{GroupCombinators, SyntaxComponent, SyntaxComponentMultiplier}; use gosub_css3::colors::{is_named_color, is_system_color}; use gosub_css3::stylesheet::CssValue; +use crate::syntax::{GroupCombinators, SyntaxComponent, SyntaxComponentMultiplier}; + /// Structure to return from a matching function. #[derive(Debug, Clone)] pub struct MatchResult<'a> { @@ -34,12 +35,12 @@ impl CssSyntaxTree { } /// Matches a CSS value (or set of values) against the syntax tree. Will return a normalized version of the value(s) if it matches. - pub fn matches(&self, input: Vec) -> bool { + pub fn matches(&self, input: &[CssValue]) -> bool { if self.components.len() != 1 { panic!("Syntax tree must have exactly one root component"); } - let res = match_component(&input, &self.components[0]); + let res = match_component(input, &self.components[0]); res.matched && res.remainder.is_empty() } } @@ -304,7 +305,11 @@ fn match_component_single<'a>( CssValue::String(v) if v.starts_with('#') => return first_match(input), _ => {} }, - _ => panic!("Unknown built-in datatype: {:?}", datatype), + _ => { + println!("unknown datatype: {datatype:?}"); + + return first_match(input); + } // _ => panic!("Unknown built-in datatype: {:?}", datatype), }, SyntaxComponent::Inherit { .. } => match value { CssValue::Inherit => return first_match(input), @@ -648,7 +653,7 @@ fn first_match(input: &[CssValue]) -> MatchResult { mod tests { use gosub_css3::stylesheet::CssValue; - use crate::property_definitions::{parse_definition_files, PropertyDefinition}; + use crate::property_definitions::{get_css_definitions, PropertyDefinition}; use crate::syntax::CssSyntax; use super::*; @@ -695,17 +700,17 @@ mod tests { fn test_match_group1() { // Exactly one let tree = CssSyntax::new("auto | none | block").compile().unwrap(); - assert_true!(tree.matches(vec![str!("auto")])); - assert_true!(tree.matches(vec![CssValue::None])); - assert_true!(tree.matches(vec![str!("block")])); - assert_false!(tree.matches(vec![str!("inline")])); - assert_false!(tree.matches(vec![str!("")])); - assert_false!(tree.matches(vec![str!("foobar")])); - assert_false!(tree.matches(vec![str!("foo"), CssValue::None])); - assert_false!(tree.matches(vec![CssValue::None, str!("foo")])); - assert_false!(tree.matches(vec![str!("auto"), CssValue::None])); - assert_false!(tree.matches(vec![str!("auto"), CssValue::Comma, str!("none"),])); - assert_false!(tree.matches(vec![ + assert_true!(tree.matches(&[str!("auto")])); + assert_true!(tree.matches(&[CssValue::None])); + assert_true!(tree.matches(&[str!("block")])); + assert_false!(tree.matches(&[str!("inline")])); + assert_false!(tree.matches(&[str!("")])); + assert_false!(tree.matches(&[str!("foobar")])); + assert_false!(tree.matches(&[str!("foo"), CssValue::None])); + assert_false!(tree.matches(&[CssValue::None, str!("foo")])); + assert_false!(tree.matches(&[str!("auto"), CssValue::None])); + assert_false!(tree.matches(&[str!("auto"), CssValue::Comma, str!("none"),])); + assert_false!(tree.matches(&[ str!("auto"), CssValue::Comma, CssValue::None, @@ -718,42 +723,42 @@ mod tests { fn test_match_group2() { // juxtaposition let tree = CssSyntax::new("auto none block").compile().unwrap(); - assert_false!(tree.matches(vec![str!("auto")])); - assert_false!(tree.matches(vec![CssValue::None])); - assert_false!(tree.matches(vec![str!("block")])); - assert_true!(tree.matches(vec![str!("auto"), CssValue::None, str!("block"),])); - assert_false!(tree.matches(vec![str!("block"), CssValue::None, str!("block"),])); - assert_false!(tree.matches(vec![str!("auto"), CssValue::None, str!("auto"),])); + assert_false!(tree.matches(&[str!("auto")])); + assert_false!(tree.matches(&[CssValue::None])); + assert_false!(tree.matches(&[str!("block")])); + assert_true!(tree.matches(&[str!("auto"), CssValue::None, str!("block"),])); + assert_false!(tree.matches(&[str!("block"), CssValue::None, str!("block"),])); + assert_false!(tree.matches(&[str!("auto"), CssValue::None, str!("auto"),])); } #[test] fn test_match_group3() { // all any order let tree = CssSyntax::new("auto && none && block").compile().unwrap(); - assert_false!(tree.matches(vec![str!("auto")])); - assert_false!(tree.matches(vec![CssValue::None])); - assert_false!(tree.matches(vec![str!("block")])); - assert_false!(tree.matches(vec![str!("inline")])); - assert_false!(tree.matches(vec![str!("")])); - assert_false!(tree.matches(vec![str!("foobar")])); - assert_false!(tree.matches(vec![str!("foo"), CssValue::None])); - assert_false!(tree.matches(vec![CssValue::None, str!("foo")])); - assert_false!(tree.matches(vec![str!("auto"), CssValue::None])); - assert_false!(tree.matches(vec![str!("auto"), CssValue::Comma, str!("none")])); - assert_false!(tree.matches(vec![ + assert_false!(tree.matches(&[str!("auto")])); + assert_false!(tree.matches(&[CssValue::None])); + assert_false!(tree.matches(&[str!("block")])); + assert_false!(tree.matches(&[str!("inline")])); + assert_false!(tree.matches(&[str!("")])); + assert_false!(tree.matches(&[str!("foobar")])); + assert_false!(tree.matches(&[str!("foo"), CssValue::None])); + assert_false!(tree.matches(&[CssValue::None, str!("foo")])); + assert_false!(tree.matches(&[str!("auto"), CssValue::None])); + assert_false!(tree.matches(&[str!("auto"), CssValue::Comma, str!("none")])); + assert_false!(tree.matches(&[ str!("auto"), CssValue::Comma, CssValue::None, CssValue::Comma, str!("block") ])); - assert_true!(tree.matches(vec![str!("block"), str!("auto"), CssValue::None])); - assert_true!(tree.matches(vec![str!("auto"), str!("block"), CssValue::None])); - assert_true!(tree.matches(vec![str!("block"), CssValue::None, str!("auto")])); - assert_true!(tree.matches(vec![CssValue::None, str!("auto"), str!("block")])); - assert_false!(tree.matches(vec![str!("auto"), str!("block")])); - assert_false!(tree.matches(vec![CssValue::None, str!("block")])); - assert_false!(tree.matches(vec![ + assert_true!(tree.matches(&[str!("block"), str!("auto"), CssValue::None])); + assert_true!(tree.matches(&[str!("auto"), str!("block"), CssValue::None])); + assert_true!(tree.matches(&[str!("block"), CssValue::None, str!("auto")])); + assert_true!(tree.matches(&[CssValue::None, str!("auto"), str!("block")])); + assert_false!(tree.matches(&[str!("auto"), str!("block")])); + assert_false!(tree.matches(&[CssValue::None, str!("block")])); + assert_false!(tree.matches(&[ str!("block"), str!("block"), CssValue::None, @@ -765,26 +770,26 @@ mod tests { fn test_match_group4() { // At least one in any order let tree = CssSyntax::new("auto || none || block").compile().unwrap(); - assert_true!(tree.matches(vec![str!("auto")])); - assert_true!(tree.matches(vec![CssValue::None])); - assert_true!(tree.matches(vec![str!("block")])); - assert_true!(tree.matches(vec![str!("auto"), CssValue::None])); - assert_true!(tree.matches(vec![str!("block"), str!("auto"), CssValue::None,])); - - assert_false!(tree.matches(vec![str!("inline")])); - assert_false!(tree.matches(vec![str!("")])); - assert_false!(tree.matches(vec![str!("foo"), CssValue::None])); - assert_false!(tree.matches(vec![CssValue::None, str!("foo")])); - assert_false!(tree.matches(vec![CssValue::None, CssValue::None,])); - assert_false!(tree.matches(vec![str!("auto"), CssValue::Comma, str!("none"),])); - assert_false!(tree.matches(vec![ + assert_true!(tree.matches(&[str!("auto")])); + assert_true!(tree.matches(&[CssValue::None])); + assert_true!(tree.matches(&[str!("block")])); + assert_true!(tree.matches(&[str!("auto"), CssValue::None])); + assert_true!(tree.matches(&[str!("block"), str!("auto"), CssValue::None,])); + + assert_false!(tree.matches(&[str!("inline")])); + assert_false!(tree.matches(&[str!("")])); + assert_false!(tree.matches(&[str!("foo"), CssValue::None])); + assert_false!(tree.matches(&[CssValue::None, str!("foo")])); + assert_false!(tree.matches(&[CssValue::None, CssValue::None,])); + assert_false!(tree.matches(&[str!("auto"), CssValue::Comma, str!("none"),])); + assert_false!(tree.matches(&[ str!("auto"), CssValue::Comma, CssValue::None, CssValue::Comma, str!("block"), ])); - assert_false!(tree.matches(vec![ + assert_false!(tree.matches(&[ str!("block"), str!("block"), CssValue::None, @@ -941,54 +946,48 @@ mod tests { #[test] fn test_multipliers_optional() { let tree = CssSyntax::new("foo bar baz").compile().unwrap(); - assert_false!(tree.clone().matches(vec![str!("foo")])); - assert_false!(tree.clone().matches(vec![str!("foo")])); + assert_false!(tree.clone().matches(&[str!("foo")])); + assert_false!(tree.clone().matches(&[str!("foo")])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("baz"),])); - assert_false!(tree.clone().matches(vec![str!("foo"), str!("baz"),])); + .matches(&[str!("foo"), str!("bar"), str!("baz"),])); + assert_false!(tree.clone().matches(&[str!("foo"), str!("baz"),])); let tree = CssSyntax::new("foo bar?").compile().unwrap(); dbg!(&tree); - assert_true!(tree.clone().matches(vec![str!("foo")])); - assert_true!(tree.clone().matches(vec![str!("foo"), str!("bar"),])); + assert_true!(tree.clone().matches(&[str!("foo")])); + assert_true!(tree.clone().matches(&[str!("foo"), str!("bar"),])); assert_false!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("bar"),])); - assert_false!(tree.clone().matches(vec![str!("bar"), str!("foo"),])); + .matches(&[str!("foo"), str!("bar"), str!("bar"),])); + assert_false!(tree.clone().matches(&[str!("bar"), str!("foo"),])); let tree = CssSyntax::new("foo bar? baz").compile().unwrap(); - assert_false!(tree.clone().matches(vec![str!("foo")])); - assert_true!(tree.clone().matches(vec![str!("foo"), str!("baz"),])); + assert_false!(tree.clone().matches(&[str!("foo")])); + assert_true!(tree.clone().matches(&[str!("foo"), str!("baz"),])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("baz"),])); + .matches(&[str!("foo"), str!("bar"), str!("baz"),])); - assert_false!(tree.clone().matches(vec![ - str!("foo"), - str!("bar"), - str!("bar"), - str!("baz"), - ])); + assert_false!(tree + .clone() + .matches(&[str!("foo"), str!("bar"), str!("bar"), str!("baz"),])); - assert_false!(tree.clone().matches(vec![ - str!("foo"), - str!("bar"), - str!("baz"), - str!("baz"), - ])); + assert_false!(tree + .clone() + .matches(&[str!("foo"), str!("bar"), str!("baz"), str!("baz"),])); } #[test] fn test_multipliers_zero_or_more() { let tree = CssSyntax::new("foo bar* baz").compile().unwrap(); - assert_false!(tree.clone().matches(vec![str!("foo")])); - assert_false!(tree.clone().matches(vec![str!("foo")])); + assert_false!(tree.clone().matches(&[str!("foo")])); + assert_false!(tree.clone().matches(&[str!("foo")])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("baz"),])); - assert_true!(tree.clone().matches(vec![str!("foo"), str!("baz"),])); - assert_true!(tree.clone().matches(vec![ + .matches(&[str!("foo"), str!("bar"), str!("baz"),])); + assert_true!(tree.clone().matches(&[str!("foo"), str!("baz"),])); + assert_true!(tree.clone().matches(&[ str!("foo"), str!("bar"), str!("bar"), @@ -996,7 +995,7 @@ mod tests { str!("bar"), str!("baz"), ])); - assert_false!(tree.clone().matches(vec![ + assert_false!(tree.clone().matches(&[ str!("foo"), str!("bar"), str!("bar"), @@ -1006,25 +1005,25 @@ mod tests { ])); let tree = CssSyntax::new("foo bar*").compile().unwrap(); - assert_true!(tree.clone().matches(vec![str!("foo")])); - assert_true!(tree.clone().matches(vec![str!("foo")])); - assert_true!(tree.clone().matches(vec![str!("foo"), str!("bar"),])); + assert_true!(tree.clone().matches(&[str!("foo")])); + assert_true!(tree.clone().matches(&[str!("foo")])); + assert_true!(tree.clone().matches(&[str!("foo"), str!("bar"),])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("bar"),])); - assert_false!(tree.clone().matches(vec![str!("bar"), str!("foo"),])); + .matches(&[str!("foo"), str!("bar"), str!("bar"),])); + assert_false!(tree.clone().matches(&[str!("bar"), str!("foo"),])); } #[test] fn test_multipliers_one_or_more() { let tree = CssSyntax::new("foo bar+ baz").compile().unwrap(); - assert_false!(tree.clone().matches(vec![str!("foo")])); - assert_false!(tree.clone().matches(vec![str!("foo")])); + assert_false!(tree.clone().matches(&[str!("foo")])); + assert_false!(tree.clone().matches(&[str!("foo")])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("baz"),])); - assert_false!(tree.clone().matches(vec![str!("foo"), str!("baz"),])); - assert_true!(tree.clone().matches(vec![ + .matches(&[str!("foo"), str!("bar"), str!("baz"),])); + assert_false!(tree.clone().matches(&[str!("foo"), str!("baz"),])); + assert_true!(tree.clone().matches(&[ str!("foo"), str!("bar"), str!("bar"), @@ -1032,7 +1031,7 @@ mod tests { str!("bar"), str!("baz"), ])); - assert_false!(tree.clone().matches(vec![ + assert_false!(tree.clone().matches(&[ str!("foo"), str!("bar"), str!("bar"), @@ -1042,54 +1041,48 @@ mod tests { ])); let tree = CssSyntax::new("foo bar+").compile().unwrap(); - assert_false!(tree.clone().matches(vec![str!("foo")])); - assert_false!(tree.clone().matches(vec![str!("bar")])); - assert_true!(tree.clone().matches(vec![str!("foo"), str!("bar"),])); + assert_false!(tree.clone().matches(&[str!("foo")])); + assert_false!(tree.clone().matches(&[str!("bar")])); + assert_true!(tree.clone().matches(&[str!("foo"), str!("bar"),])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("bar"),])); - assert_false!(tree.clone().matches(vec![str!("bar"), str!("foo"),])); + .matches(&[str!("foo"), str!("bar"), str!("bar"),])); + assert_false!(tree.clone().matches(&[str!("bar"), str!("foo"),])); let tree = CssSyntax::new("foo+ bar+").compile().unwrap(); - assert_false!(tree.clone().matches(vec![str!("foo")])); - assert_false!(tree.clone().matches(vec![str!("bar")])); - assert_true!(tree.clone().matches(vec![str!("foo"), str!("bar"),])); + assert_false!(tree.clone().matches(&[str!("foo")])); + assert_false!(tree.clone().matches(&[str!("bar")])); + assert_true!(tree.clone().matches(&[str!("foo"), str!("bar"),])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("bar"),])); - assert_true!(tree.clone().matches(vec![ - str!("foo"), - str!("foo"), - str!("bar"), - str!("bar"), - ])); + .matches(&[str!("foo"), str!("bar"), str!("bar"),])); + assert_true!(tree + .clone() + .matches(&[str!("foo"), str!("foo"), str!("bar"), str!("bar"),])); - assert_false!(tree.clone().matches(vec![str!("bar"), str!("foo"),])); + assert_false!(tree.clone().matches(&[str!("bar"), str!("foo"),])); } #[test] fn test_multipliers_between() { let tree = CssSyntax::new("foo bar{1,3} baz").compile().unwrap(); - assert_false!(tree.clone().matches(vec![str!("foo")])); - assert_false!(tree.clone().matches(vec![str!("foo")])); + assert_false!(tree.clone().matches(&[str!("foo")])); + assert_false!(tree.clone().matches(&[str!("foo")])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("baz"),])); - assert_false!(tree.clone().matches(vec![str!("foo"), str!("baz"),])); - assert_true!(tree.clone().matches(vec![ - str!("foo"), - str!("bar"), - str!("bar"), - str!("baz"), - ])); - assert_true!(tree.clone().matches(vec![ + .matches(&[str!("foo"), str!("bar"), str!("baz"),])); + assert_false!(tree.clone().matches(&[str!("foo"), str!("baz"),])); + assert_true!(tree + .clone() + .matches(&[str!("foo"), str!("bar"), str!("bar"), str!("baz"),])); + assert_true!(tree.clone().matches(&[ str!("foo"), str!("bar"), str!("bar"), str!("bar"), str!("baz"), ])); - assert_false!(tree.clone().matches(vec![ + assert_false!(tree.clone().matches(&[ str!("foo"), str!("bar"), str!("bar"), @@ -1097,7 +1090,7 @@ mod tests { str!("bar"), str!("baz"), ])); - assert_false!(tree.clone().matches(vec![ + assert_false!(tree.clone().matches(&[ str!("foo"), str!("bar"), str!("bar"), @@ -1107,25 +1100,25 @@ mod tests { ])); let tree = CssSyntax::new("foo bar{0,3}").compile().unwrap(); - assert_true!(tree.clone().matches(vec![str!("foo")])); - assert_true!(tree.clone().matches(vec![str!("foo")])); - assert_true!(tree.clone().matches(vec![str!("foo"), str!("bar"),])); + assert_true!(tree.clone().matches(&[str!("foo")])); + assert_true!(tree.clone().matches(&[str!("foo")])); + assert_true!(tree.clone().matches(&[str!("foo"), str!("bar"),])); assert_true!(tree .clone() - .matches(vec![str!("foo"), str!("bar"), str!("bar"),])); - assert_false!(tree.clone().matches(vec![ + .matches(&[str!("foo"), str!("bar"), str!("bar"),])); + assert_false!(tree.clone().matches(&[ str!("foo"), str!("bar"), str!("bar"), str!("bar"), str!("bar"), ])); - assert_false!(tree.clone().matches(vec![str!("bar"), str!("foo"),])); + assert_false!(tree.clone().matches(&[str!("bar"), str!("foo"),])); } #[test] fn test_matcher() { - let mut definitions = parse_definition_files(); + let mut definitions = get_css_definitions().clone(); definitions.add_property( "testprop", PropertyDefinition { @@ -1147,25 +1140,25 @@ mod tests { assert_true!(prop .clone() - .matches(vec![str!("left"), CssValue::Unit(5.0, "px".into()),])); + .matches(&[str!("left"), CssValue::Unit(5.0, "px".into()),])); assert_true!(prop .clone() - .matches(vec![str!("top"), CssValue::Unit(5.0, "px".into()),])); + .matches(&[str!("top"), CssValue::Unit(5.0, "px".into()),])); assert_true!(prop .clone() - .matches(vec![str!("bottom"), CssValue::Unit(5.0, "px".into()),])); + .matches(&[str!("bottom"), CssValue::Unit(5.0, "px".into()),])); assert_true!(prop .clone() - .matches(vec![str!("right"), CssValue::Unit(5.0, "px".into()),])); - assert_true!(prop.clone().matches(vec![str!("left")])); - assert_true!(prop.clone().matches(vec![str!("top")])); - assert_true!(prop.clone().matches(vec![str!("bottom")])); - assert_true!(prop.clone().matches(vec![str!("right")])); + .matches(&[str!("right"), CssValue::Unit(5.0, "px".into()),])); + assert_true!(prop.clone().matches(&[str!("left")])); + assert_true!(prop.clone().matches(&[str!("top")])); + assert_true!(prop.clone().matches(&[str!("bottom")])); + assert_true!(prop.clone().matches(&[str!("right")])); assert_false!(prop .clone() - .matches(vec![CssValue::Unit(5.0, "px".into()), str!("right"),])); - assert_false!(prop.clone().matches(vec![ + .matches(&[CssValue::Unit(5.0, "px".into()), str!("right"),])); + assert_false!(prop.clone().matches(&[ CssValue::Unit(5.0, "px".into()), CssValue::Unit(10.0, "px".into()), str!("right"), @@ -1174,7 +1167,7 @@ mod tests { #[test] fn test_matcher_2() { - let mut definitions = parse_definition_files(); + let mut definitions = get_css_definitions().clone(); definitions.add_property( "testprop", PropertyDefinition { @@ -1190,40 +1183,40 @@ mod tests { let prop = definitions.find_property("testprop").unwrap(); - assert_true!(prop.clone().matches(vec![str!("left"),])); - assert_true!(prop.clone().matches(vec![str!("left"), str!("top"),])); - assert_true!(prop.clone().matches(vec![str!("center"), str!("top"),])); - assert_false!(prop.clone().matches(vec![str!("top"), str!("top"),])); - assert_false!(prop.clone().matches(vec![str!("top"), str!("center"),])); - assert_true!(prop.clone().matches(vec![str!("center"), str!("top"),])); - assert_true!(prop.clone().matches(vec![str!("center"), str!("center"),])); + assert_true!(prop.clone().matches(&[str!("left"),])); + assert_true!(prop.clone().matches(&[str!("left"), str!("top"),])); + assert_true!(prop.clone().matches(&[str!("center"), str!("top"),])); + assert_false!(prop.clone().matches(&[str!("top"), str!("top"),])); + assert_false!(prop.clone().matches(&[str!("top"), str!("center"),])); + assert_true!(prop.clone().matches(&[str!("center"), str!("top"),])); + assert_true!(prop.clone().matches(&[str!("center"), str!("center"),])); assert_true!(prop .clone() - .matches(vec![CssValue::Percentage(10.0), CssValue::Percentage(20.0),])); - assert_true!(prop.clone().matches(vec![ + .matches(&[CssValue::Percentage(10.0), CssValue::Percentage(20.0),])); + assert_true!(prop.clone().matches(&[ CssValue::Unit(10.0, "px".into()), CssValue::Percentage(20.0), ])); assert_true!(prop .clone() - .matches(vec![str!("left"), CssValue::Percentage(20.0),])); + .matches(&[str!("left"), CssValue::Percentage(20.0),])); assert_true!(prop .clone() - .matches(vec![CssValue::Unit(10.0, "px".into()), str!("center"),])); + .matches(&[CssValue::Unit(10.0, "px".into()), str!("center"),])); assert_true!(prop .clone() - .matches(vec![CssValue::Percentage(10.0), str!("top"),])); + .matches(&[CssValue::Percentage(10.0), str!("top"),])); - assert_true!(prop.clone().matches(vec![str!("right")])); + assert_true!(prop.clone().matches(&[str!("right")])); - assert_true!(prop.clone().matches(vec![str!("top")])); + assert_true!(prop.clone().matches(&[str!("top")])); } #[test] fn test_matcher_3() { - let mut definitions = parse_definition_files(); + let mut definitions = get_css_definitions().clone(); definitions.add_property( "testprop", PropertyDefinition { @@ -1241,12 +1234,12 @@ mod tests { let prop = definitions.find_property("testprop").unwrap(); - assert_true!(prop.clone().matches(vec![str!("foo"),])); - assert_true!(prop.clone().matches(vec![str!("foo"), str!("foo"),])); - assert_true!(prop.clone().matches(vec![str!("foo"), str!("bar"),])); + assert_true!(prop.clone().matches(&[str!("foo"),])); + assert_true!(prop.clone().matches(&[str!("foo"), str!("foo"),])); + assert_true!(prop.clone().matches(&[str!("foo"), str!("bar"),])); - assert_false!(prop.clone().matches(vec![str!("bar"),])); - assert_false!(prop.clone().matches(vec![str!("bar"), str!("foo"),])); + assert_false!(prop.clone().matches(&[str!("bar"),])); + assert_false!(prop.clone().matches(&[str!("bar"), str!("foo"),])); } #[test] @@ -1375,14 +1368,14 @@ mod tests { #[test] fn test_match_with_subgroups() { let tree = CssSyntax::new("[a b ] | [a c]").compile().unwrap(); - assert_true!(tree.matches(vec![str!("a"), str!("b"),])); - assert_true!(tree.matches(vec![str!("a"), str!("c"),])); - assert_false!(tree.matches(vec![str!("b"), str!("b"),])); + assert_true!(tree.matches(&[str!("a"), str!("b"),])); + assert_true!(tree.matches(&[str!("a"), str!("c"),])); + assert_false!(tree.matches(&[str!("b"), str!("b"),])); } #[test] fn test_matcher_4() { - let mut definitions = parse_definition_files(); + let mut definitions = get_css_definitions().clone(); definitions.add_property( "testprop", PropertyDefinition { @@ -1404,39 +1397,39 @@ mod tests { assert_true!(prop .clone() - .matches(vec![str!("left"), CssValue::Unit(10.0, "px".into()),])); + .matches(&[str!("left"), CssValue::Unit(10.0, "px".into()),])); assert_true!(prop .clone() - .matches(vec![str!("right"), CssValue::Unit(10.0, "px".into()),])); - assert_true!(prop.clone().matches(vec![str!("left"),])); - assert_true!(prop.clone().matches(vec![str!("right"),])); + .matches(&[str!("right"), CssValue::Unit(10.0, "px".into()),])); + assert_true!(prop.clone().matches(&[str!("left"),])); + assert_true!(prop.clone().matches(&[str!("right"),])); assert_true!(prop .clone() - .matches(vec![str!("top"), CssValue::Unit(10.0, "px".into()),])); + .matches(&[str!("top"), CssValue::Unit(10.0, "px".into()),])); assert_true!(prop .clone() - .matches(vec![str!("bottom"), CssValue::Unit(10.0, "px".into()),])); + .matches(&[str!("bottom"), CssValue::Unit(10.0, "px".into()),])); - assert_true!(prop.clone().matches(vec![str!("top"),])); - assert_true!(prop.clone().matches(vec![str!("bottom"),])); + assert_true!(prop.clone().matches(&[str!("top"),])); + assert_true!(prop.clone().matches(&[str!("bottom"),])); } #[test] fn test_comma_separated() { let tree = CssSyntax::new("[foo | bar | baz]#").compile().unwrap(); - assert_true!(tree.matches(vec![str!("foo")])); - assert_true!(tree.matches(vec![str!("foo"), CssValue::Comma, str!("foo")])); - assert_true!(tree.matches(vec![ + assert_true!(tree.matches(&[str!("foo")])); + assert_true!(tree.matches(&[str!("foo"), CssValue::Comma, str!("foo")])); + assert_true!(tree.matches(&[ str!("foo"), CssValue::Comma, str!("foo"), CssValue::Comma, str!("foo") ])); - assert_true!(tree.matches(vec![str!("foo"), CssValue::Comma, str!("bar")])); - assert_true!(tree.matches(vec![str!("foo"), CssValue::Comma, str!("baz")])); - assert_true!(tree.matches(vec![ + assert_true!(tree.matches(&[str!("foo"), CssValue::Comma, str!("bar")])); + assert_true!(tree.matches(&[str!("foo"), CssValue::Comma, str!("baz")])); + assert_true!(tree.matches(&[ str!("foo"), CssValue::Comma, str!("bar"), @@ -1444,18 +1437,8 @@ mod tests { str!("baz") ])); - assert_false!(tree.matches(vec![str!("foo"), CssValue::Comma])); - assert_false!(tree.matches(vec![ - str!("foo"), - CssValue::Comma, - str!("bar"), - CssValue::Comma - ])); - assert_false!(tree.matches(vec![ - str!("foo"), - CssValue::Comma, - CssValue::Comma, - str!("bar") - ])); + assert_false!(tree.matches(&[str!("foo"), CssValue::Comma])); + assert_false!(tree.matches(&[str!("foo"), CssValue::Comma, str!("bar"), CssValue::Comma])); + assert_false!(tree.matches(&[str!("foo"), CssValue::Comma, CssValue::Comma, str!("bar")])); } }