1pub mod parser;
2use lazy_static::*;
3
4use std::collections::BTreeSet;
6
7#[derive(Debug, PartialEq)]
13pub struct Stylesheet {
14 pub rules: Vec<Rule>,
15}
16
17#[derive(Debug, PartialEq)]
18pub struct Rule {
19 pub selectors: SortedSelectors,
22 pub declarations: Vec<Declaration>,
23}
24
25#[derive(Debug, PartialEq)]
26pub struct SortedSelectors {
27 pub selectors: Vec<Selector>,
28}
29
30impl SortedSelectors {
31 pub fn new(mut selectors: Vec<Selector>) -> SortedSelectors {
32 selectors.sort_by(|a, b| b.specifity().cmp(&a.specifity()));
33 SortedSelectors { selectors }
34 }
35}
36
37#[derive(Debug, Clone, PartialEq)]
38pub enum Selector {
39 Simple(SimpleSelector),
40}
41
42impl Selector {
43 #[cfg(test)]
44 pub(crate) fn tag(tag_name: &str) -> Selector {
45 Selector::Simple(SimpleSelector::tag(tag_name))
46 }
47
48 #[cfg(test)]
49 pub(crate) fn id(id: &str) -> Selector {
50 Selector::Simple(SimpleSelector::id(id))
51 }
52
53 #[cfg(test)]
54 pub(crate) fn class(classes: &[&str]) -> Selector {
55 Selector::Simple(SimpleSelector::class(classes))
56 }
57
58 #[cfg(test)]
59 pub(crate) fn universal() -> Selector {
60 Selector::Simple(Default::default())
61 }
62}
63
64#[derive(Debug, Clone, Default, PartialEq)]
65pub struct SimpleSelector {
66 pub tag_name: Option<String>,
67 pub id: Option<String>,
68 pub classes: BTreeSet<String>,
69}
70
71impl SimpleSelector {
72 #[cfg(test)]
73 pub(crate) fn tag(tag_name: &str) -> SimpleSelector {
74 SimpleSelector {
75 tag_name: Some(tag_name.to_string()),
76 ..Default::default()
77 }
78 }
79
80 #[cfg(test)]
81 pub(crate) fn id(id: &str) -> SimpleSelector {
82 SimpleSelector {
83 id: Some(id.to_string()),
84 ..Default::default()
85 }
86 }
87
88 #[cfg(test)]
89 pub(crate) fn class(classes: &[&str]) -> SimpleSelector {
90 SimpleSelector {
91 classes: classes.iter().map(|s| s.to_string()).collect(),
92 ..Default::default()
93 }
94 }
95
96 #[cfg(test)]
97 pub(crate) fn universal() -> SimpleSelector {
98 Default::default()
99 }
100}
101
102#[derive(Debug, Clone, PartialEq)]
103pub struct Declaration {
104 pub name: String,
105 pub value: Value,
106}
107
108impl Declaration {
109 #[cfg(test)]
110 pub(crate) fn color(rgb: Rgb) -> Declaration {
111 Declaration {
112 name: "color".to_string(),
113 value: Value::color(rgb),
114 }
115 }
116}
117
118#[derive(Debug, Clone, PartialEq)]
119pub enum Value {
120 Keyword(String),
121 Length(f32, Unit),
122 ColorValue(Color),
123}
124
125impl Value {
126 #[cfg(test)]
127 pub(crate) fn color((r, g, b): Rgb) -> Value {
128 Value::ColorValue(Color { r, g, b })
129 }
130
131 pub fn keyword_auto() -> &'static Value {
132 lazy_static! {
133 static ref AUTO: Value = Value::Keyword("auto".to_string());
134 }
135 &AUTO
136 }
137
138 pub fn length_zero() -> &'static Value {
139 lazy_static! {
140 static ref LENGTH_ZERO: Value = Value::Length(0.0, Unit::Px);
141 }
142 &LENGTH_ZERO
143 }
144
145 pub fn to_px(&self) -> f32 {
146 match *self {
147 Value::Length(px, Unit::Px) => px,
148 _ => 0.0,
149 }
150 }
151}
152
153#[derive(Debug, Clone, PartialEq, Eq)]
154pub enum Unit {
155 Px,
156}
157
158pub type Rgb = (u8, u8, u8);
159
160#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
161pub struct Color {
162 pub r: u8,
163 pub g: u8,
164 pub b: u8,
165 }
167
168pub type Specifity = (usize, usize, usize);
169
170impl Selector {
171 pub fn specifity(&self) -> Specifity {
172 let Selector::Simple(ref simple) = *self;
173 let a = if simple.id.is_some() { 1 } else { 0 };
174 let b = simple.classes.len();
175 let c = if simple.tag_name.is_some() { 1 } else { 0 };
176 (a, b, c)
177 }
178}
179
180#[cfg(test)]
181mod test {
182 use super::*;
183 use maplit::btreeset;
184
185 #[test]
186 fn sorted_selectors_test() {
187 let selectors = vec![
188 Selector::tag("div"),
189 Selector::Simple(Default::default()),
190 Selector::id("foo"),
191 Selector::Simple(SimpleSelector {
192 classes: btreeset! { "class1".to_string(), "class2".to_string() },
193 ..Default::default()
194 }),
195 Selector::Simple(SimpleSelector {
196 tag_name: Some("div".to_string()),
197 classes: btreeset! { "class2".to_string() },
198 ..Default::default()
199 }),
200 Selector::class(&["class1"]),
201 ];
202
203 let sorted_selectors = SortedSelectors::new(selectors.clone());
204 assert_eq!(
205 sorted_selectors.selectors,
206 vec![
207 Selector::id("foo"),
208 Selector::Simple(SimpleSelector {
209 classes: btreeset! { "class1".to_string(), "class2".to_string() },
210 ..Default::default()
211 }),
212 Selector::Simple(SimpleSelector {
213 tag_name: Some("div".to_string()),
214 classes: btreeset! { "class2".to_string() },
215 ..Default::default()
216 }),
217 Selector::class(&["class1"]),
218 Selector::tag("div"),
219 Selector::Simple(Default::default()),
220 ]
221 );
222 }
223
224}