From 24fbd17f3e5ffd5e31a0b73ab6afcee0bcff6555 Mon Sep 17 00:00:00 2001 From: Glint Dev Date: Wed, 22 Jul 2026 13:06:01 +0300 Subject: [PATCH] Phase 4.1: Add StyleIndex struct and build_index() to StyleSheet --- src/interpreter/style.rs | 105 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/src/interpreter/style.rs b/src/interpreter/style.rs index f8a41c5..f0971de 100644 --- a/src/interpreter/style.rs +++ b/src/interpreter/style.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::borrow::Cow; @@ -457,9 +457,19 @@ impl StyleRule { } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct StyleSheet { rules: Vec, + index: Option, +} + +impl Default for StyleSheet { + fn default() -> Self { + Self { + rules: Vec::new(), + index: None, + } + } } impl StyleSheet { @@ -473,6 +483,64 @@ impl StyleSheet { } } + pub fn build_index(&mut self) { + let mut index = StyleIndex::new(); + index.epoch += 1; + + for (i, rule) in self.rules.iter().enumerate() { + let specificity = rule.selector.specificity(); + index.rule_specificities.push(specificity); + index.rules.push(rule.clone()); + + if rule.selector.compounds.len() == 1 { + if let Some(compound) = rule.selector.compounds.first() { + let tag_key = compound.tag.as_deref().unwrap_or("*"); + index.by_tag.entry(tag_key.to_string()).or_default().push(i); + + if tag_key == "*" { + index.universal_rules.push(i); + } + + for cls in &compound.classes { + index.by_class.entry(cls.clone()).or_default().push(i); + index.by_tag_class.entry((tag_key.to_string(), cls.clone())).or_default().push(i); + } + + if let Some(id) = &compound.id { + index.by_id.entry(id.clone()).or_default().push(i); + index.by_tag_id.entry((tag_key.to_string(), id.clone())).or_default().push(i); + } + } + } else { + if let Some(compound) = rule.selector.compounds.last() { + let tag_key = compound.tag.as_deref().unwrap_or("*"); + index.by_tag.entry(tag_key.to_string()).or_default().push(i); + + if tag_key == "*" { + index.universal_rules.push(i); + } + + for cls in &compound.classes { + index.by_class.entry(cls.clone()).or_default().push(i); + index.by_tag_class.entry((tag_key.to_string(), cls.clone())).or_default().push(i); + } + + if let Some(id) = &compound.id { + index.by_id.entry(id.clone()).or_default().push(i); + index.by_tag_id.entry((tag_key.to_string(), id.clone())).or_default().push(i); + } + } + index.complex_rules.push((i, i)); + } + } + + self.index = Some(index); + } + + pub fn has_index(&self) -> bool { + self.index.is_some() + } + pub fn matching_rules<'a>( &'a self, type_name: &str, @@ -563,6 +631,39 @@ fn split_selectors(input: &str) -> Vec { parts } +pub type RuleId = usize; + +#[derive(Debug, Clone)] +pub struct StyleIndex { + pub by_tag: HashMap>, + pub by_class: HashMap>, + pub by_id: HashMap>, + pub by_tag_class: HashMap<(String, String), Vec>, + pub by_tag_id: HashMap<(String, String), Vec>, + pub complex_rules: Vec<(RuleId, RuleId)>, + pub universal_rules: Vec, + pub rule_specificities: Vec<(u32, u32, u32)>, + pub rules: Vec, + pub epoch: u64, +} + +impl StyleIndex { + pub fn new() -> Self { + Self { + by_tag: HashMap::new(), + by_class: HashMap::new(), + by_id: HashMap::new(), + by_tag_class: HashMap::new(), + by_tag_id: HashMap::new(), + complex_rules: Vec::new(), + universal_rules: Vec::new(), + rule_specificities: Vec::new(), + rules: Vec::new(), + epoch: 0, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum Overflow { #[default]