/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::<_> |