Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/parcel_selectors-0.28.3/builder.rs
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5
//! Helper module to build up a selector safely and efficiently.
6
//!
7
//! Our selector representation is designed to optimize matching, and has
8
//! several requirements:
9
//! * All simple selectors and combinators are stored inline in the same buffer
10
//!   as Component instances.
11
//! * We store the top-level compound selectors from right to left, i.e. in
12
//!   matching order.
13
//! * We store the simple selectors for each combinator from left to right, so
14
//!   that we match the cheaper simple selectors first.
15
//!
16
//! Meeting all these constraints without extra memmove traffic during parsing
17
//! is non-trivial. This module encapsulates those details and presents an
18
//! easy-to-use API for the parser.
19
20
use crate::parser::{Combinator, Component, SelectorImpl};
21
use crate::sink::Push;
22
// use servo_arc::{Arc, HeaderWithLength, ThinArc};
23
use smallvec::{self, SmallVec};
24
use std::cmp;
25
use std::iter;
26
use std::ops::{Add, AddAssign};
27
use std::ptr;
28
use std::slice;
29
30
/// Top-level SelectorBuilder struct. This should be stack-allocated by the
31
/// consumer and never moved (because it contains a lot of inline data that
32
/// would be slow to memmov).
33
///
34
/// After instantiation, callers may call the push_simple_selector() and
35
/// push_combinator() methods to append selector data as it is encountered
36
/// (from left to right). Once the process is complete, callers should invoke
37
/// build(), which transforms the contents of the SelectorBuilder into a heap-
38
/// allocated Selector and leaves the builder in a drained state.
39
#[derive(Debug)]
40
pub struct SelectorBuilder<'i, Impl: SelectorImpl<'i>> {
41
  /// The entire sequence of simple selectors, from left to right, without combinators.
42
  ///
43
  /// We make this large because the result of parsing a selector is fed into a new
44
  /// Arc-ed allocation, so any spilled vec would be a wasted allocation. Also,
45
  /// Components are large enough that we don't have much cache locality benefit
46
  /// from reserving stack space for fewer of them.
47
  simple_selectors: SmallVec<[Component<'i, Impl>; 32]>,
48
  /// The combinators, and the length of the compound selector to their left.
49
  combinators: SmallVec<[(Combinator, usize); 16]>,
50
  /// The length of the current compound selector.
51
  current_len: usize,
52
}
53
54
impl<'i, Impl: SelectorImpl<'i>> Default for SelectorBuilder<'i, Impl> {
55
  #[inline(always)]
56
1.90M
  fn default() -> Self {
57
1.90M
    SelectorBuilder {
58
1.90M
      simple_selectors: SmallVec::new(),
59
1.90M
      combinators: SmallVec::new(),
60
1.90M
      current_len: 0,
61
1.90M
    }
62
1.90M
  }
<parcel_selectors::builder::SelectorBuilder<lightningcss::selector::private::Selectors> as core::default::Default>::default
Line
Count
Source
56
1.90M
  fn default() -> Self {
57
1.90M
    SelectorBuilder {
58
1.90M
      simple_selectors: SmallVec::new(),
59
1.90M
      combinators: SmallVec::new(),
60
1.90M
      current_len: 0,
61
1.90M
    }
62
1.90M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilder<_> as core::default::Default>::default
63
}
64
65
impl<'i, Impl: SelectorImpl<'i>> Push<Component<'i, Impl>> for SelectorBuilder<'i, Impl> {
66
2.05M
  fn push(&mut self, value: Component<'i, Impl>) {
67
2.05M
    self.push_simple_selector(value);
68
2.05M
  }
<parcel_selectors::builder::SelectorBuilder<lightningcss::selector::private::Selectors> as parcel_selectors::sink::Push<parcel_selectors::parser::Component<lightningcss::selector::private::Selectors>>>::push
Line
Count
Source
66
2.05M
  fn push(&mut self, value: Component<'i, Impl>) {
67
2.05M
    self.push_simple_selector(value);
68
2.05M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilder<_> as parcel_selectors::sink::Push<parcel_selectors::parser::Component<_>>>::push
69
}
70
71
impl<'i, Impl: SelectorImpl<'i>> SelectorBuilder<'i, Impl> {
72
  /// Pushes a simple selector onto the current compound selector.
73
  #[inline(always)]
74
2.91M
  pub fn push_simple_selector(&mut self, ss: Component<'i, Impl>) {
75
2.91M
    assert!(!ss.is_combinator());
76
2.91M
    self.simple_selectors.push(ss);
77
2.91M
    self.current_len += 1;
78
2.91M
  }
<parcel_selectors::builder::SelectorBuilder<lightningcss::selector::private::Selectors>>::push_simple_selector
Line
Count
Source
74
2.91M
  pub fn push_simple_selector(&mut self, ss: Component<'i, Impl>) {
75
2.91M
    assert!(!ss.is_combinator());
76
2.91M
    self.simple_selectors.push(ss);
77
2.91M
    self.current_len += 1;
78
2.91M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilder<_>>::push_simple_selector
79
80
  /// Completes the current compound selector and starts a new one, delimited
81
  /// by the given combinator.
82
  #[inline(always)]
83
581k
  pub fn push_combinator(&mut self, c: Combinator) {
84
581k
    self.combinators.push((c, self.current_len));
85
581k
    self.current_len = 0;
86
581k
  }
<parcel_selectors::builder::SelectorBuilder<lightningcss::selector::private::Selectors>>::push_combinator
Line
Count
Source
83
581k
  pub fn push_combinator(&mut self, c: Combinator) {
84
581k
    self.combinators.push((c, self.current_len));
85
581k
    self.current_len = 0;
86
581k
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilder<_>>::push_combinator
87
88
  /// Returns true if combinators have ever been pushed to this builder.
89
  #[inline(always)]
90
165k
  pub fn has_combinators(&self) -> bool {
91
165k
    !self.combinators.is_empty()
92
165k
  }
<parcel_selectors::builder::SelectorBuilder<lightningcss::selector::private::Selectors>>::has_combinators
Line
Count
Source
90
165k
  pub fn has_combinators(&self) -> bool {
91
165k
    !self.combinators.is_empty()
92
165k
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilder<_>>::has_combinators
93
94
1.33M
  pub fn add_nesting_prefix(&mut self) {
95
1.33M
    self.combinators.insert(0, (Combinator::Descendant, 1));
96
1.33M
    self.simple_selectors.insert(0, Component::Nesting);
97
1.33M
  }
<parcel_selectors::builder::SelectorBuilder<lightningcss::selector::private::Selectors>>::add_nesting_prefix
Line
Count
Source
94
1.33M
  pub fn add_nesting_prefix(&mut self) {
95
1.33M
    self.combinators.insert(0, (Combinator::Descendant, 1));
96
1.33M
    self.simple_selectors.insert(0, Component::Nesting);
97
1.33M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilder<_>>::add_nesting_prefix
98
99
  /// Consumes the builder, producing a Selector.
100
  #[inline(always)]
101
1.56M
  pub fn build(
102
1.56M
    &mut self,
103
1.56M
    parsed_pseudo: bool,
104
1.56M
    parsed_slotted: bool,
105
1.56M
    parsed_part: bool,
106
1.56M
  ) -> (SpecificityAndFlags, Vec<Component<'i, Impl>>) {
107
    // Compute the specificity and flags.
108
1.56M
    let specificity = specificity(self.simple_selectors.iter());
109
1.56M
    let mut flags = SelectorFlags::empty();
110
1.56M
    if parsed_pseudo {
111
59.3k
      flags |= SelectorFlags::HAS_PSEUDO;
112
1.50M
    }
113
1.56M
    if parsed_slotted {
114
0
      flags |= SelectorFlags::HAS_SLOTTED;
115
1.56M
    }
116
1.56M
    if parsed_part {
117
0
      flags |= SelectorFlags::HAS_PART;
118
1.56M
    }
119
1.56M
    self.build_with_specificity_and_flags(SpecificityAndFlags { specificity, flags })
120
1.56M
  }
<parcel_selectors::builder::SelectorBuilder<lightningcss::selector::private::Selectors>>::build
Line
Count
Source
101
1.56M
  pub fn build(
102
1.56M
    &mut self,
103
1.56M
    parsed_pseudo: bool,
104
1.56M
    parsed_slotted: bool,
105
1.56M
    parsed_part: bool,
106
1.56M
  ) -> (SpecificityAndFlags, Vec<Component<'i, Impl>>) {
107
    // Compute the specificity and flags.
108
1.56M
    let specificity = specificity(self.simple_selectors.iter());
109
1.56M
    let mut flags = SelectorFlags::empty();
110
1.56M
    if parsed_pseudo {
111
59.3k
      flags |= SelectorFlags::HAS_PSEUDO;
112
1.50M
    }
113
1.56M
    if parsed_slotted {
114
0
      flags |= SelectorFlags::HAS_SLOTTED;
115
1.56M
    }
116
1.56M
    if parsed_part {
117
0
      flags |= SelectorFlags::HAS_PART;
118
1.56M
    }
119
1.56M
    self.build_with_specificity_and_flags(SpecificityAndFlags { specificity, flags })
120
1.56M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilder<_>>::build
121
122
  /// Builds with an explicit SpecificityAndFlags. This is separated from build() so
123
  /// that unit tests can pass an explicit specificity.
124
  #[inline(always)]
125
1.56M
  pub fn build_with_specificity_and_flags(
126
1.56M
    &mut self,
127
1.56M
    spec: SpecificityAndFlags,
128
1.56M
  ) -> (SpecificityAndFlags, Vec<Component<'i, Impl>>) {
129
    // Use a raw pointer to be able to call set_len despite "borrowing" the slice.
130
    // This is similar to SmallVec::drain, but we use a slice here because
131
    // we’re gonna traverse it non-linearly.
132
1.56M
    let raw_simple_selectors: *const [Component<Impl>] = &*self.simple_selectors;
133
    unsafe {
134
      // Panic-safety: if SelectorBuilderIter is not iterated to the end,
135
      // some simple selectors will safely leak.
136
1.56M
      self.simple_selectors.set_len(0)
137
    }
138
1.56M
    let (rest, current) = split_from_end(unsafe { &*raw_simple_selectors }, self.current_len);
139
1.56M
    let iter = SelectorBuilderIter {
140
1.56M
      current_simple_selectors: current.iter(),
141
1.56M
      rest_of_simple_selectors: rest,
142
1.56M
      combinators: self.combinators.drain(..).rev(),
143
1.56M
    };
144
145
1.56M
    (spec, iter.collect())
146
1.56M
  }
<parcel_selectors::builder::SelectorBuilder<lightningcss::selector::private::Selectors>>::build_with_specificity_and_flags
Line
Count
Source
125
1.56M
  pub fn build_with_specificity_and_flags(
126
1.56M
    &mut self,
127
1.56M
    spec: SpecificityAndFlags,
128
1.56M
  ) -> (SpecificityAndFlags, Vec<Component<'i, Impl>>) {
129
    // Use a raw pointer to be able to call set_len despite "borrowing" the slice.
130
    // This is similar to SmallVec::drain, but we use a slice here because
131
    // we’re gonna traverse it non-linearly.
132
1.56M
    let raw_simple_selectors: *const [Component<Impl>] = &*self.simple_selectors;
133
    unsafe {
134
      // Panic-safety: if SelectorBuilderIter is not iterated to the end,
135
      // some simple selectors will safely leak.
136
1.56M
      self.simple_selectors.set_len(0)
137
    }
138
1.56M
    let (rest, current) = split_from_end(unsafe { &*raw_simple_selectors }, self.current_len);
139
1.56M
    let iter = SelectorBuilderIter {
140
1.56M
      current_simple_selectors: current.iter(),
141
1.56M
      rest_of_simple_selectors: rest,
142
1.56M
      combinators: self.combinators.drain(..).rev(),
143
1.56M
    };
144
145
1.56M
    (spec, iter.collect())
146
1.56M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilder<_>>::build_with_specificity_and_flags
147
}
148
149
struct SelectorBuilderIter<'a, 'i, Impl: SelectorImpl<'i>> {
150
  current_simple_selectors: slice::Iter<'a, Component<'i, Impl>>,
151
  rest_of_simple_selectors: &'a [Component<'i, Impl>],
152
  combinators: iter::Rev<smallvec::Drain<'a, [(Combinator, usize); 16]>>,
153
}
154
155
impl<'a, 'i, Impl: SelectorImpl<'i>> ExactSizeIterator for SelectorBuilderIter<'a, 'i, Impl> {
156
3.13M
  fn len(&self) -> usize {
157
3.13M
    self.current_simple_selectors.len() + self.rest_of_simple_selectors.len() + self.combinators.len()
158
3.13M
  }
<parcel_selectors::builder::SelectorBuilderIter<lightningcss::selector::private::Selectors> as core::iter::traits::exact_size::ExactSizeIterator>::len
Line
Count
Source
156
3.13M
  fn len(&self) -> usize {
157
3.13M
    self.current_simple_selectors.len() + self.rest_of_simple_selectors.len() + self.combinators.len()
158
3.13M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilderIter<_> as core::iter::traits::exact_size::ExactSizeIterator>::len
159
}
160
161
impl<'a, 'i, Impl: SelectorImpl<'i>> Iterator for SelectorBuilderIter<'a, 'i, Impl> {
162
  type Item = Component<'i, Impl>;
163
  #[inline(always)]
164
7.27M
  fn next(&mut self) -> Option<Self::Item> {
165
7.27M
    if let Some(simple_selector_ref) = self.current_simple_selectors.next() {
166
      // Move a simple selector out of this slice iterator.
167
      // This is safe because we’ve called SmallVec::set_len(0) above,
168
      // so SmallVec::drop won’t drop this simple selector.
169
3.94M
      unsafe { Some(ptr::read(simple_selector_ref)) }
170
    } else {
171
3.33M
      self.combinators.next().map(|(combinator, len)| {
172
1.76M
        let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
173
1.76M
        self.rest_of_simple_selectors = rest;
174
1.76M
        self.current_simple_selectors = current.iter();
175
1.76M
        Component::Combinator(combinator)
176
1.76M
      })
<parcel_selectors::builder::SelectorBuilderIter<lightningcss::selector::private::Selectors> as core::iter::traits::iterator::Iterator>::next::{closure#0}
Line
Count
Source
171
1.76M
      self.combinators.next().map(|(combinator, len)| {
172
1.76M
        let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
173
1.76M
        self.rest_of_simple_selectors = rest;
174
1.76M
        self.current_simple_selectors = current.iter();
175
1.76M
        Component::Combinator(combinator)
176
1.76M
      })
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilderIter<_> as core::iter::traits::iterator::Iterator>::next::{closure#0}
177
    }
178
7.27M
  }
<parcel_selectors::builder::SelectorBuilderIter<lightningcss::selector::private::Selectors> as core::iter::traits::iterator::Iterator>::next
Line
Count
Source
164
7.27M
  fn next(&mut self) -> Option<Self::Item> {
165
7.27M
    if let Some(simple_selector_ref) = self.current_simple_selectors.next() {
166
      // Move a simple selector out of this slice iterator.
167
      // This is safe because we’ve called SmallVec::set_len(0) above,
168
      // so SmallVec::drop won’t drop this simple selector.
169
3.94M
      unsafe { Some(ptr::read(simple_selector_ref)) }
170
    } else {
171
3.33M
      self.combinators.next().map(|(combinator, len)| {
172
        let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
173
        self.rest_of_simple_selectors = rest;
174
        self.current_simple_selectors = current.iter();
175
        Component::Combinator(combinator)
176
      })
177
    }
178
7.27M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilderIter<_> as core::iter::traits::iterator::Iterator>::next
179
180
1.56M
  fn size_hint(&self) -> (usize, Option<usize>) {
181
1.56M
    (self.len(), Some(self.len()))
182
1.56M
  }
<parcel_selectors::builder::SelectorBuilderIter<lightningcss::selector::private::Selectors> as core::iter::traits::iterator::Iterator>::size_hint
Line
Count
Source
180
1.56M
  fn size_hint(&self) -> (usize, Option<usize>) {
181
1.56M
    (self.len(), Some(self.len()))
182
1.56M
  }
Unexecuted instantiation: <parcel_selectors::builder::SelectorBuilderIter<_> as core::iter::traits::iterator::Iterator>::size_hint
183
}
184
185
3.33M
fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
186
3.33M
  s.split_at(s.len() - at)
187
3.33M
}
parcel_selectors::builder::split_from_end::<parcel_selectors::parser::Component<lightningcss::selector::private::Selectors>>
Line
Count
Source
185
3.33M
fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
186
3.33M
  s.split_at(s.len() - at)
187
3.33M
}
Unexecuted instantiation: parcel_selectors::builder::split_from_end::<_>
188
189
bitflags! {
190
    /// Flags that indicate at which point of parsing a selector are we.
191
    #[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Hash)]
192
    pub (crate) struct SelectorFlags : u8 {
193
        const HAS_PSEUDO = 1 << 0;
194
        const HAS_SLOTTED = 1 << 1;
195
        const HAS_PART = 1 << 2;
196
    }
197
}
198
199
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
200
pub struct SpecificityAndFlags {
201
  /// There are two free bits here, since we use ten bits for each specificity
202
  /// kind (id, class, element).
203
  pub(crate) specificity: u32,
204
  /// There's padding after this field due to the size of the flags.
205
  pub(crate) flags: SelectorFlags,
206
}
207
208
impl SpecificityAndFlags {
209
  #[inline]
210
24.6k
  pub fn specificity(&self) -> u32 {
211
24.6k
    self.specificity
212
24.6k
  }
<parcel_selectors::builder::SpecificityAndFlags>::specificity
Line
Count
Source
210
24.6k
  pub fn specificity(&self) -> u32 {
211
24.6k
    self.specificity
212
24.6k
  }
Unexecuted instantiation: <parcel_selectors::builder::SpecificityAndFlags>::specificity
213
214
  #[inline]
215
0
  pub fn has_pseudo_element(&self) -> bool {
216
0
    self.flags.intersects(SelectorFlags::HAS_PSEUDO)
217
0
  }
218
219
  #[inline]
220
0
  pub fn is_slotted(&self) -> bool {
221
0
    self.flags.intersects(SelectorFlags::HAS_SLOTTED)
222
0
  }
223
224
  #[inline]
225
0
  pub fn is_part(&self) -> bool {
226
0
    self.flags.intersects(SelectorFlags::HAS_PART)
227
0
  }
228
}
229
230
const MAX_10BIT: u32 = (1u32 << 10) - 1;
231
232
#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
233
struct Specificity {
234
  id_selectors: u32,
235
  class_like_selectors: u32,
236
  element_selectors: u32,
237
}
238
impl Add for Specificity {
239
  type Output = Specificity;
240
241
0
  fn add(self, rhs: Self) -> Self::Output {
242
0
    Specificity {
243
0
      id_selectors: self.id_selectors + rhs.id_selectors,
244
0
      class_like_selectors: self.class_like_selectors + rhs.class_like_selectors,
245
0
      element_selectors: self.element_selectors + rhs.element_selectors,
246
0
    }
247
0
  }
248
}
249
impl AddAssign for Specificity {
250
3.49k
  fn add_assign(&mut self, rhs: Self) {
251
3.49k
    self.id_selectors += rhs.id_selectors;
252
3.49k
    self.element_selectors += rhs.element_selectors;
253
3.49k
    self.class_like_selectors += rhs.class_like_selectors;
254
3.49k
  }
255
}
256
257
impl From<u32> for Specificity {
258
  #[inline]
259
3.49k
  fn from(value: u32) -> Specificity {
260
3.49k
    assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
261
3.49k
    Specificity {
262
3.49k
      id_selectors: value >> 20,
263
3.49k
      class_like_selectors: (value >> 10) & MAX_10BIT,
264
3.49k
      element_selectors: value & MAX_10BIT,
265
3.49k
    }
266
3.49k
  }
<parcel_selectors::builder::Specificity as core::convert::From<u32>>::from
Line
Count
Source
259
3.49k
  fn from(value: u32) -> Specificity {
260
3.49k
    assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
261
3.49k
    Specificity {
262
3.49k
      id_selectors: value >> 20,
263
3.49k
      class_like_selectors: (value >> 10) & MAX_10BIT,
264
3.49k
      element_selectors: value & MAX_10BIT,
265
3.49k
    }
266
3.49k
  }
Unexecuted instantiation: <parcel_selectors::builder::Specificity as core::convert::From<u32>>::from
267
}
268
269
impl From<Specificity> for u32 {
270
  #[inline]
271
1.56M
  fn from(specificity: Specificity) -> u32 {
272
1.56M
    cmp::min(specificity.id_selectors, MAX_10BIT) << 20
273
1.56M
      | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10
274
1.56M
      | cmp::min(specificity.element_selectors, MAX_10BIT)
275
1.56M
  }
<u32 as core::convert::From<parcel_selectors::builder::Specificity>>::from
Line
Count
Source
271
1.56M
  fn from(specificity: Specificity) -> u32 {
272
1.56M
    cmp::min(specificity.id_selectors, MAX_10BIT) << 20
273
1.56M
      | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10
274
1.56M
      | cmp::min(specificity.element_selectors, MAX_10BIT)
275
1.56M
  }
Unexecuted instantiation: <u32 as core::convert::From<parcel_selectors::builder::Specificity>>::from
276
}
277
278
1.56M
fn specificity<'i, Impl>(iter: slice::Iter<Component<'i, Impl>>) -> u32
279
1.56M
where
280
1.56M
  Impl: SelectorImpl<'i>,
281
{
282
1.56M
  complex_selector_specificity(iter).into()
283
1.56M
}
parcel_selectors::builder::specificity::<lightningcss::selector::private::Selectors>
Line
Count
Source
278
1.56M
fn specificity<'i, Impl>(iter: slice::Iter<Component<'i, Impl>>) -> u32
279
1.56M
where
280
1.56M
  Impl: SelectorImpl<'i>,
281
{
282
1.56M
  complex_selector_specificity(iter).into()
283
1.56M
}
Unexecuted instantiation: parcel_selectors::builder::specificity::<_>
284
285
1.56M
fn complex_selector_specificity<'i, Impl>(iter: slice::Iter<Component<'i, Impl>>) -> Specificity
286
1.56M
where
287
1.56M
  Impl: SelectorImpl<'i>,
288
{
289
3.94M
  fn simple_selector_specificity<'i, Impl>(simple_selector: &Component<'i, Impl>, specificity: &mut Specificity)
290
3.94M
  where
291
3.94M
    Impl: SelectorImpl<'i>,
292
  {
293
3.94M
    match *simple_selector {
294
      Component::Combinator(..) => {
295
0
        unreachable!("Found combinator in simple selectors vector?");
296
      }
297
      Component::Part(..) | Component::PseudoElement(..) | Component::LocalName(..) => {
298
1.86M
        specificity.element_selectors += 1
299
      }
300
0
      Component::Slotted(ref selector) => {
301
0
        specificity.element_selectors += 1;
302
0
        // Note that due to the way ::slotted works we only compete with
303
0
        // other ::slotted rules, so the above rule doesn't really
304
0
        // matter, but we do it still for consistency with other
305
0
        // pseudo-elements.
306
0
        //
307
0
        // See: https://github.com/w3c/csswg-drafts/issues/1915
308
0
        *specificity += Specificity::from(selector.specificity());
309
0
      }
310
31
      Component::Host(ref selector) => {
311
31
        specificity.class_like_selectors += 1;
312
31
        if let Some(ref selector) = *selector {
313
0
          // See: https://github.com/w3c/csswg-drafts/issues/1915
314
0
          *specificity += Specificity::from(selector.specificity());
315
31
        }
316
      }
317
20.1k
      Component::ID(..) => {
318
20.1k
        specificity.id_selectors += 1;
319
20.1k
      }
320
      Component::Class(..)
321
      | Component::AttributeInNoNamespace { .. }
322
      | Component::AttributeInNoNamespaceExists { .. }
323
      | Component::AttributeOther(..)
324
      | Component::Root
325
      | Component::Empty
326
      | Component::Scope
327
      | Component::Nth(..)
328
648k
      | Component::NonTSPseudoClass(..) => {
329
648k
        specificity.class_like_selectors += 1;
330
648k
      }
331
0
      Component::NthOf(ref nth_of_data) => {
332
        // https://drafts.csswg.org/selectors/#specificity-rules:
333
        //
334
        //     The specificity of the :nth-last-child() pseudo-class,
335
        //     like the :nth-child() pseudo-class, combines the
336
        //     specificity of a regular pseudo-class with that of its
337
        //     selector argument S.
338
0
        specificity.class_like_selectors += 1;
339
0
        let mut max = 0;
340
0
        for selector in nth_of_data.selectors() {
341
0
          max = std::cmp::max(selector.specificity(), max);
342
0
        }
343
0
        *specificity += Specificity::from(max);
344
      }
345
2.82k
      Component::Negation(ref list) | Component::Is(ref list) | Component::Any(_, ref list) => {
346
        // https://drafts.csswg.org/selectors/#specificity-rules:
347
        //
348
        //     The specificity of an :is() pseudo-class is replaced by the
349
        //     specificity of the most specific complex selector in its
350
        //     selector list argument.
351
3.49k
        let mut max = 0;
352
24.6k
        for selector in &**list {
353
24.6k
          max = std::cmp::max(selector.specificity(), max);
354
24.6k
        }
355
3.49k
        *specificity += Specificity::from(max);
356
      }
357
      Component::Where(..)
358
      | Component::Has(..)
359
      | Component::ExplicitUniversalType
360
      | Component::ExplicitAnyNamespace
361
      | Component::ExplicitNoNamespace
362
      | Component::DefaultNamespace(..)
363
22.0k
      | Component::Namespace(..) => {
364
22.0k
        // Does not affect specificity
365
22.0k
      }
366
1.38M
      Component::Nesting => {
367
1.38M
        // TODO
368
1.38M
      }
369
    }
370
3.94M
  }
parcel_selectors::builder::complex_selector_specificity::simple_selector_specificity::<lightningcss::selector::private::Selectors>
Line
Count
Source
289
3.94M
  fn simple_selector_specificity<'i, Impl>(simple_selector: &Component<'i, Impl>, specificity: &mut Specificity)
290
3.94M
  where
291
3.94M
    Impl: SelectorImpl<'i>,
292
  {
293
3.94M
    match *simple_selector {
294
      Component::Combinator(..) => {
295
0
        unreachable!("Found combinator in simple selectors vector?");
296
      }
297
      Component::Part(..) | Component::PseudoElement(..) | Component::LocalName(..) => {
298
1.86M
        specificity.element_selectors += 1
299
      }
300
0
      Component::Slotted(ref selector) => {
301
0
        specificity.element_selectors += 1;
302
0
        // Note that due to the way ::slotted works we only compete with
303
0
        // other ::slotted rules, so the above rule doesn't really
304
0
        // matter, but we do it still for consistency with other
305
0
        // pseudo-elements.
306
0
        //
307
0
        // See: https://github.com/w3c/csswg-drafts/issues/1915
308
0
        *specificity += Specificity::from(selector.specificity());
309
0
      }
310
31
      Component::Host(ref selector) => {
311
31
        specificity.class_like_selectors += 1;
312
31
        if let Some(ref selector) = *selector {
313
0
          // See: https://github.com/w3c/csswg-drafts/issues/1915
314
0
          *specificity += Specificity::from(selector.specificity());
315
31
        }
316
      }
317
20.1k
      Component::ID(..) => {
318
20.1k
        specificity.id_selectors += 1;
319
20.1k
      }
320
      Component::Class(..)
321
      | Component::AttributeInNoNamespace { .. }
322
      | Component::AttributeInNoNamespaceExists { .. }
323
      | Component::AttributeOther(..)
324
      | Component::Root
325
      | Component::Empty
326
      | Component::Scope
327
      | Component::Nth(..)
328
648k
      | Component::NonTSPseudoClass(..) => {
329
648k
        specificity.class_like_selectors += 1;
330
648k
      }
331
0
      Component::NthOf(ref nth_of_data) => {
332
        // https://drafts.csswg.org/selectors/#specificity-rules:
333
        //
334
        //     The specificity of the :nth-last-child() pseudo-class,
335
        //     like the :nth-child() pseudo-class, combines the
336
        //     specificity of a regular pseudo-class with that of its
337
        //     selector argument S.
338
0
        specificity.class_like_selectors += 1;
339
0
        let mut max = 0;
340
0
        for selector in nth_of_data.selectors() {
341
0
          max = std::cmp::max(selector.specificity(), max);
342
0
        }
343
0
        *specificity += Specificity::from(max);
344
      }
345
2.82k
      Component::Negation(ref list) | Component::Is(ref list) | Component::Any(_, ref list) => {
346
        // https://drafts.csswg.org/selectors/#specificity-rules:
347
        //
348
        //     The specificity of an :is() pseudo-class is replaced by the
349
        //     specificity of the most specific complex selector in its
350
        //     selector list argument.
351
3.49k
        let mut max = 0;
352
24.6k
        for selector in &**list {
353
24.6k
          max = std::cmp::max(selector.specificity(), max);
354
24.6k
        }
355
3.49k
        *specificity += Specificity::from(max);
356
      }
357
      Component::Where(..)
358
      | Component::Has(..)
359
      | Component::ExplicitUniversalType
360
      | Component::ExplicitAnyNamespace
361
      | Component::ExplicitNoNamespace
362
      | Component::DefaultNamespace(..)
363
22.0k
      | Component::Namespace(..) => {
364
22.0k
        // Does not affect specificity
365
22.0k
      }
366
1.38M
      Component::Nesting => {
367
1.38M
        // TODO
368
1.38M
      }
369
    }
370
3.94M
  }
Unexecuted instantiation: parcel_selectors::builder::complex_selector_specificity::simple_selector_specificity::<_>
371
372
1.56M
  let mut specificity = Default::default();
373
3.94M
  for simple_selector in iter {
374
3.94M
    simple_selector_specificity(&simple_selector, &mut specificity);
375
3.94M
  }
376
1.56M
  specificity
377
1.56M
}
parcel_selectors::builder::complex_selector_specificity::<lightningcss::selector::private::Selectors>
Line
Count
Source
285
1.56M
fn complex_selector_specificity<'i, Impl>(iter: slice::Iter<Component<'i, Impl>>) -> Specificity
286
1.56M
where
287
1.56M
  Impl: SelectorImpl<'i>,
288
{
289
  fn simple_selector_specificity<'i, Impl>(simple_selector: &Component<'i, Impl>, specificity: &mut Specificity)
290
  where
291
    Impl: SelectorImpl<'i>,
292
  {
293
    match *simple_selector {
294
      Component::Combinator(..) => {
295
        unreachable!("Found combinator in simple selectors vector?");
296
      }
297
      Component::Part(..) | Component::PseudoElement(..) | Component::LocalName(..) => {
298
        specificity.element_selectors += 1
299
      }
300
      Component::Slotted(ref selector) => {
301
        specificity.element_selectors += 1;
302
        // Note that due to the way ::slotted works we only compete with
303
        // other ::slotted rules, so the above rule doesn't really
304
        // matter, but we do it still for consistency with other
305
        // pseudo-elements.
306
        //
307
        // See: https://github.com/w3c/csswg-drafts/issues/1915
308
        *specificity += Specificity::from(selector.specificity());
309
      }
310
      Component::Host(ref selector) => {
311
        specificity.class_like_selectors += 1;
312
        if let Some(ref selector) = *selector {
313
          // See: https://github.com/w3c/csswg-drafts/issues/1915
314
          *specificity += Specificity::from(selector.specificity());
315
        }
316
      }
317
      Component::ID(..) => {
318
        specificity.id_selectors += 1;
319
      }
320
      Component::Class(..)
321
      | Component::AttributeInNoNamespace { .. }
322
      | Component::AttributeInNoNamespaceExists { .. }
323
      | Component::AttributeOther(..)
324
      | Component::Root
325
      | Component::Empty
326
      | Component::Scope
327
      | Component::Nth(..)
328
      | Component::NonTSPseudoClass(..) => {
329
        specificity.class_like_selectors += 1;
330
      }
331
      Component::NthOf(ref nth_of_data) => {
332
        // https://drafts.csswg.org/selectors/#specificity-rules:
333
        //
334
        //     The specificity of the :nth-last-child() pseudo-class,
335
        //     like the :nth-child() pseudo-class, combines the
336
        //     specificity of a regular pseudo-class with that of its
337
        //     selector argument S.
338
        specificity.class_like_selectors += 1;
339
        let mut max = 0;
340
        for selector in nth_of_data.selectors() {
341
          max = std::cmp::max(selector.specificity(), max);
342
        }
343
        *specificity += Specificity::from(max);
344
      }
345
      Component::Negation(ref list) | Component::Is(ref list) | Component::Any(_, ref list) => {
346
        // https://drafts.csswg.org/selectors/#specificity-rules:
347
        //
348
        //     The specificity of an :is() pseudo-class is replaced by the
349
        //     specificity of the most specific complex selector in its
350
        //     selector list argument.
351
        let mut max = 0;
352
        for selector in &**list {
353
          max = std::cmp::max(selector.specificity(), max);
354
        }
355
        *specificity += Specificity::from(max);
356
      }
357
      Component::Where(..)
358
      | Component::Has(..)
359
      | Component::ExplicitUniversalType
360
      | Component::ExplicitAnyNamespace
361
      | Component::ExplicitNoNamespace
362
      | Component::DefaultNamespace(..)
363
      | Component::Namespace(..) => {
364
        // Does not affect specificity
365
      }
366
      Component::Nesting => {
367
        // TODO
368
      }
369
    }
370
  }
371
372
1.56M
  let mut specificity = Default::default();
373
3.94M
  for simple_selector in iter {
374
3.94M
    simple_selector_specificity(&simple_selector, &mut specificity);
375
3.94M
  }
376
1.56M
  specificity
377
1.56M
}
Unexecuted instantiation: parcel_selectors::builder::complex_selector_specificity::<_>