use crate::{
media_query::MediaQuery,
parser::DefaultAtRule,
properties::{
custom::{Function, TokenOrValue, Variable},
Property,
},
rules::{supports::SupportsCondition, CssRule},
selector::Selector,
values::{
angle::Angle,
color::CssColor,
ident::{CustomIdent, DashedIdent},
image::Image,
length::LengthValue,
ratio::Ratio,
resolution::Resolution,
time::Time,
url::Url,
},
};
use bitflags::bitflags;
use smallvec::SmallVec;
pub(crate) use lightningcss_derive::Visit;
bitflags! {
pub struct VisitTypes: u32 {
const RULES = 1 << 0;
const PROPERTIES = 1 << 1;
const URLS = 1 << 2;
const COLORS = 1 << 3;
const IMAGES = 1 << 4;
const LENGTHS = 1 << 5;
const ANGLES = 1 << 6;
const RATIOS = 1 << 7;
const RESOLUTIONS = 1 << 8;
const TIMES = 1 << 9;
const CUSTOM_IDENTS = 1 << 10;
const DASHED_IDENTS = 1 << 11;
const VARIABLES = 1 << 12;
const MEDIA_QUERIES = 1 << 13;
const SUPPORTS_CONDITIONS = 1 << 14;
const SELECTORS = 1 << 15;
const FUNCTIONS = 1 << 16;
const TOKENS = 1 << 17;
}
}
#[macro_export]
macro_rules! visit_types {
($( $flag: ident )|+) => {
VisitTypes::from_bits_truncate(0 $(| VisitTypes::$flag.bits())+)
}
}
pub trait Visitor<'i, T: Visit<'i, T, Self> = DefaultAtRule>: Sized {
const TYPES: VisitTypes;
#[inline]
fn visit_rule(&mut self, rule: &mut CssRule<'i, T>) {
rule.visit_children(self)
}
#[inline]
fn visit_property(&mut self, property: &mut Property<'i>) {
property.visit_children(self)
}
fn visit_url(&mut self, _url: &mut Url<'i>) {}
#[allow(unused_variables)]
fn visit_color(&mut self, color: &mut CssColor) {}
#[inline]
fn visit_image(&mut self, image: &mut Image<'i>) {
image.visit_children(self)
}
#[allow(unused_variables)]
fn visit_length(&mut self, length: &mut LengthValue) {}
#[allow(unused_variables)]
fn visit_angle(&mut self, angle: &mut Angle) {}
#[allow(unused_variables)]
fn visit_ratio(&mut self, ratio: &mut Ratio) {}
#[allow(unused_variables)]
fn visit_resolution(&mut self, resolution: &mut Resolution) {}
#[allow(unused_variables)]
fn visit_time(&mut self, time: &mut Time) {}
#[allow(unused_variables)]
fn visit_custom_ident(&mut self, ident: &mut CustomIdent) {}
#[allow(unused_variables)]
fn visit_dashed_ident(&mut self, ident: &mut DashedIdent) {}
#[inline]
fn visit_variable(&mut self, var: &mut Variable<'i>) {
var.visit_children(self)
}
#[inline]
fn visit_media_query(&mut self, query: &mut MediaQuery<'i>) {
query.visit_children(self)
}
#[inline]
fn visit_supports_condition(&mut self, condition: &mut SupportsCondition<'i>) {
condition.visit_children(self)
}
#[allow(unused_variables)]
fn visit_selector(&mut self, selector: &mut Selector<'i>) {}
#[inline]
fn visit_function(&mut self, function: &mut Function<'i>) {
function.visit_children(self)
}
#[inline]
fn visit_token(&mut self, token: &mut TokenOrValue<'i>) {
token.visit_children(self)
}
}
pub trait Visit<'i, T: Visit<'i, T, V>, V: Visitor<'i, T>> {
const CHILD_TYPES: VisitTypes;
#[inline]
fn visit(&mut self, visitor: &mut V) {
self.visit_children(visitor)
}
fn visit_children(&mut self, visitor: &mut V);
}
impl<'i, T: Visit<'i, T, V>, V: Visitor<'i, T>, U: Visit<'i, T, V>> Visit<'i, T, V> for Option<U> {
const CHILD_TYPES: VisitTypes = U::CHILD_TYPES;
fn visit(&mut self, visitor: &mut V) {
if let Some(v) = self {
v.visit(visitor)
}
}
fn visit_children(&mut self, visitor: &mut V) {
if let Some(v) = self {
v.visit_children(visitor)
}
}
}
impl<'i, T: Visit<'i, T, V>, V: Visitor<'i, T>, U: Visit<'i, T, V>> Visit<'i, T, V> for Box<U> {
const CHILD_TYPES: VisitTypes = U::CHILD_TYPES;
fn visit(&mut self, visitor: &mut V) {
self.as_mut().visit(visitor)
}
fn visit_children(&mut self, visitor: &mut V) {
self.as_mut().visit_children(visitor)
}
}
impl<'i, T: Visit<'i, T, V>, V: Visitor<'i, T>, U: Visit<'i, T, V>> Visit<'i, T, V> for Vec<U> {
const CHILD_TYPES: VisitTypes = U::CHILD_TYPES;
fn visit(&mut self, visitor: &mut V) {
for v in self {
v.visit(visitor)
}
}
fn visit_children(&mut self, visitor: &mut V) {
for v in self {
v.visit_children(visitor)
}
}
}
impl<'i, A: smallvec::Array<Item = U>, U: Visit<'i, T, V>, T: Visit<'i, T, V>, V: Visitor<'i, T>> Visit<'i, T, V>
for SmallVec<A>
{
const CHILD_TYPES: VisitTypes = U::CHILD_TYPES;
fn visit(&mut self, visitor: &mut V) {
for v in self {
v.visit(visitor)
}
}
fn visit_children(&mut self, visitor: &mut V) {
for v in self {
v.visit_children(visitor)
}
}
}
macro_rules! impl_visit {
($t: ty) => {
impl<'i, V: Visitor<'i, T>, T: Visit<'i, T, V>> Visit<'i, T, V> for $t {
const CHILD_TYPES: VisitTypes = VisitTypes::empty();
fn visit_children(&mut self, _: &mut V) {}
}
};
}
impl_visit!(u8);
impl_visit!(u16);
impl_visit!(u32);
impl_visit!(i32);
impl_visit!(f32);
impl_visit!(bool);
impl_visit!(char);
impl_visit!(str);
impl_visit!(String);
impl_visit!((f32, f32));