1use crate::{
62 declaration::DeclarationBlock,
63 media_query::{MediaFeature, MediaFeatureValue, MediaList, MediaQuery},
64 parser::DefaultAtRule,
65 properties::{
66 custom::{EnvironmentVariable, Function, TokenList, TokenOrValue, Variable},
67 Property,
68 },
69 rules::{supports::SupportsCondition, CssRule, CssRuleList},
70 selector::{Selector, SelectorList},
71 stylesheet::StyleSheet,
72 values::{
73 angle::Angle,
74 color::CssColor,
75 ident::{CustomIdent, DashedIdent},
76 image::Image,
77 length::LengthValue,
78 ratio::Ratio,
79 resolution::Resolution,
80 time::Time,
81 url::Url,
82 },
83};
84use bitflags::bitflags;
85use smallvec::SmallVec;
86
87pub(crate) use lightningcss_derive::Visit;
88
89bitflags! {
90 #[derive(PartialEq, Eq, Clone, Copy)]
95 pub struct VisitTypes: u32 {
96 const RULES = 1 << 0;
98 const PROPERTIES = 1 << 1;
100 const URLS = 1 << 2;
102 const COLORS = 1 << 3;
104 const IMAGES = 1 << 4;
106 const LENGTHS = 1 << 5;
108 const ANGLES = 1 << 6;
110 const RATIOS = 1 << 7;
112 const RESOLUTIONS = 1 << 8;
114 const TIMES = 1 << 9;
116 const CUSTOM_IDENTS = 1 << 10;
118 const DASHED_IDENTS = 1 << 11;
120 const VARIABLES = 1 << 12;
122 const ENVIRONMENT_VARIABLES = 1 << 13;
124 const MEDIA_QUERIES = 1 << 14;
126 const SUPPORTS_CONDITIONS = 1 << 15;
128 const SELECTORS = 1 << 16;
130 const FUNCTIONS = 1 << 17;
132 const TOKENS = 1 << 18;
134 }
135}
136
137#[macro_export]
139macro_rules! visit_types {
140 ($( $flag: ident )|+) => {
141 $crate::visitor::VisitTypes::from_bits_truncate(0 $(| $crate::visitor::VisitTypes::$flag.bits())+)
142 }
143}
144
145pub trait Visitor<'i, T: Visit<'i, T, Self> = DefaultAtRule> {
147 type Error;
149
150 fn visit_types(&self) -> VisitTypes;
153
154 #[inline]
156 fn visit_stylesheet<'o>(&mut self, stylesheet: &mut StyleSheet<'i, 'o, T>) -> Result<(), Self::Error> {
157 stylesheet.visit_children(self)
158 }
159
160 #[inline]
162 fn visit_rule_list(&mut self, rules: &mut CssRuleList<'i, T>) -> Result<(), Self::Error> {
163 rules.visit_children(self)
164 }
165
166 #[inline]
168 fn visit_rule(&mut self, rule: &mut CssRule<'i, T>) -> Result<(), Self::Error> {
169 rule.visit_children(self)
170 }
171
172 #[inline]
174 fn visit_declaration_block(&mut self, decls: &mut DeclarationBlock<'i>) -> Result<(), Self::Error> {
175 decls.visit_children(self)
176 }
177
178 #[inline]
180 fn visit_property(&mut self, property: &mut Property<'i>) -> Result<(), Self::Error> {
181 property.visit_children(self)
182 }
183
184 fn visit_url(&mut self, _url: &mut Url<'i>) -> Result<(), Self::Error> {
186 Ok(())
187 }
188
189 #[allow(unused_variables)]
191 fn visit_color(&mut self, color: &mut CssColor) -> Result<(), Self::Error> {
192 Ok(())
193 }
194
195 #[inline]
197 fn visit_image(&mut self, image: &mut Image<'i>) -> Result<(), Self::Error> {
198 image.visit_children(self)
199 }
200
201 #[allow(unused_variables)]
203 fn visit_length(&mut self, length: &mut LengthValue) -> Result<(), Self::Error> {
204 Ok(())
205 }
206
207 #[allow(unused_variables)]
209 fn visit_angle(&mut self, angle: &mut Angle) -> Result<(), Self::Error> {
210 Ok(())
211 }
212
213 #[allow(unused_variables)]
215 fn visit_ratio(&mut self, ratio: &mut Ratio) -> Result<(), Self::Error> {
216 Ok(())
217 }
218
219 #[allow(unused_variables)]
221 fn visit_resolution(&mut self, resolution: &mut Resolution) -> Result<(), Self::Error> {
222 Ok(())
223 }
224
225 #[allow(unused_variables)]
227 fn visit_time(&mut self, time: &mut Time) -> Result<(), Self::Error> {
228 Ok(())
229 }
230
231 #[allow(unused_variables)]
233 fn visit_custom_ident(&mut self, ident: &mut CustomIdent) -> Result<(), Self::Error> {
234 Ok(())
235 }
236
237 #[allow(unused_variables)]
239 fn visit_dashed_ident(&mut self, ident: &mut DashedIdent) -> Result<(), Self::Error> {
240 Ok(())
241 }
242
243 #[inline]
245 fn visit_variable(&mut self, var: &mut Variable<'i>) -> Result<(), Self::Error> {
246 var.visit_children(self)
247 }
248
249 #[inline]
251 fn visit_environment_variable(&mut self, env: &mut EnvironmentVariable<'i>) -> Result<(), Self::Error> {
252 env.visit_children(self)
253 }
254
255 #[inline]
257 fn visit_media_list(&mut self, media: &mut MediaList<'i>) -> Result<(), Self::Error> {
258 media.visit_children(self)
259 }
260
261 #[inline]
263 fn visit_media_query(&mut self, query: &mut MediaQuery<'i>) -> Result<(), Self::Error> {
264 query.visit_children(self)
265 }
266
267 #[inline]
269 fn visit_media_feature(&mut self, feature: &mut MediaFeature<'i>) -> Result<(), Self::Error> {
270 feature.visit_children(self)
271 }
272
273 #[inline]
275 fn visit_media_feature_value(&mut self, value: &mut MediaFeatureValue<'i>) -> Result<(), Self::Error> {
276 value.visit_children(self)
277 }
278
279 #[inline]
281 fn visit_supports_condition(&mut self, condition: &mut SupportsCondition<'i>) -> Result<(), Self::Error> {
282 condition.visit_children(self)
283 }
284
285 #[inline]
287 fn visit_selector_list(&mut self, selectors: &mut SelectorList<'i>) -> Result<(), Self::Error> {
288 selectors.visit_children(self)
289 }
290
291 #[allow(unused_variables)]
293 fn visit_selector(&mut self, selector: &mut Selector<'i>) -> Result<(), Self::Error> {
294 Ok(())
295 }
296
297 #[inline]
299 fn visit_function(&mut self, function: &mut Function<'i>) -> Result<(), Self::Error> {
300 function.visit_children(self)
301 }
302
303 #[inline]
305 fn visit_token_list(&mut self, tokens: &mut TokenList<'i>) -> Result<(), Self::Error> {
306 tokens.visit_children(self)
307 }
308
309 #[inline]
311 fn visit_token(&mut self, token: &mut TokenOrValue<'i>) -> Result<(), Self::Error> {
312 token.visit_children(self)
313 }
314}
315
316pub trait Visit<'i, T: Visit<'i, T, V>, V: ?Sized + Visitor<'i, T>> {
318 const CHILD_TYPES: VisitTypes;
322
323 #[inline]
326 fn visit(&mut self, visitor: &mut V) -> Result<(), V::Error> {
327 self.visit_children(visitor)
328 }
329
330 fn visit_children(&mut self, visitor: &mut V) -> Result<(), V::Error>;
332}
333
334impl<'i, T: Visit<'i, T, V>, V: ?Sized + Visitor<'i, T>, U: Visit<'i, T, V>> Visit<'i, T, V> for Option<U> {
335 const CHILD_TYPES: VisitTypes = U::CHILD_TYPES;
336
337 fn visit(&mut self, visitor: &mut V) -> Result<(), V::Error> {
338 if let Some(v) = self {
339 v.visit(visitor)
340 } else {
341 Ok(())
342 }
343 }
344
345 fn visit_children(&mut self, visitor: &mut V) -> Result<(), V::Error> {
346 if let Some(v) = self {
347 v.visit_children(visitor)
348 } else {
349 Ok(())
350 }
351 }
352}
353
354impl<'i, T: Visit<'i, T, V>, V: ?Sized + Visitor<'i, T>, U: Visit<'i, T, V>> Visit<'i, T, V> for Box<U> {
355 const CHILD_TYPES: VisitTypes = U::CHILD_TYPES;
356
357 fn visit(&mut self, visitor: &mut V) -> Result<(), V::Error> {
358 self.as_mut().visit(visitor)
359 }
360
361 fn visit_children(&mut self, visitor: &mut V) -> Result<(), V::Error> {
362 self.as_mut().visit_children(visitor)
363 }
364}
365
366impl<'i, T: Visit<'i, T, V>, V: ?Sized + Visitor<'i, T>, U: Visit<'i, T, V>> Visit<'i, T, V> for Vec<U> {
367 const CHILD_TYPES: VisitTypes = U::CHILD_TYPES;
368
369 fn visit(&mut self, visitor: &mut V) -> Result<(), V::Error> {
370 self.iter_mut().try_for_each(|v| v.visit(visitor))
371 }
372
373 fn visit_children(&mut self, visitor: &mut V) -> Result<(), V::Error> {
374 self.iter_mut().try_for_each(|v| v.visit_children(visitor))
375 }
376}
377
378impl<'i, A: smallvec::Array<Item = U>, U: Visit<'i, T, V>, T: Visit<'i, T, V>, V: ?Sized + Visitor<'i, T>>
379 Visit<'i, T, V> for SmallVec<A>
380{
381 const CHILD_TYPES: VisitTypes = U::CHILD_TYPES;
382
383 fn visit(&mut self, visitor: &mut V) -> Result<(), V::Error> {
384 self.iter_mut().try_for_each(|v| v.visit(visitor))
385 }
386
387 fn visit_children(&mut self, visitor: &mut V) -> Result<(), V::Error> {
388 self.iter_mut().try_for_each(|v| v.visit_children(visitor))
389 }
390}
391
392macro_rules! impl_visit {
393 ($t: ty) => {
394 impl<'i, V: ?Sized + Visitor<'i, T>, T: Visit<'i, T, V>> Visit<'i, T, V> for $t {
395 const CHILD_TYPES: VisitTypes = VisitTypes::empty();
396
397 fn visit_children(&mut self, _: &mut V) -> Result<(), V::Error> {
398 Ok(())
399 }
400 }
401 };
402}
403
404impl_visit!(u8);
405impl_visit!(u16);
406impl_visit!(u32);
407impl_visit!(i32);
408impl_visit!(f32);
409impl_visit!(bool);
410impl_visit!(char);
411impl_visit!(str);
412impl_visit!(String);
413impl_visit!((f32, f32));