Phase 4.1: Add StyleIndex struct and build_index() to StyleSheet

This commit is contained in:
Glint Dev
2026-07-22 13:06:01 +03:00
parent 26ed1f900e
commit 24fbd17f3e

View File

@@ -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<StyleRule>,
index: Option<StyleIndex>,
}
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<String> {
parts
}
pub type RuleId = usize;
#[derive(Debug, Clone)]
pub struct StyleIndex {
pub by_tag: HashMap<String, Vec<RuleId>>,
pub by_class: HashMap<String, Vec<RuleId>>,
pub by_id: HashMap<String, Vec<RuleId>>,
pub by_tag_class: HashMap<(String, String), Vec<RuleId>>,
pub by_tag_id: HashMap<(String, String), Vec<RuleId>>,
pub complex_rules: Vec<(RuleId, RuleId)>,
pub universal_rules: Vec<RuleId>,
pub rule_specificities: Vec<(u32, u32, u32)>,
pub rules: Vec<StyleRule>,
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]