lewp_selectors/
builder.rs1use crate::parser::{Combinator, Component, SelectorImpl};
21use crate::sink::Push;
22use servo_arc::{Arc, HeaderWithLength, ThinArc};
23use smallvec::{self, SmallVec};
24use std::cmp;
25use std::iter;
26use std::ptr;
27use std::slice;
28
29#[derive(Debug)]
39pub struct SelectorBuilder<Impl: SelectorImpl> {
40 simple_selectors: SmallVec<[Component<Impl>; 32]>,
47 combinators: SmallVec<[(Combinator, usize); 16]>,
49 current_len: usize,
51}
52
53impl<Impl: SelectorImpl> Default for SelectorBuilder<Impl> {
54 #[inline(always)]
55 fn default() -> Self {
56 SelectorBuilder {
57 simple_selectors: SmallVec::new(),
58 combinators: SmallVec::new(),
59 current_len: 0,
60 }
61 }
62}
63
64impl<Impl: SelectorImpl> Push<Component<Impl>> for SelectorBuilder<Impl> {
65 fn push(&mut self, value: Component<Impl>) {
66 self.push_simple_selector(value);
67 }
68}
69
70impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
71 #[inline(always)]
73 pub fn push_simple_selector(&mut self, ss: Component<Impl>) {
74 assert!(!ss.is_combinator());
75 self.simple_selectors.push(ss);
76 self.current_len += 1;
77 }
78
79 #[inline(always)]
82 pub fn push_combinator(&mut self, c: Combinator) {
83 self.combinators.push((c, self.current_len));
84 self.current_len = 0;
85 }
86
87 #[inline(always)]
89 pub fn has_combinators(&self) -> bool {
90 !self.combinators.is_empty()
91 }
92
93 #[inline(always)]
95 pub fn build(
96 &mut self,
97 parsed_pseudo: bool,
98 parsed_slotted: bool,
99 parsed_part: bool,
100 ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
101 let specificity = specificity(self.simple_selectors.iter());
103 let mut flags = SelectorFlags::empty();
104 if parsed_pseudo {
105 flags |= SelectorFlags::HAS_PSEUDO;
106 }
107 if parsed_slotted {
108 flags |= SelectorFlags::HAS_SLOTTED;
109 }
110 if parsed_part {
111 flags |= SelectorFlags::HAS_PART;
112 }
113 self.build_with_specificity_and_flags(SpecificityAndFlags {
114 specificity,
115 flags,
116 })
117 }
118
119 #[inline(always)]
122 pub fn build_with_specificity_and_flags(
123 &mut self,
124 spec: SpecificityAndFlags,
125 ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
126 let full_len = self.simple_selectors.len() + self.combinators.len();
129
130 let header = HeaderWithLength::new(spec, full_len);
132
133 let raw_simple_selectors: *const [Component<Impl>] =
139 &*self.simple_selectors;
140 unsafe {
141 self.simple_selectors.set_len(0)
144 }
145 let (rest, current) =
146 split_from_end(unsafe { &*raw_simple_selectors }, self.current_len);
147 let iter = SelectorBuilderIter {
148 current_simple_selectors: current.iter(),
149 rest_of_simple_selectors: rest,
150 combinators: self.combinators.drain(..).rev(),
151 };
152
153 Arc::into_thin(Arc::from_header_and_iter(header, iter))
154 }
155}
156
157struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
158 current_simple_selectors: slice::Iter<'a, Component<Impl>>,
159 rest_of_simple_selectors: &'a [Component<Impl>],
160 combinators: iter::Rev<smallvec::Drain<'a, [(Combinator, usize); 16]>>,
161}
162
163impl<'a, Impl: SelectorImpl> ExactSizeIterator
164 for SelectorBuilderIter<'a, Impl>
165{
166 fn len(&self) -> usize {
167 self.current_simple_selectors.len()
168 + self.rest_of_simple_selectors.len()
169 + self.combinators.len()
170 }
171}
172
173impl<'a, Impl: SelectorImpl> Iterator for SelectorBuilderIter<'a, Impl> {
174 type Item = Component<Impl>;
175 #[inline(always)]
176 fn next(&mut self) -> Option<Self::Item> {
177 if let Some(simple_selector_ref) = self.current_simple_selectors.next()
178 {
179 unsafe { Some(ptr::read(simple_selector_ref)) }
183 } else {
184 self.combinators.next().map(|(combinator, len)| {
185 let (rest, current) =
186 split_from_end(self.rest_of_simple_selectors, len);
187 self.rest_of_simple_selectors = rest;
188 self.current_simple_selectors = current.iter();
189 Component::Combinator(combinator)
190 })
191 }
192 }
193
194 fn size_hint(&self) -> (usize, Option<usize>) {
195 (self.len(), Some(self.len()))
196 }
197}
198
199fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
200 s.split_at(s.len() - at)
201}
202
203bitflags! {
204 #[derive(Default)]
206 pub (crate) struct SelectorFlags : u8 {
207 const HAS_PSEUDO = 1 << 0;
208 const HAS_SLOTTED = 1 << 1;
209 const HAS_PART = 1 << 2;
210 }
211}
212
213#[derive(Clone, Copy, Debug, Eq, PartialEq)]
214pub struct SpecificityAndFlags {
215 pub(crate) specificity: u32,
218 pub(crate) flags: SelectorFlags,
220}
221
222impl SpecificityAndFlags {
223 #[inline]
224 pub fn specificity(&self) -> u32 {
225 self.specificity
226 }
227
228 #[inline]
229 pub fn has_pseudo_element(&self) -> bool {
230 self.flags.intersects(SelectorFlags::HAS_PSEUDO)
231 }
232
233 #[inline]
234 pub fn is_slotted(&self) -> bool {
235 self.flags.intersects(SelectorFlags::HAS_SLOTTED)
236 }
237
238 #[inline]
239 pub fn is_part(&self) -> bool {
240 self.flags.intersects(SelectorFlags::HAS_PART)
241 }
242}
243
244const MAX_10BIT: u32 = (1u32 << 10) - 1;
245
246#[derive(
247 Add, AddAssign, Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd,
248)]
249struct Specificity {
250 id_selectors: u32,
251 class_like_selectors: u32,
252 element_selectors: u32,
253}
254
255impl From<u32> for Specificity {
256 #[inline]
257 fn from(value: u32) -> Specificity {
258 assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
259 Specificity {
260 id_selectors: value >> 20,
261 class_like_selectors: (value >> 10) & MAX_10BIT,
262 element_selectors: value & MAX_10BIT,
263 }
264 }
265}
266
267impl From<Specificity> for u32 {
268 #[inline]
269 fn from(specificity: Specificity) -> u32 {
270 cmp::min(specificity.id_selectors, MAX_10BIT) << 20
271 | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10
272 | cmp::min(specificity.element_selectors, MAX_10BIT)
273 }
274}
275
276fn specificity<Impl>(iter: slice::Iter<Component<Impl>>) -> u32
277where
278 Impl: SelectorImpl,
279{
280 complex_selector_specificity(iter).into()
281}
282
283fn complex_selector_specificity<Impl>(
284 iter: slice::Iter<Component<Impl>>,
285) -> Specificity
286where
287 Impl: SelectorImpl,
288{
289 fn simple_selector_specificity<Impl>(
290 simple_selector: &Component<Impl>,
291 specificity: &mut Specificity,
292 ) where
293 Impl: SelectorImpl,
294 {
295 match *simple_selector {
296 Component::Combinator(..) => {
297 unreachable!("Found combinator in simple selectors vector?");
298 }
299 Component::Part(..)
300 | Component::PseudoElement(..)
301 | Component::LocalName(..) => specificity.element_selectors += 1,
302 Component::Slotted(ref selector) => {
303 specificity.element_selectors += 1;
304 *specificity += Specificity::from(selector.specificity());
311 }
312 Component::Host(ref selector) => {
313 specificity.class_like_selectors += 1;
314 if let Some(ref selector) = *selector {
315 *specificity += Specificity::from(selector.specificity());
317 }
318 }
319 Component::ID(..) => {
320 specificity.id_selectors += 1;
321 }
322 Component::Class(..)
323 | Component::AttributeInNoNamespace { .. }
324 | Component::AttributeInNoNamespaceExists { .. }
325 | Component::AttributeOther(..)
326 | Component::FirstChild
327 | Component::LastChild
328 | Component::OnlyChild
329 | Component::Root
330 | Component::Empty
331 | Component::Scope
332 | Component::NthChild(..)
333 | Component::NthLastChild(..)
334 | Component::NthOfType(..)
335 | Component::NthLastOfType(..)
336 | Component::FirstOfType
337 | Component::LastOfType
338 | Component::OnlyOfType
339 | Component::NonTSPseudoClass(..) => {
340 specificity.class_like_selectors += 1;
341 }
342 Component::Negation(ref list) | Component::Is(ref list) => {
343 let mut max = 0;
349 for selector in &**list {
350 max = std::cmp::max(selector.specificity(), max);
351 }
352 *specificity += Specificity::from(max);
353 }
354 Component::Where(..)
355 | Component::ExplicitUniversalType
356 | Component::ExplicitAnyNamespace
357 | Component::ExplicitNoNamespace
358 | Component::DefaultNamespace(..)
359 | Component::Namespace(..) => {
360 }
362 }
363 }
364
365 let mut specificity = Default::default();
366 for simple_selector in iter {
367 simple_selector_specificity(&simple_selector, &mut specificity);
368 }
369 specificity
370}