orbtk_css_engine/
selector.rs1use std::fmt;
2use std::{collections::HashSet, ops::Add};
3
4#[derive(Clone, Debug)]
5pub enum SelectorRelation {
6 Ancestor(Selector),
7 Parent(Selector),
8}
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
17pub struct Specificity([u8; 3]);
18
19impl Add<Self> for Specificity {
20 type Output = Self;
21
22 fn add(self, rhs: Self) -> Self::Output {
23 Specificity([
24 self.0[0] + rhs.0[0],
25 self.0[1] + rhs.0[1],
26 self.0[2] + rhs.0[2],
27 ])
28 }
29}
30
31#[derive(Debug, Default)]
33pub struct Selector {
34 pub id: Option<String>,
35 pub element: Option<String>,
36 pub classes: HashSet<String>,
37 pub pseudo_classes: HashSet<String>,
38 pub relation: Option<Box<SelectorRelation>>,
39 pub dirty: bool,
40}
41
42impl Selector {
44 pub fn new() -> Self {
45 Selector {
46 id: None,
47 element: None,
48 classes: HashSet::new(),
49 pseudo_classes: HashSet::new(),
50 relation: None,
51 dirty: true,
52 }
53 }
54
55 pub fn is_empty(&self) -> bool {
56 self.element.is_none()
57 && self.id.is_none()
58 && self.classes.is_empty()
59 && self.pseudo_classes.is_empty()
60 }
61
62 pub fn dirty(&self) -> bool {
63 self.dirty
64 }
65
66 pub fn set_dirty(&mut self, dirty: bool) {
67 self.dirty = dirty;
68 }
69
70 pub fn specificity(&self) -> Specificity {
71 let s = Specificity([
72 if self.id.is_some() { 1 } else { 0 },
73 (self.classes.len() + self.pseudo_classes.len()) as u8,
74 if self.element.is_some() { 1 } else { 0 },
75 ]);
76
77 if let Some(ref relation) = self.relation {
78 match **relation {
79 SelectorRelation::Ancestor(ref x) | SelectorRelation::Parent(ref x) => {
80 return x.specificity() + s;
81 }
82 }
83 }
84
85 s
86 }
87
88 pub fn matches(&self, other: &Selector) -> bool {
89 if self.id.is_some() && self.id != other.id {
90 return false;
91 }
92
93 if self.element.is_some() && self.element != other.element {
94 return false;
95 }
96
97 if !other.classes.is_superset(&self.classes) {
98 return false;
99 }
100
101 if !other.pseudo_classes.is_superset(&self.pseudo_classes) {
102 return false;
103 }
104
105 true
106 }
107
108 pub fn with<S: Into<String>>(mut self, element: S) -> Self {
109 self.element = Some(element.into());
110 self
111 }
112
113 pub fn id<S: Into<String>>(mut self, id: S) -> Self {
114 self.id = Some(id.into());
115 self
116 }
117
118 pub fn class<S: Into<String>>(mut self, class: S) -> Self {
119 self.classes.insert(class.into());
120 self
121 }
122
123 pub fn without_class<S: Into<String>>(mut self, class: S) -> Self {
124 self.classes.remove(&class.into());
125 self
126 }
127
128 pub fn pseudo_class<S: Into<String>>(mut self, pseudo_class: S) -> Self {
129 self.pseudo_classes.insert(pseudo_class.into());
130 self
131 }
132
133 pub fn without_pseudo_class<S: Into<String>>(mut self, pseudo_class: S) -> Self {
134 self.pseudo_classes.remove(&pseudo_class.into());
135 self
136 }
137}
138
139impl PartialEq for Selector {
140 fn eq(&self, other: &Selector) -> bool {
141 self.id == other.id
142 }
143}
144
145impl Clone for Selector {
146 fn clone(&self) -> Self {
147 Selector {
148 id: self.id.clone(),
149 element: self.element.clone(),
150 classes: self.classes.clone(),
151 pseudo_classes: self.pseudo_classes.clone(),
152 relation: self.relation.clone(),
153 dirty: self.dirty,
154 }
155 }
156}
157
158impl fmt::Display for Selector {
159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160 if let Some(element) = &self.element {
161 return write!(f, ", css: {}", element);
162 }
163
164 write!(f, "")
165 }
166}
167
168impl From<String> for Selector {
171 fn from(s: String) -> Selector {
172 Selector::new().with(s)
173 }
174}
175
176impl From<&str> for Selector {
177 fn from(s: &str) -> Selector {
178 Selector::new().with(s.to_string())
179 }
180}
181
182impl From<&Selector> for Selector {
183 fn from(s: &Selector) -> Selector {
184 let mut selector = Selector::default();
185 selector.element = s.element.clone();
186 selector.id = s.id.clone();
187 selector.classes = s.classes.clone();
188 selector.pseudo_classes = s.pseudo_classes.clone();
189 selector
190 }
191}