use alloc::{string::String, vec::Vec};
use core::fmt;
use crate::{
corety::OptionString,
dynamic_selector::DynamicSelectorVec,
props::property::{CssProperty, CssPropertyType},
AzString,
};
#[derive(Debug, Default, PartialEq, PartialOrd, Clone)]
#[repr(C)]
pub struct Css {
pub rules: CssRuleBlockVec,
}
impl_option!(
Css,
OptionCss,
copy = false,
[Debug, Clone, PartialEq, PartialOrd]
);
impl_vec!(Css, CssVec, CssVecDestructor, CssVecDestructorType, CssVecSlice, OptionCss);
impl_vec_mut!(Css, CssVec);
impl_vec_debug!(Css, CssVec);
impl_vec_partialord!(Css, CssVec);
impl_vec_clone!(Css, CssVec, CssVecDestructor);
impl_vec_partialeq!(Css, CssVec);
impl_vec!(CssRuleBlock, CssRuleBlockVec, CssRuleBlockVecDestructor, CssRuleBlockVecDestructorType, CssRuleBlockVecSlice, OptionCssRuleBlock);
impl_vec_mut!(CssRuleBlock, CssRuleBlockVec);
impl_vec_debug!(CssRuleBlock, CssRuleBlockVec);
impl_vec_partialord!(CssRuleBlock, CssRuleBlockVec);
impl_vec_clone!(CssRuleBlock, CssRuleBlockVec, CssRuleBlockVecDestructor);
impl_vec_partialeq!(CssRuleBlock, CssRuleBlockVec);
impl Css {
pub fn is_empty(&self) -> bool {
self.rules.as_ref().is_empty()
}
pub fn new(rules: Vec<CssRuleBlock>) -> Self {
Self {
rules: rules.into(),
}
}
#[cfg(feature = "parser")]
pub fn from_string(s: crate::AzString) -> Self {
crate::parser2::new_from_str(s.as_str()).0
}
#[cfg(feature = "parser")]
pub fn parse_inline(style: &str) -> Self {
use alloc::string::ToString;
let mut wrapped = String::with_capacity(style.len() + 6);
wrapped.push_str("* {\n");
wrapped.push_str(style);
wrapped.push_str("\n}");
let (mut css, _warnings) = crate::parser2::new_from_str(&wrapped);
for rule in css.rules.as_mut() {
rule.priority = rule_priority::INLINE;
}
css
}
#[cfg(feature = "parser")]
pub fn from_string_with_warnings(
s: crate::AzString,
) -> (Self, Vec<crate::parser2::CssParseWarnMsgOwned>) {
let (css, warnings) = crate::parser2::new_from_str(s.as_str());
(
css,
warnings
.into_iter()
.map(|w| crate::parser2::CssParseWarnMsgOwned {
warning: w.warning.to_contained(),
location: w.location,
})
.collect(),
)
}
}
impl From<Vec<CssRuleBlock>> for Css {
fn from(rules: Vec<CssRuleBlock>) -> Self {
Self {
rules: rules.into(),
}
}
}
impl Eq for Css {}
impl Ord for Css {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.rules.as_ref().len().cmp(&other.rules.as_ref().len())
}
}
impl Eq for CssRuleBlock {}
impl Ord for CssRuleBlock {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.path.cmp(&other.path).then_with(|| self.declarations.cmp(&other.declarations))
}
}
impl From<crate::dynamic_selector::CssPropertyWithConditionsVec> for Css {
fn from(props: crate::dynamic_selector::CssPropertyWithConditionsVec) -> Self {
let rules: Vec<CssRuleBlock> = props.into_library_owned_vec().into_iter().map(|p| {
CssRuleBlock {
path: CssPath { selectors: Vec::new().into() },
declarations: alloc::vec![CssDeclaration::Static(p.property)].into(),
conditions: p.apply_if,
priority: rule_priority::INLINE,
}
}).collect();
Css { rules: rules.into() }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C, u8)]
pub enum CssDeclaration {
Static(CssProperty),
Dynamic(DynamicCssProperty),
}
impl_option!(
CssDeclaration,
OptionCssDeclaration,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl CssDeclaration {
pub const fn new_static(prop: CssProperty) -> Self {
CssDeclaration::Static(prop)
}
pub const fn new_dynamic(prop: DynamicCssProperty) -> Self {
CssDeclaration::Dynamic(prop)
}
pub fn get_type(&self) -> CssPropertyType {
use self::CssDeclaration::*;
match self {
Static(s) => s.get_type(),
Dynamic(d) => d.default_value.get_type(),
}
}
pub fn is_inheritable(&self) -> bool {
use self::CssDeclaration::*;
match self {
Static(s) => s.get_type().is_inheritable(),
Dynamic(d) => d.is_inheritable(),
}
}
pub fn can_trigger_relayout(&self) -> bool {
use self::CssDeclaration::*;
match self {
Static(s) => s.get_type().can_trigger_relayout(),
Dynamic(d) => d.can_trigger_relayout(),
}
}
pub fn to_str(&self) -> String {
use self::CssDeclaration::*;
match self {
Static(s) => format!("{:?}", s),
Dynamic(d) => format!("var(--{}, {:?})", d.dynamic_id, d.default_value),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub struct DynamicCssProperty {
pub dynamic_id: AzString,
pub default_value: CssProperty,
}
#[repr(C, u8)]
pub enum BoxOrStatic<T> {
Boxed(*mut T),
Static(*const T),
}
impl<T> BoxOrStatic<T> {
#[inline]
pub fn heap(value: T) -> Self {
BoxOrStatic::Boxed(Box::into_raw(Box::new(value)))
}
#[inline]
pub fn as_ref(&self) -> &T {
match self {
BoxOrStatic::Boxed(ptr) => unsafe {
debug_assert!(!ptr.is_null(), "BoxOrStatic::Boxed contained a null pointer");
&**ptr
},
BoxOrStatic::Static(ptr) => unsafe {
debug_assert!(!ptr.is_null(), "BoxOrStatic::Static contained a null pointer");
&**ptr
},
}
}
#[inline]
pub fn as_mut(&mut self) -> &mut T {
match self {
BoxOrStatic::Boxed(ptr) => unsafe { &mut **ptr },
BoxOrStatic::Static(_) => panic!("Cannot mutate a static BoxOrStatic value"),
}
}
#[inline]
pub fn into_inner(self) -> T where T: Clone {
let val = self.as_ref().clone();
core::mem::forget(self);
val
}
}
impl<T> Drop for BoxOrStatic<T> {
fn drop(&mut self) {
if let BoxOrStatic::Boxed(ptr) = self {
if !ptr.is_null() {
unsafe { drop(Box::from_raw(*ptr)); }
*ptr = core::ptr::null_mut();
}
}
}
}
impl<T: Clone> Clone for BoxOrStatic<T> {
fn clone(&self) -> Self {
match self {
BoxOrStatic::Boxed(ptr) => {
let val = unsafe { &**ptr }.clone();
BoxOrStatic::Boxed(Box::into_raw(Box::new(val)))
}
BoxOrStatic::Static(ptr) => BoxOrStatic::Static(*ptr),
}
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for BoxOrStatic<T> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
self.as_ref().fmt(f)
}
}
impl<T: core::fmt::Display> core::fmt::Display for BoxOrStatic<T> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
self.as_ref().fmt(f)
}
}
impl<T: PartialEq> PartialEq for BoxOrStatic<T> {
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl<T: Eq> Eq for BoxOrStatic<T> {}
impl<T: core::hash::Hash> core::hash::Hash for BoxOrStatic<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.as_ref().hash(state)
}
}
impl<T: PartialOrd> PartialOrd for BoxOrStatic<T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.as_ref().partial_cmp(other.as_ref())
}
}
impl<T: Ord> Ord for BoxOrStatic<T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.as_ref().cmp(other.as_ref())
}
}
impl<T> core::ops::Deref for BoxOrStatic<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.as_ref()
}
}
impl<T: Default> Default for BoxOrStatic<T> {
fn default() -> Self {
BoxOrStatic::heap(T::default())
}
}
impl<T: PrintAsCssValue> PrintAsCssValue for BoxOrStatic<T> {
fn print_as_css_value(&self) -> String {
self.as_ref().print_as_css_value()
}
}
unsafe impl<T: Send + 'static> Send for BoxOrStatic<T> {}
unsafe impl<T: Sync + 'static> Sync for BoxOrStatic<T> {}
pub type BoxOrStaticStyleBoxShadow = BoxOrStatic<crate::props::style::box_shadow::StyleBoxShadow>;
pub type BoxOrStaticString = BoxOrStatic<crate::AzString>;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C, u8)] pub enum CssPropertyValue<T> {
Auto,
None,
Initial,
Inherit,
Revert,
Unset,
Exact(T),
}
pub trait PrintAsCssValue {
fn print_as_css_value(&self) -> String;
}
impl<T: PrintAsCssValue> CssPropertyValue<T> {
pub fn get_css_value_fmt(&self) -> String {
match self {
CssPropertyValue::Auto => "auto".to_string(),
CssPropertyValue::None => "none".to_string(),
CssPropertyValue::Initial => "initial".to_string(),
CssPropertyValue::Inherit => "inherit".to_string(),
CssPropertyValue::Revert => "revert".to_string(),
CssPropertyValue::Unset => "unset".to_string(),
CssPropertyValue::Exact(e) => e.print_as_css_value(),
}
}
}
impl<T: fmt::Display> fmt::Display for CssPropertyValue<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::CssPropertyValue::*;
match self {
Auto => write!(f, "auto"),
None => write!(f, "none"),
Initial => write!(f, "initial"),
Inherit => write!(f, "inherit"),
Revert => write!(f, "revert"),
Unset => write!(f, "unset"),
Exact(e) => write!(f, "{}", e),
}
}
}
impl<T> From<T> for CssPropertyValue<T> {
fn from(c: T) -> Self {
CssPropertyValue::Exact(c)
}
}
impl<T> CssPropertyValue<T> {
#[inline]
pub fn map_property<F: Fn(T) -> U, U>(self, map_fn: F) -> CssPropertyValue<U> {
match self {
CssPropertyValue::Exact(c) => CssPropertyValue::Exact(map_fn(c)),
CssPropertyValue::Auto => CssPropertyValue::Auto,
CssPropertyValue::None => CssPropertyValue::None,
CssPropertyValue::Initial => CssPropertyValue::Initial,
CssPropertyValue::Inherit => CssPropertyValue::Inherit,
CssPropertyValue::Revert => CssPropertyValue::Revert,
CssPropertyValue::Unset => CssPropertyValue::Unset,
}
}
#[inline]
pub fn get_property(&self) -> Option<&T> {
match self {
CssPropertyValue::Exact(c) => Some(c),
_ => None,
}
}
#[inline]
pub fn get_property_owned(self) -> Option<T> {
match self {
CssPropertyValue::Exact(c) => Some(c),
_ => None,
}
}
#[inline]
pub fn is_auto(&self) -> bool {
matches!(self, CssPropertyValue::Auto)
}
#[inline]
pub fn is_none(&self) -> bool {
matches!(self, CssPropertyValue::None)
}
#[inline]
pub fn is_initial(&self) -> bool {
matches!(self, CssPropertyValue::Initial)
}
#[inline]
pub fn is_inherit(&self) -> bool {
matches!(self, CssPropertyValue::Inherit)
}
#[inline]
pub fn is_revert(&self) -> bool {
matches!(self, CssPropertyValue::Revert)
}
#[inline]
pub fn is_unset(&self) -> bool {
matches!(self, CssPropertyValue::Unset)
}
}
impl<T: Default> CssPropertyValue<T> {
#[inline]
pub fn get_property_or_default(self) -> Option<T> {
match self {
CssPropertyValue::Auto | CssPropertyValue::Initial => Some(T::default()),
CssPropertyValue::Exact(c) => Some(c),
CssPropertyValue::None
| CssPropertyValue::Inherit
| CssPropertyValue::Revert
| CssPropertyValue::Unset => None,
}
}
}
impl<T: Default> Default for CssPropertyValue<T> {
#[inline]
fn default() -> Self {
CssPropertyValue::Exact(T::default())
}
}
impl DynamicCssProperty {
pub fn is_inheritable(&self) -> bool {
false
}
pub fn can_trigger_relayout(&self) -> bool {
self.default_value.get_type().can_trigger_relayout()
}
}
pub mod rule_priority {
pub const UA: u8 = 0;
pub const SYSTEM: u8 = 10;
pub const AUTHOR: u8 = 20;
pub const INLINE: u8 = 30;
pub const RUNTIME: u8 = 50;
}
#[derive(Debug, Default, Clone, PartialEq)]
#[repr(C)]
pub struct CssRuleBlock {
pub path: CssPath,
pub declarations: CssDeclarationVec,
pub conditions: DynamicSelectorVec,
pub priority: u8,
}
impl_option!(
CssRuleBlock,
OptionCssRuleBlock,
copy = false,
[Debug, Clone, PartialEq, PartialOrd]
);
impl PartialOrd for CssRuleBlock {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
match self.path.partial_cmp(&other.path) {
Some(core::cmp::Ordering::Equal) => self.declarations.partial_cmp(&other.declarations),
ord => ord,
}
}
}
impl_vec!(CssDeclaration, CssDeclarationVec, CssDeclarationVecDestructor, CssDeclarationVecDestructorType, CssDeclarationVecSlice, OptionCssDeclaration);
impl_vec_mut!(CssDeclaration, CssDeclarationVec);
impl_vec_debug!(CssDeclaration, CssDeclarationVec);
impl_vec_partialord!(CssDeclaration, CssDeclarationVec);
impl_vec_ord!(CssDeclaration, CssDeclarationVec);
impl_vec_clone!(
CssDeclaration,
CssDeclarationVec,
CssDeclarationVecDestructor
);
impl_vec_partialeq!(CssDeclaration, CssDeclarationVec);
impl_vec_eq!(CssDeclaration, CssDeclarationVec);
impl_vec_hash!(CssDeclaration, CssDeclarationVec);
impl CssRuleBlock {
pub fn new(path: CssPath, declarations: Vec<CssDeclaration>) -> Self {
Self {
path,
declarations: declarations.into(),
conditions: DynamicSelectorVec::from_const_slice(&[]),
priority: rule_priority::AUTHOR,
}
}
pub fn with_conditions(
path: CssPath,
declarations: Vec<CssDeclaration>,
conditions: Vec<crate::dynamic_selector::DynamicSelector>,
) -> Self {
Self {
path,
declarations: declarations.into(),
conditions: conditions.into(),
priority: rule_priority::AUTHOR,
}
}
}
pub type CssContentGroup<'a> = Vec<&'a CssPathSelector>;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub enum NodeTypeTag {
Html,
Head,
Body,
Div,
P,
Article,
Section,
Nav,
Aside,
Header,
Footer,
Main,
Figure,
FigCaption,
H1,
H2,
H3,
H4,
H5,
H6,
Br,
Hr,
Pre,
BlockQuote,
Address,
Details,
Summary,
Dialog,
Ul,
Ol,
Li,
Dl,
Dt,
Dd,
Menu,
MenuItem,
Dir,
Table,
Caption,
THead,
TBody,
TFoot,
Tr,
Th,
Td,
ColGroup,
Col,
Form,
FieldSet,
Legend,
Label,
Input,
Button,
Select,
OptGroup,
SelectOption,
TextArea,
Output,
Progress,
Meter,
DataList,
Span,
A,
Em,
Strong,
B,
I,
U,
S,
Mark,
Del,
Ins,
Code,
Samp,
Kbd,
Var,
Cite,
Dfn,
Abbr,
Acronym,
Q,
Time,
Sub,
Sup,
Small,
Big,
Bdo,
Bdi,
Wbr,
Ruby,
Rt,
Rtc,
Rp,
Data,
Canvas,
Object,
Param,
Embed,
Audio,
Video,
Source,
Track,
Map,
Area,
Svg,
SvgPath,
SvgCircle,
SvgRect,
SvgEllipse,
SvgLine,
SvgPolygon,
SvgPolyline,
SvgG,
SvgDefs,
SvgSymbol,
SvgUse,
SvgSwitch,
SvgText,
SvgTspan,
SvgTextPath,
SvgLinearGradient,
SvgRadialGradient,
SvgStop,
SvgPattern,
SvgClipPathElement,
SvgMask,
SvgFilter,
SvgFeBlend,
SvgFeColorMatrix,
SvgFeComponentTransfer,
SvgFeComposite,
SvgFeConvolveMatrix,
SvgFeDiffuseLighting,
SvgFeDisplacementMap,
SvgFeDistantLight,
SvgFeDropShadow,
SvgFeFlood,
SvgFeFuncR,
SvgFeFuncG,
SvgFeFuncB,
SvgFeFuncA,
SvgFeGaussianBlur,
SvgFeImage,
SvgFeMerge,
SvgFeMergeNode,
SvgFeMorphology,
SvgFeOffset,
SvgFePointLight,
SvgFeSpecularLighting,
SvgFeSpotLight,
SvgFeTile,
SvgFeTurbulence,
SvgMarker,
SvgImage,
SvgForeignObject,
SvgTitle,
SvgDesc,
SvgMetadata,
SvgA,
SvgView,
SvgStyle,
SvgScript,
SvgAnimate,
SvgAnimateMotion,
SvgAnimateTransform,
SvgSet,
SvgMpath,
Title,
Meta,
Link,
Script,
Style,
Base,
Text,
Img,
VirtualView,
Icon,
GeolocationProbe,
Before,
After,
Marker,
Placeholder,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum NodeTypeTagParseError<'a> {
Invalid(&'a str),
}
impl<'a> fmt::Display for NodeTypeTagParseError<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
NodeTypeTagParseError::Invalid(e) => write!(f, "Invalid node type: {}", e),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, u8)]
pub enum NodeTypeTagParseErrorOwned {
Invalid(AzString),
}
impl<'a> NodeTypeTagParseError<'a> {
pub fn to_contained(&self) -> NodeTypeTagParseErrorOwned {
match self {
NodeTypeTagParseError::Invalid(s) => NodeTypeTagParseErrorOwned::Invalid(s.to_string().into()),
}
}
}
impl NodeTypeTagParseErrorOwned {
pub fn to_shared<'a>(&'a self) -> NodeTypeTagParseError<'a> {
match self {
NodeTypeTagParseErrorOwned::Invalid(s) => NodeTypeTagParseError::Invalid(s),
}
}
}
impl NodeTypeTag {
pub fn from_str(css_key: &str) -> Result<Self, NodeTypeTagParseError<'_>> {
match css_key {
"html" => Ok(NodeTypeTag::Html),
"head" => Ok(NodeTypeTag::Head),
"body" => Ok(NodeTypeTag::Body),
"div" => Ok(NodeTypeTag::Div),
"p" => Ok(NodeTypeTag::P),
"article" => Ok(NodeTypeTag::Article),
"section" => Ok(NodeTypeTag::Section),
"nav" => Ok(NodeTypeTag::Nav),
"aside" => Ok(NodeTypeTag::Aside),
"header" => Ok(NodeTypeTag::Header),
"footer" => Ok(NodeTypeTag::Footer),
"main" => Ok(NodeTypeTag::Main),
"figure" => Ok(NodeTypeTag::Figure),
"figcaption" => Ok(NodeTypeTag::FigCaption),
"h1" => Ok(NodeTypeTag::H1),
"h2" => Ok(NodeTypeTag::H2),
"h3" => Ok(NodeTypeTag::H3),
"h4" => Ok(NodeTypeTag::H4),
"h5" => Ok(NodeTypeTag::H5),
"h6" => Ok(NodeTypeTag::H6),
"br" => Ok(NodeTypeTag::Br),
"hr" => Ok(NodeTypeTag::Hr),
"pre" => Ok(NodeTypeTag::Pre),
"blockquote" => Ok(NodeTypeTag::BlockQuote),
"address" => Ok(NodeTypeTag::Address),
"details" => Ok(NodeTypeTag::Details),
"summary" => Ok(NodeTypeTag::Summary),
"dialog" => Ok(NodeTypeTag::Dialog),
"ul" => Ok(NodeTypeTag::Ul),
"ol" => Ok(NodeTypeTag::Ol),
"li" => Ok(NodeTypeTag::Li),
"dl" => Ok(NodeTypeTag::Dl),
"dt" => Ok(NodeTypeTag::Dt),
"dd" => Ok(NodeTypeTag::Dd),
"menu" => Ok(NodeTypeTag::Menu),
"menuitem" => Ok(NodeTypeTag::MenuItem),
"dir" => Ok(NodeTypeTag::Dir),
"table" => Ok(NodeTypeTag::Table),
"caption" => Ok(NodeTypeTag::Caption),
"thead" => Ok(NodeTypeTag::THead),
"tbody" => Ok(NodeTypeTag::TBody),
"tfoot" => Ok(NodeTypeTag::TFoot),
"tr" => Ok(NodeTypeTag::Tr),
"th" => Ok(NodeTypeTag::Th),
"td" => Ok(NodeTypeTag::Td),
"colgroup" => Ok(NodeTypeTag::ColGroup),
"col" => Ok(NodeTypeTag::Col),
"form" => Ok(NodeTypeTag::Form),
"fieldset" => Ok(NodeTypeTag::FieldSet),
"legend" => Ok(NodeTypeTag::Legend),
"label" => Ok(NodeTypeTag::Label),
"input" => Ok(NodeTypeTag::Input),
"button" => Ok(NodeTypeTag::Button),
"select" => Ok(NodeTypeTag::Select),
"optgroup" => Ok(NodeTypeTag::OptGroup),
"option" => Ok(NodeTypeTag::SelectOption),
"textarea" => Ok(NodeTypeTag::TextArea),
"output" => Ok(NodeTypeTag::Output),
"progress" => Ok(NodeTypeTag::Progress),
"meter" => Ok(NodeTypeTag::Meter),
"datalist" => Ok(NodeTypeTag::DataList),
"span" => Ok(NodeTypeTag::Span),
"a" => Ok(NodeTypeTag::A),
"em" => Ok(NodeTypeTag::Em),
"strong" => Ok(NodeTypeTag::Strong),
"b" => Ok(NodeTypeTag::B),
"i" => Ok(NodeTypeTag::I),
"u" => Ok(NodeTypeTag::U),
"s" => Ok(NodeTypeTag::S),
"mark" => Ok(NodeTypeTag::Mark),
"del" => Ok(NodeTypeTag::Del),
"ins" => Ok(NodeTypeTag::Ins),
"code" => Ok(NodeTypeTag::Code),
"samp" => Ok(NodeTypeTag::Samp),
"kbd" => Ok(NodeTypeTag::Kbd),
"var" => Ok(NodeTypeTag::Var),
"cite" => Ok(NodeTypeTag::Cite),
"dfn" => Ok(NodeTypeTag::Dfn),
"abbr" => Ok(NodeTypeTag::Abbr),
"acronym" => Ok(NodeTypeTag::Acronym),
"q" => Ok(NodeTypeTag::Q),
"time" => Ok(NodeTypeTag::Time),
"sub" => Ok(NodeTypeTag::Sub),
"sup" => Ok(NodeTypeTag::Sup),
"small" => Ok(NodeTypeTag::Small),
"big" => Ok(NodeTypeTag::Big),
"bdo" => Ok(NodeTypeTag::Bdo),
"bdi" => Ok(NodeTypeTag::Bdi),
"wbr" => Ok(NodeTypeTag::Wbr),
"ruby" => Ok(NodeTypeTag::Ruby),
"rt" => Ok(NodeTypeTag::Rt),
"rtc" => Ok(NodeTypeTag::Rtc),
"rp" => Ok(NodeTypeTag::Rp),
"data" => Ok(NodeTypeTag::Data),
"canvas" => Ok(NodeTypeTag::Canvas),
"object" => Ok(NodeTypeTag::Object),
"param" => Ok(NodeTypeTag::Param),
"embed" => Ok(NodeTypeTag::Embed),
"audio" => Ok(NodeTypeTag::Audio),
"video" => Ok(NodeTypeTag::Video),
"source" => Ok(NodeTypeTag::Source),
"track" => Ok(NodeTypeTag::Track),
"map" => Ok(NodeTypeTag::Map),
"area" => Ok(NodeTypeTag::Area),
"svg" => Ok(NodeTypeTag::Svg),
"path" => Ok(NodeTypeTag::SvgPath),
"circle" => Ok(NodeTypeTag::SvgCircle),
"rect" => Ok(NodeTypeTag::SvgRect),
"ellipse" => Ok(NodeTypeTag::SvgEllipse),
"line" => Ok(NodeTypeTag::SvgLine),
"polygon" => Ok(NodeTypeTag::SvgPolygon),
"polyline" => Ok(NodeTypeTag::SvgPolyline),
"g" => Ok(NodeTypeTag::SvgG),
"defs" => Ok(NodeTypeTag::SvgDefs),
"symbol" => Ok(NodeTypeTag::SvgSymbol),
"use" => Ok(NodeTypeTag::SvgUse),
"switch" => Ok(NodeTypeTag::SvgSwitch),
"svg:text" => Ok(NodeTypeTag::SvgText),
"tspan" => Ok(NodeTypeTag::SvgTspan),
"textpath" => Ok(NodeTypeTag::SvgTextPath),
"lineargradient" => Ok(NodeTypeTag::SvgLinearGradient),
"radialgradient" => Ok(NodeTypeTag::SvgRadialGradient),
"stop" => Ok(NodeTypeTag::SvgStop),
"pattern" => Ok(NodeTypeTag::SvgPattern),
"clippath" => Ok(NodeTypeTag::SvgClipPathElement),
"mask" => Ok(NodeTypeTag::SvgMask),
"filter" => Ok(NodeTypeTag::SvgFilter),
"feblend" => Ok(NodeTypeTag::SvgFeBlend),
"fecolormatrix" => Ok(NodeTypeTag::SvgFeColorMatrix),
"fecomponenttransfer" => Ok(NodeTypeTag::SvgFeComponentTransfer),
"fecomposite" => Ok(NodeTypeTag::SvgFeComposite),
"feconvolvematrix" => Ok(NodeTypeTag::SvgFeConvolveMatrix),
"fediffuselighting" => Ok(NodeTypeTag::SvgFeDiffuseLighting),
"fedisplacementmap" => Ok(NodeTypeTag::SvgFeDisplacementMap),
"fedistantlight" => Ok(NodeTypeTag::SvgFeDistantLight),
"fedropshadow" => Ok(NodeTypeTag::SvgFeDropShadow),
"feflood" => Ok(NodeTypeTag::SvgFeFlood),
"fefuncr" => Ok(NodeTypeTag::SvgFeFuncR),
"fefuncg" => Ok(NodeTypeTag::SvgFeFuncG),
"fefuncb" => Ok(NodeTypeTag::SvgFeFuncB),
"fefunca" => Ok(NodeTypeTag::SvgFeFuncA),
"fegaussianblur" => Ok(NodeTypeTag::SvgFeGaussianBlur),
"feimage" => Ok(NodeTypeTag::SvgFeImage),
"femerge" => Ok(NodeTypeTag::SvgFeMerge),
"femergenode" => Ok(NodeTypeTag::SvgFeMergeNode),
"femorphology" => Ok(NodeTypeTag::SvgFeMorphology),
"feoffset" => Ok(NodeTypeTag::SvgFeOffset),
"fepointlight" => Ok(NodeTypeTag::SvgFePointLight),
"fespecularlighting" => Ok(NodeTypeTag::SvgFeSpecularLighting),
"fespotlight" => Ok(NodeTypeTag::SvgFeSpotLight),
"fetile" => Ok(NodeTypeTag::SvgFeTile),
"feturbulence" => Ok(NodeTypeTag::SvgFeTurbulence),
"image" | "svg:image" => Ok(NodeTypeTag::SvgImage),
"svg:marker" => Ok(NodeTypeTag::SvgMarker),
"foreignobject" => Ok(NodeTypeTag::SvgForeignObject),
"svg:title" => Ok(NodeTypeTag::SvgTitle),
"svg:a" => Ok(NodeTypeTag::SvgA),
"svg:style" => Ok(NodeTypeTag::SvgStyle),
"svg:script" => Ok(NodeTypeTag::SvgScript),
"desc" => Ok(NodeTypeTag::SvgDesc),
"metadata" => Ok(NodeTypeTag::SvgMetadata),
"view" => Ok(NodeTypeTag::SvgView),
"animate" => Ok(NodeTypeTag::SvgAnimate),
"animatemotion" => Ok(NodeTypeTag::SvgAnimateMotion),
"animatetransform" => Ok(NodeTypeTag::SvgAnimateTransform),
"set" => Ok(NodeTypeTag::SvgSet),
"mpath" => Ok(NodeTypeTag::SvgMpath),
"title" => Ok(NodeTypeTag::Title),
"meta" => Ok(NodeTypeTag::Meta),
"link" => Ok(NodeTypeTag::Link),
"script" => Ok(NodeTypeTag::Script),
"style" => Ok(NodeTypeTag::Style),
"base" => Ok(NodeTypeTag::Base),
"img" => Ok(NodeTypeTag::Img),
"virtual-view" | "iframe" => Ok(NodeTypeTag::VirtualView),
"icon" => Ok(NodeTypeTag::Icon),
"geolocation-probe" => Ok(NodeTypeTag::GeolocationProbe),
"before" | "::before" => Ok(NodeTypeTag::Before),
"after" | "::after" => Ok(NodeTypeTag::After),
"marker" | "::marker" => Ok(NodeTypeTag::Marker),
"placeholder" | "::placeholder" => Ok(NodeTypeTag::Placeholder),
other => Err(NodeTypeTagParseError::Invalid(other)),
}
}
}
impl fmt::Display for NodeTypeTag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
NodeTypeTag::Html => write!(f, "html"),
NodeTypeTag::Head => write!(f, "head"),
NodeTypeTag::Body => write!(f, "body"),
NodeTypeTag::Div => write!(f, "div"),
NodeTypeTag::P => write!(f, "p"),
NodeTypeTag::Article => write!(f, "article"),
NodeTypeTag::Section => write!(f, "section"),
NodeTypeTag::Nav => write!(f, "nav"),
NodeTypeTag::Aside => write!(f, "aside"),
NodeTypeTag::Header => write!(f, "header"),
NodeTypeTag::Footer => write!(f, "footer"),
NodeTypeTag::Main => write!(f, "main"),
NodeTypeTag::Figure => write!(f, "figure"),
NodeTypeTag::FigCaption => write!(f, "figcaption"),
NodeTypeTag::H1 => write!(f, "h1"),
NodeTypeTag::H2 => write!(f, "h2"),
NodeTypeTag::H3 => write!(f, "h3"),
NodeTypeTag::H4 => write!(f, "h4"),
NodeTypeTag::H5 => write!(f, "h5"),
NodeTypeTag::H6 => write!(f, "h6"),
NodeTypeTag::Br => write!(f, "br"),
NodeTypeTag::Hr => write!(f, "hr"),
NodeTypeTag::Pre => write!(f, "pre"),
NodeTypeTag::BlockQuote => write!(f, "blockquote"),
NodeTypeTag::Address => write!(f, "address"),
NodeTypeTag::Details => write!(f, "details"),
NodeTypeTag::Summary => write!(f, "summary"),
NodeTypeTag::Dialog => write!(f, "dialog"),
NodeTypeTag::Ul => write!(f, "ul"),
NodeTypeTag::Ol => write!(f, "ol"),
NodeTypeTag::Li => write!(f, "li"),
NodeTypeTag::Dl => write!(f, "dl"),
NodeTypeTag::Dt => write!(f, "dt"),
NodeTypeTag::Dd => write!(f, "dd"),
NodeTypeTag::Menu => write!(f, "menu"),
NodeTypeTag::MenuItem => write!(f, "menuitem"),
NodeTypeTag::Dir => write!(f, "dir"),
NodeTypeTag::Table => write!(f, "table"),
NodeTypeTag::Caption => write!(f, "caption"),
NodeTypeTag::THead => write!(f, "thead"),
NodeTypeTag::TBody => write!(f, "tbody"),
NodeTypeTag::TFoot => write!(f, "tfoot"),
NodeTypeTag::Tr => write!(f, "tr"),
NodeTypeTag::Th => write!(f, "th"),
NodeTypeTag::Td => write!(f, "td"),
NodeTypeTag::ColGroup => write!(f, "colgroup"),
NodeTypeTag::Col => write!(f, "col"),
NodeTypeTag::Form => write!(f, "form"),
NodeTypeTag::FieldSet => write!(f, "fieldset"),
NodeTypeTag::Legend => write!(f, "legend"),
NodeTypeTag::Label => write!(f, "label"),
NodeTypeTag::Input => write!(f, "input"),
NodeTypeTag::Button => write!(f, "button"),
NodeTypeTag::Select => write!(f, "select"),
NodeTypeTag::OptGroup => write!(f, "optgroup"),
NodeTypeTag::SelectOption => write!(f, "option"),
NodeTypeTag::TextArea => write!(f, "textarea"),
NodeTypeTag::Output => write!(f, "output"),
NodeTypeTag::Progress => write!(f, "progress"),
NodeTypeTag::Meter => write!(f, "meter"),
NodeTypeTag::DataList => write!(f, "datalist"),
NodeTypeTag::Span => write!(f, "span"),
NodeTypeTag::A => write!(f, "a"),
NodeTypeTag::Em => write!(f, "em"),
NodeTypeTag::Strong => write!(f, "strong"),
NodeTypeTag::B => write!(f, "b"),
NodeTypeTag::I => write!(f, "i"),
NodeTypeTag::U => write!(f, "u"),
NodeTypeTag::S => write!(f, "s"),
NodeTypeTag::Mark => write!(f, "mark"),
NodeTypeTag::Del => write!(f, "del"),
NodeTypeTag::Ins => write!(f, "ins"),
NodeTypeTag::Code => write!(f, "code"),
NodeTypeTag::Samp => write!(f, "samp"),
NodeTypeTag::Kbd => write!(f, "kbd"),
NodeTypeTag::Var => write!(f, "var"),
NodeTypeTag::Cite => write!(f, "cite"),
NodeTypeTag::Dfn => write!(f, "dfn"),
NodeTypeTag::Abbr => write!(f, "abbr"),
NodeTypeTag::Acronym => write!(f, "acronym"),
NodeTypeTag::Q => write!(f, "q"),
NodeTypeTag::Time => write!(f, "time"),
NodeTypeTag::Sub => write!(f, "sub"),
NodeTypeTag::Sup => write!(f, "sup"),
NodeTypeTag::Small => write!(f, "small"),
NodeTypeTag::Big => write!(f, "big"),
NodeTypeTag::Bdo => write!(f, "bdo"),
NodeTypeTag::Bdi => write!(f, "bdi"),
NodeTypeTag::Wbr => write!(f, "wbr"),
NodeTypeTag::Ruby => write!(f, "ruby"),
NodeTypeTag::Rt => write!(f, "rt"),
NodeTypeTag::Rtc => write!(f, "rtc"),
NodeTypeTag::Rp => write!(f, "rp"),
NodeTypeTag::Data => write!(f, "data"),
NodeTypeTag::Canvas => write!(f, "canvas"),
NodeTypeTag::Object => write!(f, "object"),
NodeTypeTag::Param => write!(f, "param"),
NodeTypeTag::Embed => write!(f, "embed"),
NodeTypeTag::Audio => write!(f, "audio"),
NodeTypeTag::Video => write!(f, "video"),
NodeTypeTag::Source => write!(f, "source"),
NodeTypeTag::Track => write!(f, "track"),
NodeTypeTag::Map => write!(f, "map"),
NodeTypeTag::Area => write!(f, "area"),
NodeTypeTag::Svg => write!(f, "svg"),
NodeTypeTag::SvgPath => write!(f, "path"),
NodeTypeTag::SvgCircle => write!(f, "circle"),
NodeTypeTag::SvgRect => write!(f, "rect"),
NodeTypeTag::SvgEllipse => write!(f, "ellipse"),
NodeTypeTag::SvgLine => write!(f, "line"),
NodeTypeTag::SvgPolygon => write!(f, "polygon"),
NodeTypeTag::SvgPolyline => write!(f, "polyline"),
NodeTypeTag::SvgG => write!(f, "g"),
NodeTypeTag::SvgDefs => write!(f, "defs"),
NodeTypeTag::SvgSymbol => write!(f, "symbol"),
NodeTypeTag::SvgUse => write!(f, "use"),
NodeTypeTag::SvgSwitch => write!(f, "switch"),
NodeTypeTag::SvgText => write!(f, "svg:text"),
NodeTypeTag::SvgTspan => write!(f, "tspan"),
NodeTypeTag::SvgTextPath => write!(f, "textpath"),
NodeTypeTag::SvgLinearGradient => write!(f, "lineargradient"),
NodeTypeTag::SvgRadialGradient => write!(f, "radialgradient"),
NodeTypeTag::SvgStop => write!(f, "stop"),
NodeTypeTag::SvgPattern => write!(f, "pattern"),
NodeTypeTag::SvgClipPathElement => write!(f, "clippath"),
NodeTypeTag::SvgMask => write!(f, "mask"),
NodeTypeTag::SvgFilter => write!(f, "filter"),
NodeTypeTag::SvgFeBlend => write!(f, "feblend"),
NodeTypeTag::SvgFeColorMatrix => write!(f, "fecolormatrix"),
NodeTypeTag::SvgFeComponentTransfer => write!(f, "fecomponenttransfer"),
NodeTypeTag::SvgFeComposite => write!(f, "fecomposite"),
NodeTypeTag::SvgFeConvolveMatrix => write!(f, "feconvolvematrix"),
NodeTypeTag::SvgFeDiffuseLighting => write!(f, "fediffuselighting"),
NodeTypeTag::SvgFeDisplacementMap => write!(f, "fedisplacementmap"),
NodeTypeTag::SvgFeDistantLight => write!(f, "fedistantlight"),
NodeTypeTag::SvgFeDropShadow => write!(f, "fedropshadow"),
NodeTypeTag::SvgFeFlood => write!(f, "feflood"),
NodeTypeTag::SvgFeFuncR => write!(f, "fefuncr"),
NodeTypeTag::SvgFeFuncG => write!(f, "fefuncg"),
NodeTypeTag::SvgFeFuncB => write!(f, "fefuncb"),
NodeTypeTag::SvgFeFuncA => write!(f, "fefunca"),
NodeTypeTag::SvgFeGaussianBlur => write!(f, "fegaussianblur"),
NodeTypeTag::SvgFeImage => write!(f, "feimage"),
NodeTypeTag::SvgFeMerge => write!(f, "femerge"),
NodeTypeTag::SvgFeMergeNode => write!(f, "femergenode"),
NodeTypeTag::SvgFeMorphology => write!(f, "femorphology"),
NodeTypeTag::SvgFeOffset => write!(f, "feoffset"),
NodeTypeTag::SvgFePointLight => write!(f, "fepointlight"),
NodeTypeTag::SvgFeSpecularLighting => write!(f, "fespecularlighting"),
NodeTypeTag::SvgFeSpotLight => write!(f, "fespotlight"),
NodeTypeTag::SvgFeTile => write!(f, "fetile"),
NodeTypeTag::SvgFeTurbulence => write!(f, "feturbulence"),
NodeTypeTag::SvgMarker => write!(f, "svg:marker"),
NodeTypeTag::SvgImage => write!(f, "svg:image"),
NodeTypeTag::SvgForeignObject => write!(f, "foreignobject"),
NodeTypeTag::SvgTitle => write!(f, "svg:title"),
NodeTypeTag::SvgDesc => write!(f, "desc"),
NodeTypeTag::SvgMetadata => write!(f, "metadata"),
NodeTypeTag::SvgA => write!(f, "svg:a"),
NodeTypeTag::SvgView => write!(f, "view"),
NodeTypeTag::SvgStyle => write!(f, "svg:style"),
NodeTypeTag::SvgScript => write!(f, "svg:script"),
NodeTypeTag::SvgAnimate => write!(f, "animate"),
NodeTypeTag::SvgAnimateMotion => write!(f, "animatemotion"),
NodeTypeTag::SvgAnimateTransform => write!(f, "animatetransform"),
NodeTypeTag::SvgSet => write!(f, "set"),
NodeTypeTag::SvgMpath => write!(f, "mpath"),
NodeTypeTag::Title => write!(f, "title"),
NodeTypeTag::Meta => write!(f, "meta"),
NodeTypeTag::Link => write!(f, "link"),
NodeTypeTag::Script => write!(f, "script"),
NodeTypeTag::Style => write!(f, "style"),
NodeTypeTag::Base => write!(f, "base"),
NodeTypeTag::Text => write!(f, "text"),
NodeTypeTag::Img => write!(f, "img"),
NodeTypeTag::VirtualView => write!(f, "virtual-view"),
NodeTypeTag::Icon => write!(f, "icon"),
NodeTypeTag::GeolocationProbe => write!(f, "geolocation-probe"),
NodeTypeTag::Before => write!(f, "::before"),
NodeTypeTag::After => write!(f, "::after"),
NodeTypeTag::Marker => write!(f, "::marker"),
NodeTypeTag::Placeholder => write!(f, "::placeholder"),
}
}
}
#[derive(Clone, Hash, Default, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub struct CssPath {
pub selectors: CssPathSelectorVec,
}
impl_vec!(CssPathSelector, CssPathSelectorVec, CssPathSelectorVecDestructor, CssPathSelectorVecDestructorType, CssPathSelectorVecSlice, OptionCssPathSelector);
impl_vec_debug!(CssPathSelector, CssPathSelectorVec);
impl_vec_partialord!(CssPathSelector, CssPathSelectorVec);
impl_vec_ord!(CssPathSelector, CssPathSelectorVec);
impl_vec_clone!(
CssPathSelector,
CssPathSelectorVec,
CssPathSelectorVecDestructor
);
impl_vec_partialeq!(CssPathSelector, CssPathSelectorVec);
impl_vec_eq!(CssPathSelector, CssPathSelectorVec);
impl_vec_hash!(CssPathSelector, CssPathSelectorVec);
impl CssPath {
pub fn new(selectors: Vec<CssPathSelector>) -> Self {
Self {
selectors: selectors.into(),
}
}
}
impl fmt::Display for CssPath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for selector in self.selectors.as_ref() {
write!(f, "{}", selector)?;
}
Ok(())
}
}
impl fmt::Debug for CssPath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C, u8)]
#[derive(Default)]
pub enum CssPathSelector {
#[default]
Global,
Type(NodeTypeTag),
Class(AzString),
Id(AzString),
PseudoSelector(CssPathPseudoSelector),
Attribute(CssAttributeSelector),
DirectChildren,
Children,
AdjacentSibling,
GeneralSibling,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub struct CssAttributeSelector {
pub name: AzString,
pub op: AttributeMatchOp,
pub value: OptionString,
}
impl Default for CssAttributeSelector {
fn default() -> Self {
Self {
name: AzString::default(),
op: AttributeMatchOp::Exists,
value: OptionString::None,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub enum AttributeMatchOp {
Exists,
Eq,
Includes,
DashMatch,
Prefix,
Suffix,
Substring,
}
impl Default for AttributeMatchOp {
fn default() -> Self {
AttributeMatchOp::Exists
}
}
impl_option!(
CssPathSelector,
OptionCssPathSelector,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl fmt::Display for CssPathSelector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::CssPathSelector::*;
match &self {
Global => write!(f, "*"),
Type(n) => write!(f, "{}", n),
Class(c) => write!(f, ".{}", c),
Id(i) => write!(f, "#{}", i),
PseudoSelector(p) => write!(f, ":{}", p),
Attribute(a) => write!(f, "{}", a),
DirectChildren => write!(f, ">"),
Children => write!(f, " "),
AdjacentSibling => write!(f, "+"),
GeneralSibling => write!(f, "~"),
}
}
}
impl fmt::Display for CssAttributeSelector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match (&self.op, self.value.as_ref()) {
(AttributeMatchOp::Exists, _) => write!(f, "[{}]", self.name),
(op, Some(v)) => write!(f, "[{}{}=\"{}\"]", self.name, op.symbol_prefix(), v),
(op, None) => write!(f, "[{}{}=\"\"]", self.name, op.symbol_prefix()),
}
}
}
impl AttributeMatchOp {
pub fn symbol_prefix(&self) -> &'static str {
match self {
AttributeMatchOp::Exists => "",
AttributeMatchOp::Eq => "",
AttributeMatchOp::Includes => "~",
AttributeMatchOp::DashMatch => "|",
AttributeMatchOp::Prefix => "^",
AttributeMatchOp::Suffix => "$",
AttributeMatchOp::Substring => "*",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C, u8)]
pub enum CssPathPseudoSelector {
First,
Last,
NthChild(CssNthChildSelector),
Hover,
Active,
Focus,
Lang(AzString),
Backdrop,
Dragging,
DragOver,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C, u8)]
pub enum CssNthChildSelector {
Number(u32),
Even,
Odd,
Pattern(CssNthChildPattern),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub struct CssNthChildPattern {
pub pattern_repeat: u32,
pub offset: u32,
}
impl fmt::Display for CssNthChildSelector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::CssNthChildSelector::*;
match &self {
Number(u) => write!(f, "{}", u),
Even => write!(f, "even"),
Odd => write!(f, "odd"),
Pattern(p) => write!(f, "{}n + {}", p.pattern_repeat, p.offset),
}
}
}
impl fmt::Display for CssPathPseudoSelector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::CssPathPseudoSelector::*;
match &self {
First => write!(f, "first"),
Last => write!(f, "last"),
NthChild(u) => write!(f, "nth-child({})", u),
Hover => write!(f, "hover"),
Active => write!(f, "active"),
Focus => write!(f, "focus"),
Lang(lang) => write!(f, "lang({})", lang.as_str()),
Backdrop => write!(f, "backdrop"),
Dragging => write!(f, "dragging"),
DragOver => write!(f, "drag-over"),
}
}
}
impl Css {
pub fn empty() -> Self {
Default::default()
}
pub fn sort_by_specificity(&mut self) {
self.rules.as_mut().sort_by(|a, b| {
a.priority.cmp(&b.priority)
.then_with(|| get_specificity(&a.path).cmp(&get_specificity(&b.path)))
});
}
pub fn rules<'a>(&'a self) -> core::slice::Iter<'a, CssRuleBlock> {
self.rules.as_ref().iter()
}
pub fn iter_inline_properties<'a>(
&'a self,
) -> impl Iterator<
Item = (
&'a crate::props::property::CssProperty,
&'a DynamicSelectorVec,
),
> + 'a {
self.rules.as_ref().iter().flat_map(|r| {
r.declarations.as_ref().iter().filter_map(move |d| match d {
CssDeclaration::Static(p) => Some((p, &r.conditions)),
CssDeclaration::Dynamic(_) => None,
})
})
}
}
#[cfg(test)]
mod priority_sort_tests {
use super::*;
use crate::css::rule_priority;
fn rule_with(priority: u8, selectors: Vec<CssPathSelector>) -> CssRuleBlock {
CssRuleBlock {
path: CssPath { selectors: selectors.into() },
declarations: Vec::new().into(),
conditions: DynamicSelectorVec::from_const_slice(&[]),
priority,
}
}
#[test]
fn sort_by_priority_then_specificity() {
let mut css = Css::new(vec![
rule_with(rule_priority::AUTHOR, vec![CssPathSelector::Global]),
rule_with(rule_priority::UA, vec![
CssPathSelector::Id("ua-id".to_string().into()),
CssPathSelector::Class("ua-class".to_string().into()),
]),
rule_with(rule_priority::AUTHOR, vec![
CssPathSelector::Id("a-id".to_string().into()),
]),
rule_with(rule_priority::SYSTEM, vec![CssPathSelector::Global]),
]);
css.sort_by_specificity();
let priorities: Vec<u8> = css.rules.as_ref().iter().map(|r| r.priority).collect();
assert_eq!(
priorities,
vec![rule_priority::UA, rule_priority::SYSTEM, rule_priority::AUTHOR, rule_priority::AUTHOR],
"rules must sort by layer first; specificity only breaks ties within a layer"
);
let last_two_specificity: Vec<_> = css.rules.as_ref().iter()
.filter(|r| r.priority == rule_priority::AUTHOR)
.map(|r| get_specificity(&r.path))
.collect();
assert!(last_two_specificity[0] < last_two_specificity[1]);
}
}
pub fn get_specificity(path: &CssPath) -> (usize, usize, usize, usize) {
let id_count = path
.selectors
.iter()
.filter(|x| matches!(x, CssPathSelector::Id(_)))
.count();
let class_count = path
.selectors
.iter()
.filter(|x| {
matches!(
x,
CssPathSelector::Class(_)
| CssPathSelector::PseudoSelector(_)
| CssPathSelector::Attribute(_)
)
})
.count();
let div_count = path
.selectors
.iter()
.filter(|x| matches!(x, CssPathSelector::Type(_)))
.count();
(id_count, class_count, div_count, path.selectors.len())
}