pest_css_parser/stylesheet/
rule.rs

1use std::collections::HashMap;
2
3use super::constants::COLORS;
4
5pub type Specificity = (usize, usize, usize);
6
7#[derive(Debug, Clone, PartialEq)]
8pub enum CssRule {
9    Normal(NormalRule),
10    Comment(String),
11}
12
13#[derive(Debug, Default, Clone, PartialEq)]
14pub struct NormalRule {
15    pub selectors: Vec<Selector>,
16    pub declarations: HashMap<String, Value>,
17}
18
19#[derive(Debug, Clone, PartialEq)]
20pub enum Selector {
21    Simple(SimpleSelector),
22}
23
24#[derive(Debug, Clone, Default, PartialEq)]
25pub struct SimpleSelector {
26    pub id: Option<String>,
27    pub class: Vec<String>,
28    pub tag_name: Option<String>,
29}
30
31#[derive(Debug, Clone, PartialEq)]
32pub enum Value {
33    Keyword(String),
34    Length(f32, Unit),
35    Color(Color),
36    StringLiteral(String),
37}
38
39#[derive(Debug, Copy, Clone, PartialEq)]
40pub enum Unit {
41    /// Centimeters
42    Cm,
43    /// Millieters
44    Mm,
45    /// Inches
46    In,
47    /// Pixels
48    Px,
49    /// Points
50    Pt,
51    /// Picas
52    Pc,
53    /// Relative to the font-size of the element
54    Em,
55    /// Relative to the x-height of the current font
56    Ex,
57    /// Relative to the width of the "0"
58    Ch,
59    /// Relative to font-size of the root element
60    Rem,
61    /// Relative to 1% of the width of the viewport*
62    Vw,
63    /// Relative to 1% of the height of the viewport*
64    Vh,
65    /// Relative to 1% of viewport's* smaller dimension
66    VMin,
67    /// Relative to 1% of viewport's* larger dimension
68    VMax,
69    /// Relative to the parent element
70    Percent,
71}
72
73#[derive(Debug, Default, Clone, Copy, PartialEq)]
74pub struct Color {
75    pub r: u8,
76    pub g: u8,
77    pub b: u8,
78    pub a: u8,
79}
80
81impl Selector {
82    /// Computes the specificity of a CSS selector as defined by the W3C specification.
83    ///
84    /// Returns the count of ID, class, and tag name selectors in a [`Selector::Simple`].
85    /// If the selector is not a [`Selector::Simple`], returns `None`.
86    ///
87    /// See [W3C Selectors Level 3](https://www.w3.org/TR/selectors/#specificity).
88    pub fn specificity(&self) -> Option<Specificity> {
89        match self {
90            Selector::Simple(simple) => {
91                let a = simple.id.iter().count();
92                let b = simple.class.len();
93                let c = simple.tag_name.iter().count();
94                Some((a, b, c))
95            }
96        }
97    }
98}
99
100impl From<&str> for Unit {
101    fn from(value: &str) -> Self {
102        match value {
103            "cm" => Unit::Cm,
104            "mm" => Unit::Mm,
105            "in" => Unit::In,
106            "px" => Unit::Px,
107            "pt" => Unit::Pt,
108            "pc" => Unit::Pc,
109
110            "em" => Unit::Em,
111            "ex" => Unit::Ex,
112            "ch" => Unit::Ch,
113            "rem" => Unit::Rem,
114            "vw" => Unit::Vw,
115            "vh" => Unit::Vh,
116            "vmin" => Unit::VMin,
117            "vmax" => Unit::VMax,
118            "%" => Unit::Percent,
119            _ => Unit::Px,
120        }
121    }
122}
123
124impl Value {
125    /// Return the length in px, or zero for non-lengths.
126    pub fn to_px(&self) -> f32 {
127        match *self {
128            Value::Length(f, _) => f,
129            _ => 0.0,
130        }
131    }
132}
133
134impl Color {
135    pub fn from_hex(hex: &str) -> Self {
136        let hex = hex.trim_start_matches('#');
137        let num = i32::from_str_radix(&hex[0..], 16).unwrap();
138        let r = (num >> 16) as u8;
139        let g = (num >> 8) as u8;
140        let b = num as u8;
141
142        Self {
143            r,
144            g,
145            b,
146            a: 255
147        }
148    }
149
150    pub fn from_keyword(name: &str) -> Self {
151        let unlocked = COLORS.lock().unwrap();
152        *unlocked.get(&name.to_lowercase()).unwrap()
153    }
154}