use vize_carton::{CompactString, SmallVec};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct SelectorId(u32);
impl SelectorId {
#[inline(always)]
pub const fn new(id: u32) -> Self {
Self(id)
}
#[inline(always)]
pub const fn as_u32(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SelectorKind {
Class = 0,
Id = 1,
Element = 2,
Attribute = 3,
PseudoClass = 4,
PseudoElement = 5,
Combinator = 6,
}
#[derive(Debug, Clone)]
pub struct SelectorPart {
pub kind: SelectorKind,
pub value: CompactString,
}
#[derive(Debug, Clone)]
pub struct CssSelector {
pub id: SelectorId,
pub raw: CompactString,
pub parts: SmallVec<[SelectorPart; 4]>,
pub start: u32,
pub end: u32,
}
#[derive(Debug, Clone)]
pub struct CssVBind {
pub property: CompactString,
pub expression: CompactString,
pub start: u32,
pub end: u32,
}
#[derive(Debug, Clone)]
pub struct CssVariable {
pub name: CompactString,
pub value: Option<CompactString>,
pub start: u32,
pub end: u32,
}
#[derive(Debug, Clone, Default)]
pub struct CssStats {
pub selector_count: u32,
pub v_bind_count: u32,
pub variable_count: u32,
pub deep_selectors: u32,
pub slotted_selectors: u32,
pub global_selectors: u32,
}
#[derive(Debug, Default)]
pub struct CssTracker {
selectors: Vec<CssSelector>,
v_binds: Vec<CssVBind>,
variables: Vec<CssVariable>,
next_id: u32,
deep_count: u32,
slotted_count: u32,
global_count: u32,
}
impl CssTracker {
#[inline]
pub fn new() -> Self {
Self::default()
}
pub fn add_selector(
&mut self,
raw: CompactString,
parts: SmallVec<[SelectorPart; 4]>,
start: u32,
end: u32,
) -> SelectorId {
let id = SelectorId::new(self.next_id);
self.next_id += 1;
self.selectors.push(CssSelector {
id,
raw,
parts,
start,
end,
});
id
}
pub fn add_v_bind(
&mut self,
property: CompactString,
expression: CompactString,
start: u32,
end: u32,
) {
self.v_binds.push(CssVBind {
property,
expression,
start,
end,
});
}
pub fn add_variable(
&mut self,
name: CompactString,
value: Option<CompactString>,
start: u32,
end: u32,
) {
self.variables.push(CssVariable {
name,
value,
start,
end,
});
}
#[inline]
pub fn record_deep(&mut self) {
self.deep_count += 1;
}
#[inline]
pub fn record_slotted(&mut self) {
self.slotted_count += 1;
}
#[inline]
pub fn record_global(&mut self) {
self.global_count += 1;
}
#[inline]
pub fn selectors(&self) -> &[CssSelector] {
&self.selectors
}
#[inline]
pub fn v_binds(&self) -> &[CssVBind] {
&self.v_binds
}
#[inline]
pub fn variables(&self) -> &[CssVariable] {
&self.variables
}
pub fn stats(&self) -> CssStats {
CssStats {
selector_count: self.selectors.len() as u32,
v_bind_count: self.v_binds.len() as u32,
variable_count: self.variables.len() as u32,
deep_selectors: self.deep_count,
slotted_selectors: self.slotted_count,
global_selectors: self.global_count,
}
}
}
#[cfg(test)]
mod tests {
use super::{CssTracker, SelectorKind, SelectorPart};
use vize_carton::CompactString;
#[test]
fn test_css_tracker() {
let mut tracker = CssTracker::new();
tracker.add_selector(
CompactString::new(".btn"),
vize_carton::smallvec![SelectorPart {
kind: SelectorKind::Class,
value: CompactString::new("btn"),
}],
0,
10,
);
tracker.add_v_bind(
CompactString::new("color"),
CompactString::new("theme.color"),
20,
40,
);
let stats = tracker.stats();
assert_eq!(stats.selector_count, 1);
assert_eq!(stats.v_bind_count, 1);
}
}