1use alloc::{string::String, vec::Vec};
12use core::fmt;
13
14use crate::{
15 corety::OptionString,
16 dynamic_selector::DynamicSelectorVec,
17 props::property::{CssProperty, CssPropertyType},
18 AzString,
19};
20
21#[derive(Debug, Default, PartialEq, PartialOrd, Clone)]
29#[repr(C)]
30pub struct Css {
31 pub rules: CssRuleBlockVec,
34}
35
36impl_option!(
37 Css,
38 OptionCss,
39 copy = false,
40 [Debug, Clone, PartialEq, PartialOrd]
41);
42
43impl_vec!(Css, CssVec, CssVecDestructor, CssVecDestructorType, CssVecSlice, OptionCss);
44impl_vec_mut!(Css, CssVec);
45impl_vec_debug!(Css, CssVec);
46impl_vec_partialord!(Css, CssVec);
47impl_vec_clone!(Css, CssVec, CssVecDestructor);
48impl_vec_partialeq!(Css, CssVec);
49
50impl_vec!(CssRuleBlock, CssRuleBlockVec, CssRuleBlockVecDestructor, CssRuleBlockVecDestructorType, CssRuleBlockVecSlice, OptionCssRuleBlock);
51impl_vec_mut!(CssRuleBlock, CssRuleBlockVec);
52impl_vec_debug!(CssRuleBlock, CssRuleBlockVec);
53impl_vec_partialord!(CssRuleBlock, CssRuleBlockVec);
54impl_vec_clone!(CssRuleBlock, CssRuleBlockVec, CssRuleBlockVecDestructor);
55impl_vec_partialeq!(CssRuleBlock, CssRuleBlockVec);
56
57impl Css {
58 pub fn is_empty(&self) -> bool {
59 self.rules.as_ref().is_empty()
60 }
61
62 pub fn new(rules: Vec<CssRuleBlock>) -> Self {
63 Self {
64 rules: rules.into(),
65 }
66 }
67
68 #[cfg(feature = "parser")]
69 pub fn from_string(s: crate::AzString) -> Self {
70 crate::parser2::new_from_str(s.as_str()).0
71 }
72
73 #[cfg(feature = "parser")]
81 pub fn parse_inline(style: &str) -> Self {
82 use alloc::string::ToString;
83 let mut wrapped = String::with_capacity(style.len() + 6);
84 wrapped.push_str("* {\n");
85 wrapped.push_str(style);
86 wrapped.push_str("\n}");
87 let (mut css, _warnings) = crate::parser2::new_from_str(&wrapped);
88 for rule in css.rules.as_mut() {
89 rule.priority = rule_priority::INLINE;
90 }
91 css
92 }
93
94 #[cfg(feature = "parser")]
95 pub fn from_string_with_warnings(
96 s: crate::AzString,
97 ) -> (Self, Vec<crate::parser2::CssParseWarnMsgOwned>) {
98 let (css, warnings) = crate::parser2::new_from_str(s.as_str());
99 (
100 css,
101 warnings
102 .into_iter()
103 .map(|w| crate::parser2::CssParseWarnMsgOwned {
104 warning: w.warning.to_contained(),
105 location: w.location,
106 })
107 .collect(),
108 )
109 }
110}
111
112impl From<Vec<CssRuleBlock>> for Css {
113 fn from(rules: Vec<CssRuleBlock>) -> Self {
114 Self {
115 rules: rules.into(),
116 }
117 }
118}
119
120impl Eq for Css {}
124impl Ord for Css {
125 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
126 self.rules.as_ref().len().cmp(&other.rules.as_ref().len())
127 }
128}
129impl Eq for CssRuleBlock {}
130impl Ord for CssRuleBlock {
131 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
132 self.path.cmp(&other.path).then_with(|| self.declarations.cmp(&other.declarations))
136 }
137}
138
139impl From<crate::dynamic_selector::CssPropertyWithConditionsVec> for Css {
148 fn from(props: crate::dynamic_selector::CssPropertyWithConditionsVec) -> Self {
149 let rules: Vec<CssRuleBlock> = props.into_library_owned_vec().into_iter().map(|p| {
150 CssRuleBlock {
151 path: CssPath { selectors: Vec::new().into() },
152 declarations: alloc::vec![CssDeclaration::Static(p.property)].into(),
153 conditions: p.apply_if,
154 priority: rule_priority::INLINE,
155 }
156 }).collect();
157 Css { rules: rules.into() }
158 }
159}
160
161#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
163#[repr(C, u8)]
164pub enum CssDeclaration {
165 Static(CssProperty),
167 Dynamic(DynamicCssProperty),
169}
170
171impl_option!(
172 CssDeclaration,
173 OptionCssDeclaration,
174 copy = false,
175 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
176);
177
178impl CssDeclaration {
179 pub const fn new_static(prop: CssProperty) -> Self {
180 CssDeclaration::Static(prop)
181 }
182
183 pub const fn new_dynamic(prop: DynamicCssProperty) -> Self {
184 CssDeclaration::Dynamic(prop)
185 }
186
187 pub fn get_type(&self) -> CssPropertyType {
189 use self::CssDeclaration::*;
190 match self {
191 Static(s) => s.get_type(),
192 Dynamic(d) => d.default_value.get_type(),
193 }
194 }
195
196 pub fn is_inheritable(&self) -> bool {
199 use self::CssDeclaration::*;
200 match self {
201 Static(s) => s.get_type().is_inheritable(),
202 Dynamic(d) => d.is_inheritable(),
203 }
204 }
205
206 pub fn can_trigger_relayout(&self) -> bool {
209 use self::CssDeclaration::*;
210 match self {
211 Static(s) => s.get_type().can_trigger_relayout(),
212 Dynamic(d) => d.can_trigger_relayout(),
213 }
214 }
215
216 pub fn to_str(&self) -> String {
217 use self::CssDeclaration::*;
218 match self {
219 Static(s) => format!("{:?}", s),
220 Dynamic(d) => format!("var(--{}, {:?})", d.dynamic_id, d.default_value),
221 }
222 }
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
246#[repr(C)]
247pub struct DynamicCssProperty {
248 pub dynamic_id: AzString,
250 pub default_value: CssProperty,
252}
253
254#[repr(C, u8)]
262pub enum BoxOrStatic<T> {
263 Boxed(*mut T),
265 Static(*const T),
267}
268
269impl<T> BoxOrStatic<T> {
270 #[inline]
272 pub fn heap(value: T) -> Self {
273 BoxOrStatic::Boxed(Box::into_raw(Box::new(value)))
274 }
275
276 #[inline]
282 pub fn as_ref(&self) -> &T {
283 match self {
284 BoxOrStatic::Boxed(ptr) => unsafe {
285 debug_assert!(!ptr.is_null(), "BoxOrStatic::Boxed contained a null pointer");
286 &**ptr
287 },
288 BoxOrStatic::Static(ptr) => unsafe {
289 debug_assert!(!ptr.is_null(), "BoxOrStatic::Static contained a null pointer");
290 &**ptr
291 },
292 }
293 }
294
295 #[inline]
298 pub fn as_mut(&mut self) -> &mut T {
299 match self {
300 BoxOrStatic::Boxed(ptr) => unsafe { &mut **ptr },
301 BoxOrStatic::Static(_) => panic!("Cannot mutate a static BoxOrStatic value"),
302 }
303 }
304
305 #[inline]
307 pub fn into_inner(self) -> T where T: Clone {
308 let val = self.as_ref().clone();
309 core::mem::forget(self);
311 val
312 }
313}
314
315impl<T> Drop for BoxOrStatic<T> {
316 fn drop(&mut self) {
317 if let BoxOrStatic::Boxed(ptr) = self {
318 if !ptr.is_null() {
319 unsafe { drop(Box::from_raw(*ptr)); }
320 *ptr = core::ptr::null_mut();
321 }
322 }
323 }
324}
325
326impl<T: Clone> Clone for BoxOrStatic<T> {
327 fn clone(&self) -> Self {
328 match self {
329 BoxOrStatic::Boxed(ptr) => {
330 let val = unsafe { &**ptr }.clone();
331 BoxOrStatic::Boxed(Box::into_raw(Box::new(val)))
332 }
333 BoxOrStatic::Static(ptr) => BoxOrStatic::Static(*ptr),
334 }
335 }
336}
337
338impl<T: core::fmt::Debug> core::fmt::Debug for BoxOrStatic<T> {
339 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
340 self.as_ref().fmt(f)
341 }
342}
343
344impl<T: core::fmt::Display> core::fmt::Display for BoxOrStatic<T> {
345 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
346 self.as_ref().fmt(f)
347 }
348}
349
350impl<T: PartialEq> PartialEq for BoxOrStatic<T> {
351 fn eq(&self, other: &Self) -> bool {
352 self.as_ref() == other.as_ref()
353 }
354}
355
356impl<T: Eq> Eq for BoxOrStatic<T> {}
357
358impl<T: core::hash::Hash> core::hash::Hash for BoxOrStatic<T> {
359 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
360 self.as_ref().hash(state)
361 }
362}
363
364impl<T: PartialOrd> PartialOrd for BoxOrStatic<T> {
365 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
366 self.as_ref().partial_cmp(other.as_ref())
367 }
368}
369
370impl<T: Ord> Ord for BoxOrStatic<T> {
371 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
372 self.as_ref().cmp(other.as_ref())
373 }
374}
375
376impl<T> core::ops::Deref for BoxOrStatic<T> {
377 type Target = T;
378 #[inline]
379 fn deref(&self) -> &T {
380 self.as_ref()
381 }
382}
383
384impl<T: Default> Default for BoxOrStatic<T> {
385 fn default() -> Self {
386 BoxOrStatic::heap(T::default())
387 }
388}
389
390impl<T: PrintAsCssValue> PrintAsCssValue for BoxOrStatic<T> {
391 fn print_as_css_value(&self) -> String {
392 self.as_ref().print_as_css_value()
393 }
394}
395
396unsafe impl<T: Send + 'static> Send for BoxOrStatic<T> {}
398unsafe impl<T: Sync + 'static> Sync for BoxOrStatic<T> {}
400
401pub type BoxOrStaticStyleBoxShadow = BoxOrStatic<crate::props::style::box_shadow::StyleBoxShadow>;
403
404pub type BoxOrStaticString = BoxOrStatic<crate::AzString>;
406
407#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
410#[repr(C, u8)] pub enum CssPropertyValue<T> {
412 Auto,
413 None,
414 Initial,
415 Inherit,
416 Revert,
417 Unset,
418 Exact(T),
419}
420
421pub trait PrintAsCssValue {
423 fn print_as_css_value(&self) -> String;
424}
425
426impl<T: PrintAsCssValue> CssPropertyValue<T> {
427 pub fn get_css_value_fmt(&self) -> String {
428 match self {
429 CssPropertyValue::Auto => "auto".to_string(),
430 CssPropertyValue::None => "none".to_string(),
431 CssPropertyValue::Initial => "initial".to_string(),
432 CssPropertyValue::Inherit => "inherit".to_string(),
433 CssPropertyValue::Revert => "revert".to_string(),
434 CssPropertyValue::Unset => "unset".to_string(),
435 CssPropertyValue::Exact(e) => e.print_as_css_value(),
436 }
437 }
438}
439
440impl<T: fmt::Display> fmt::Display for CssPropertyValue<T> {
441 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
442 use self::CssPropertyValue::*;
443 match self {
444 Auto => write!(f, "auto"),
445 None => write!(f, "none"),
446 Initial => write!(f, "initial"),
447 Inherit => write!(f, "inherit"),
448 Revert => write!(f, "revert"),
449 Unset => write!(f, "unset"),
450 Exact(e) => write!(f, "{}", e),
451 }
452 }
453}
454
455impl<T> From<T> for CssPropertyValue<T> {
456 fn from(c: T) -> Self {
457 CssPropertyValue::Exact(c)
458 }
459}
460
461impl<T> CssPropertyValue<T> {
462 #[inline]
465 pub fn map_property<F: Fn(T) -> U, U>(self, map_fn: F) -> CssPropertyValue<U> {
466 match self {
467 CssPropertyValue::Exact(c) => CssPropertyValue::Exact(map_fn(c)),
468 CssPropertyValue::Auto => CssPropertyValue::Auto,
469 CssPropertyValue::None => CssPropertyValue::None,
470 CssPropertyValue::Initial => CssPropertyValue::Initial,
471 CssPropertyValue::Inherit => CssPropertyValue::Inherit,
472 CssPropertyValue::Revert => CssPropertyValue::Revert,
473 CssPropertyValue::Unset => CssPropertyValue::Unset,
474 }
475 }
476
477 #[inline]
478 pub fn get_property(&self) -> Option<&T> {
479 match self {
480 CssPropertyValue::Exact(c) => Some(c),
481 _ => None,
482 }
483 }
484
485 #[inline]
486 pub fn get_property_owned(self) -> Option<T> {
487 match self {
488 CssPropertyValue::Exact(c) => Some(c),
489 _ => None,
490 }
491 }
492
493 #[inline]
494 pub fn is_auto(&self) -> bool {
495 matches!(self, CssPropertyValue::Auto)
496 }
497
498 #[inline]
499 pub fn is_none(&self) -> bool {
500 matches!(self, CssPropertyValue::None)
501 }
502
503 #[inline]
504 pub fn is_initial(&self) -> bool {
505 matches!(self, CssPropertyValue::Initial)
506 }
507
508 #[inline]
509 pub fn is_inherit(&self) -> bool {
510 matches!(self, CssPropertyValue::Inherit)
511 }
512
513 #[inline]
514 pub fn is_revert(&self) -> bool {
515 matches!(self, CssPropertyValue::Revert)
516 }
517
518 #[inline]
519 pub fn is_unset(&self) -> bool {
520 matches!(self, CssPropertyValue::Unset)
521 }
522}
523
524impl<T: Default> CssPropertyValue<T> {
525 #[inline]
526 pub fn get_property_or_default(self) -> Option<T> {
527 match self {
528 CssPropertyValue::Auto | CssPropertyValue::Initial => Some(T::default()),
529 CssPropertyValue::Exact(c) => Some(c),
530 CssPropertyValue::None
531 | CssPropertyValue::Inherit
532 | CssPropertyValue::Revert
533 | CssPropertyValue::Unset => None,
534 }
535 }
536}
537
538impl<T: Default> Default for CssPropertyValue<T> {
539 #[inline]
540 fn default() -> Self {
541 CssPropertyValue::Exact(T::default())
542 }
543}
544
545impl DynamicCssProperty {
546 pub fn is_inheritable(&self) -> bool {
547 false
551 }
552
553 pub fn can_trigger_relayout(&self) -> bool {
554 self.default_value.get_type().can_trigger_relayout()
555 }
556}
557
558pub mod rule_priority {
566 pub const UA: u8 = 0;
570
571 pub const SYSTEM: u8 = 10;
576
577 pub const AUTHOR: u8 = 20;
580
581 pub const INLINE: u8 = 30;
585
586 pub const RUNTIME: u8 = 50;
593}
594
595#[derive(Debug, Default, Clone, PartialEq)]
601#[repr(C)]
602pub struct CssRuleBlock {
603 pub path: CssPath,
605 pub declarations: CssDeclarationVec,
608 pub conditions: DynamicSelectorVec,
611 pub priority: u8,
615}
616
617impl_option!(
618 CssRuleBlock,
619 OptionCssRuleBlock,
620 copy = false,
621 [Debug, Clone, PartialEq, PartialOrd]
622);
623
624impl PartialOrd for CssRuleBlock {
625 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
626 match self.path.partial_cmp(&other.path) {
628 Some(core::cmp::Ordering::Equal) => self.declarations.partial_cmp(&other.declarations),
629 ord => ord,
630 }
631 }
632}
633
634impl_vec!(CssDeclaration, CssDeclarationVec, CssDeclarationVecDestructor, CssDeclarationVecDestructorType, CssDeclarationVecSlice, OptionCssDeclaration);
635impl_vec_mut!(CssDeclaration, CssDeclarationVec);
636impl_vec_debug!(CssDeclaration, CssDeclarationVec);
637impl_vec_partialord!(CssDeclaration, CssDeclarationVec);
638impl_vec_ord!(CssDeclaration, CssDeclarationVec);
639impl_vec_clone!(
640 CssDeclaration,
641 CssDeclarationVec,
642 CssDeclarationVecDestructor
643);
644impl_vec_partialeq!(CssDeclaration, CssDeclarationVec);
645impl_vec_eq!(CssDeclaration, CssDeclarationVec);
646impl_vec_hash!(CssDeclaration, CssDeclarationVec);
647
648impl CssRuleBlock {
649 pub fn new(path: CssPath, declarations: Vec<CssDeclaration>) -> Self {
650 Self {
651 path,
652 declarations: declarations.into(),
653 conditions: DynamicSelectorVec::from_const_slice(&[]),
654 priority: rule_priority::AUTHOR,
655 }
656 }
657
658 pub fn with_conditions(
659 path: CssPath,
660 declarations: Vec<CssDeclaration>,
661 conditions: Vec<crate::dynamic_selector::DynamicSelector>,
662 ) -> Self {
663 Self {
664 path,
665 declarations: declarations.into(),
666 conditions: conditions.into(),
667 priority: rule_priority::AUTHOR,
668 }
669 }
670}
671
672pub type CssContentGroup<'a> = Vec<&'a CssPathSelector>;
674
675#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
677#[repr(C)]
678pub enum NodeTypeTag {
679 Html,
681 Head,
682 Body,
683
684 Div,
686 P,
687 Article,
688 Section,
689 Nav,
690 Aside,
691 Header,
692 Footer,
693 Main,
694 Figure,
695 FigCaption,
696
697 H1,
699 H2,
700 H3,
701 H4,
702 H5,
703 H6,
704
705 Br,
707 Hr,
708 Pre,
709 BlockQuote,
710 Address,
711 Details,
712 Summary,
713 Dialog,
714
715 Ul,
717 Ol,
718 Li,
719 Dl,
720 Dt,
721 Dd,
722 Menu,
723 MenuItem,
724 Dir,
725
726 Table,
728 Caption,
729 THead,
730 TBody,
731 TFoot,
732 Tr,
733 Th,
734 Td,
735 ColGroup,
736 Col,
737
738 Form,
740 FieldSet,
741 Legend,
742 Label,
743 Input,
744 Button,
745 Select,
746 OptGroup,
747 SelectOption,
748 TextArea,
749 Output,
750 Progress,
751 Meter,
752 DataList,
753
754 Span,
756 A,
757 Em,
758 Strong,
759 B,
760 I,
761 U,
762 S,
763 Mark,
764 Del,
765 Ins,
766 Code,
767 Samp,
768 Kbd,
769 Var,
770 Cite,
771 Dfn,
772 Abbr,
773 Acronym,
774 Q,
775 Time,
776 Sub,
777 Sup,
778 Small,
779 Big,
780 Bdo,
781 Bdi,
782 Wbr,
783 Ruby,
784 Rt,
785 Rtc,
786 Rp,
787 Data,
788
789 Canvas,
791 Object,
792 Param,
793 Embed,
794 Audio,
795 Video,
796 Source,
797 Track,
798 Map,
799 Area,
800 Svg,
801 SvgPath,
803 SvgCircle,
805 SvgRect,
807 SvgEllipse,
809 SvgLine,
811 SvgPolygon,
813 SvgPolyline,
815 SvgG,
817
818 SvgDefs,
821 SvgSymbol,
823 SvgUse,
825 SvgSwitch,
827
828 SvgText,
831 SvgTspan,
833 SvgTextPath,
835
836 SvgLinearGradient,
839 SvgRadialGradient,
841 SvgStop,
843 SvgPattern,
845
846 SvgClipPathElement,
849 SvgMask,
851
852 SvgFilter,
855 SvgFeBlend,
857 SvgFeColorMatrix,
859 SvgFeComponentTransfer,
861 SvgFeComposite,
863 SvgFeConvolveMatrix,
865 SvgFeDiffuseLighting,
867 SvgFeDisplacementMap,
869 SvgFeDistantLight,
871 SvgFeDropShadow,
873 SvgFeFlood,
875 SvgFeFuncR,
877 SvgFeFuncG,
879 SvgFeFuncB,
881 SvgFeFuncA,
883 SvgFeGaussianBlur,
885 SvgFeImage,
887 SvgFeMerge,
889 SvgFeMergeNode,
891 SvgFeMorphology,
893 SvgFeOffset,
895 SvgFePointLight,
897 SvgFeSpecularLighting,
899 SvgFeSpotLight,
901 SvgFeTile,
903 SvgFeTurbulence,
905
906 SvgMarker,
909 SvgImage,
911 SvgForeignObject,
913
914 SvgTitle,
917 SvgDesc,
919 SvgMetadata,
921 SvgA,
923 SvgView,
925 SvgStyle,
927 SvgScript,
929
930 SvgAnimate,
933 SvgAnimateMotion,
935 SvgAnimateTransform,
937 SvgSet,
939 SvgMpath,
941
942 Title,
944 Meta,
945 Link,
946 Script,
947 Style,
948 Base,
949
950 Text,
952 Img,
953 VirtualView,
954 Icon,
956 GeolocationProbe,
959
960 Before,
962 After,
963 Marker,
964 Placeholder,
965}
966
967#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
969pub enum NodeTypeTagParseError<'a> {
970 Invalid(&'a str),
971}
972
973impl<'a> fmt::Display for NodeTypeTagParseError<'a> {
974 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
975 match &self {
976 NodeTypeTagParseError::Invalid(e) => write!(f, "Invalid node type: {}", e),
977 }
978 }
979}
980
981#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
983#[repr(C, u8)]
984pub enum NodeTypeTagParseErrorOwned {
985 Invalid(AzString),
986}
987
988impl<'a> NodeTypeTagParseError<'a> {
989 pub fn to_contained(&self) -> NodeTypeTagParseErrorOwned {
990 match self {
991 NodeTypeTagParseError::Invalid(s) => NodeTypeTagParseErrorOwned::Invalid(s.to_string().into()),
992 }
993 }
994}
995
996impl NodeTypeTagParseErrorOwned {
997 pub fn to_shared<'a>(&'a self) -> NodeTypeTagParseError<'a> {
998 match self {
999 NodeTypeTagParseErrorOwned::Invalid(s) => NodeTypeTagParseError::Invalid(s),
1000 }
1001 }
1002}
1003
1004impl NodeTypeTag {
1006 pub fn from_str(css_key: &str) -> Result<Self, NodeTypeTagParseError<'_>> {
1007 match css_key {
1008 "html" => Ok(NodeTypeTag::Html),
1010 "head" => Ok(NodeTypeTag::Head),
1011 "body" => Ok(NodeTypeTag::Body),
1012
1013 "div" => Ok(NodeTypeTag::Div),
1015 "p" => Ok(NodeTypeTag::P),
1016 "article" => Ok(NodeTypeTag::Article),
1017 "section" => Ok(NodeTypeTag::Section),
1018 "nav" => Ok(NodeTypeTag::Nav),
1019 "aside" => Ok(NodeTypeTag::Aside),
1020 "header" => Ok(NodeTypeTag::Header),
1021 "footer" => Ok(NodeTypeTag::Footer),
1022 "main" => Ok(NodeTypeTag::Main),
1023 "figure" => Ok(NodeTypeTag::Figure),
1024 "figcaption" => Ok(NodeTypeTag::FigCaption),
1025
1026 "h1" => Ok(NodeTypeTag::H1),
1028 "h2" => Ok(NodeTypeTag::H2),
1029 "h3" => Ok(NodeTypeTag::H3),
1030 "h4" => Ok(NodeTypeTag::H4),
1031 "h5" => Ok(NodeTypeTag::H5),
1032 "h6" => Ok(NodeTypeTag::H6),
1033
1034 "br" => Ok(NodeTypeTag::Br),
1036 "hr" => Ok(NodeTypeTag::Hr),
1037 "pre" => Ok(NodeTypeTag::Pre),
1038 "blockquote" => Ok(NodeTypeTag::BlockQuote),
1039 "address" => Ok(NodeTypeTag::Address),
1040 "details" => Ok(NodeTypeTag::Details),
1041 "summary" => Ok(NodeTypeTag::Summary),
1042 "dialog" => Ok(NodeTypeTag::Dialog),
1043
1044 "ul" => Ok(NodeTypeTag::Ul),
1046 "ol" => Ok(NodeTypeTag::Ol),
1047 "li" => Ok(NodeTypeTag::Li),
1048 "dl" => Ok(NodeTypeTag::Dl),
1049 "dt" => Ok(NodeTypeTag::Dt),
1050 "dd" => Ok(NodeTypeTag::Dd),
1051 "menu" => Ok(NodeTypeTag::Menu),
1052 "menuitem" => Ok(NodeTypeTag::MenuItem),
1053 "dir" => Ok(NodeTypeTag::Dir),
1054
1055 "table" => Ok(NodeTypeTag::Table),
1057 "caption" => Ok(NodeTypeTag::Caption),
1058 "thead" => Ok(NodeTypeTag::THead),
1059 "tbody" => Ok(NodeTypeTag::TBody),
1060 "tfoot" => Ok(NodeTypeTag::TFoot),
1061 "tr" => Ok(NodeTypeTag::Tr),
1062 "th" => Ok(NodeTypeTag::Th),
1063 "td" => Ok(NodeTypeTag::Td),
1064 "colgroup" => Ok(NodeTypeTag::ColGroup),
1065 "col" => Ok(NodeTypeTag::Col),
1066
1067 "form" => Ok(NodeTypeTag::Form),
1069 "fieldset" => Ok(NodeTypeTag::FieldSet),
1070 "legend" => Ok(NodeTypeTag::Legend),
1071 "label" => Ok(NodeTypeTag::Label),
1072 "input" => Ok(NodeTypeTag::Input),
1073 "button" => Ok(NodeTypeTag::Button),
1074 "select" => Ok(NodeTypeTag::Select),
1075 "optgroup" => Ok(NodeTypeTag::OptGroup),
1076 "option" => Ok(NodeTypeTag::SelectOption),
1077 "textarea" => Ok(NodeTypeTag::TextArea),
1078 "output" => Ok(NodeTypeTag::Output),
1079 "progress" => Ok(NodeTypeTag::Progress),
1080 "meter" => Ok(NodeTypeTag::Meter),
1081 "datalist" => Ok(NodeTypeTag::DataList),
1082
1083 "span" => Ok(NodeTypeTag::Span),
1085 "a" => Ok(NodeTypeTag::A),
1086 "em" => Ok(NodeTypeTag::Em),
1087 "strong" => Ok(NodeTypeTag::Strong),
1088 "b" => Ok(NodeTypeTag::B),
1089 "i" => Ok(NodeTypeTag::I),
1090 "u" => Ok(NodeTypeTag::U),
1091 "s" => Ok(NodeTypeTag::S),
1092 "mark" => Ok(NodeTypeTag::Mark),
1093 "del" => Ok(NodeTypeTag::Del),
1094 "ins" => Ok(NodeTypeTag::Ins),
1095 "code" => Ok(NodeTypeTag::Code),
1096 "samp" => Ok(NodeTypeTag::Samp),
1097 "kbd" => Ok(NodeTypeTag::Kbd),
1098 "var" => Ok(NodeTypeTag::Var),
1099 "cite" => Ok(NodeTypeTag::Cite),
1100 "dfn" => Ok(NodeTypeTag::Dfn),
1101 "abbr" => Ok(NodeTypeTag::Abbr),
1102 "acronym" => Ok(NodeTypeTag::Acronym),
1103 "q" => Ok(NodeTypeTag::Q),
1104 "time" => Ok(NodeTypeTag::Time),
1105 "sub" => Ok(NodeTypeTag::Sub),
1106 "sup" => Ok(NodeTypeTag::Sup),
1107 "small" => Ok(NodeTypeTag::Small),
1108 "big" => Ok(NodeTypeTag::Big),
1109 "bdo" => Ok(NodeTypeTag::Bdo),
1110 "bdi" => Ok(NodeTypeTag::Bdi),
1111 "wbr" => Ok(NodeTypeTag::Wbr),
1112 "ruby" => Ok(NodeTypeTag::Ruby),
1113 "rt" => Ok(NodeTypeTag::Rt),
1114 "rtc" => Ok(NodeTypeTag::Rtc),
1115 "rp" => Ok(NodeTypeTag::Rp),
1116 "data" => Ok(NodeTypeTag::Data),
1117
1118 "canvas" => Ok(NodeTypeTag::Canvas),
1120 "object" => Ok(NodeTypeTag::Object),
1121 "param" => Ok(NodeTypeTag::Param),
1122 "embed" => Ok(NodeTypeTag::Embed),
1123 "audio" => Ok(NodeTypeTag::Audio),
1124 "video" => Ok(NodeTypeTag::Video),
1125 "source" => Ok(NodeTypeTag::Source),
1126 "track" => Ok(NodeTypeTag::Track),
1127 "map" => Ok(NodeTypeTag::Map),
1128 "area" => Ok(NodeTypeTag::Area),
1129 "svg" => Ok(NodeTypeTag::Svg),
1130
1131 "path" => Ok(NodeTypeTag::SvgPath),
1133 "circle" => Ok(NodeTypeTag::SvgCircle),
1134 "rect" => Ok(NodeTypeTag::SvgRect),
1135 "ellipse" => Ok(NodeTypeTag::SvgEllipse),
1136 "line" => Ok(NodeTypeTag::SvgLine),
1137 "polygon" => Ok(NodeTypeTag::SvgPolygon),
1138 "polyline" => Ok(NodeTypeTag::SvgPolyline),
1139 "g" => Ok(NodeTypeTag::SvgG),
1140
1141 "defs" => Ok(NodeTypeTag::SvgDefs),
1143 "symbol" => Ok(NodeTypeTag::SvgSymbol),
1144 "use" => Ok(NodeTypeTag::SvgUse),
1145 "switch" => Ok(NodeTypeTag::SvgSwitch),
1146
1147 "svg:text" => Ok(NodeTypeTag::SvgText),
1149 "tspan" => Ok(NodeTypeTag::SvgTspan),
1150 "textpath" => Ok(NodeTypeTag::SvgTextPath),
1151
1152 "lineargradient" => Ok(NodeTypeTag::SvgLinearGradient),
1154 "radialgradient" => Ok(NodeTypeTag::SvgRadialGradient),
1155 "stop" => Ok(NodeTypeTag::SvgStop),
1156 "pattern" => Ok(NodeTypeTag::SvgPattern),
1157
1158 "clippath" => Ok(NodeTypeTag::SvgClipPathElement),
1160 "mask" => Ok(NodeTypeTag::SvgMask),
1161
1162 "filter" => Ok(NodeTypeTag::SvgFilter),
1164 "feblend" => Ok(NodeTypeTag::SvgFeBlend),
1165 "fecolormatrix" => Ok(NodeTypeTag::SvgFeColorMatrix),
1166 "fecomponenttransfer" => Ok(NodeTypeTag::SvgFeComponentTransfer),
1167 "fecomposite" => Ok(NodeTypeTag::SvgFeComposite),
1168 "feconvolvematrix" => Ok(NodeTypeTag::SvgFeConvolveMatrix),
1169 "fediffuselighting" => Ok(NodeTypeTag::SvgFeDiffuseLighting),
1170 "fedisplacementmap" => Ok(NodeTypeTag::SvgFeDisplacementMap),
1171 "fedistantlight" => Ok(NodeTypeTag::SvgFeDistantLight),
1172 "fedropshadow" => Ok(NodeTypeTag::SvgFeDropShadow),
1173 "feflood" => Ok(NodeTypeTag::SvgFeFlood),
1174 "fefuncr" => Ok(NodeTypeTag::SvgFeFuncR),
1175 "fefuncg" => Ok(NodeTypeTag::SvgFeFuncG),
1176 "fefuncb" => Ok(NodeTypeTag::SvgFeFuncB),
1177 "fefunca" => Ok(NodeTypeTag::SvgFeFuncA),
1178 "fegaussianblur" => Ok(NodeTypeTag::SvgFeGaussianBlur),
1179 "feimage" => Ok(NodeTypeTag::SvgFeImage),
1180 "femerge" => Ok(NodeTypeTag::SvgFeMerge),
1181 "femergenode" => Ok(NodeTypeTag::SvgFeMergeNode),
1182 "femorphology" => Ok(NodeTypeTag::SvgFeMorphology),
1183 "feoffset" => Ok(NodeTypeTag::SvgFeOffset),
1184 "fepointlight" => Ok(NodeTypeTag::SvgFePointLight),
1185 "fespecularlighting" => Ok(NodeTypeTag::SvgFeSpecularLighting),
1186 "fespotlight" => Ok(NodeTypeTag::SvgFeSpotLight),
1187 "fetile" => Ok(NodeTypeTag::SvgFeTile),
1188 "feturbulence" => Ok(NodeTypeTag::SvgFeTurbulence),
1189
1190 "image" | "svg:image" => Ok(NodeTypeTag::SvgImage),
1192 "svg:marker" => Ok(NodeTypeTag::SvgMarker),
1193 "foreignobject" => Ok(NodeTypeTag::SvgForeignObject),
1194
1195 "svg:title" => Ok(NodeTypeTag::SvgTitle),
1197 "svg:a" => Ok(NodeTypeTag::SvgA),
1198 "svg:style" => Ok(NodeTypeTag::SvgStyle),
1199 "svg:script" => Ok(NodeTypeTag::SvgScript),
1200 "desc" => Ok(NodeTypeTag::SvgDesc),
1201 "metadata" => Ok(NodeTypeTag::SvgMetadata),
1202 "view" => Ok(NodeTypeTag::SvgView),
1203
1204 "animate" => Ok(NodeTypeTag::SvgAnimate),
1206 "animatemotion" => Ok(NodeTypeTag::SvgAnimateMotion),
1207 "animatetransform" => Ok(NodeTypeTag::SvgAnimateTransform),
1208 "set" => Ok(NodeTypeTag::SvgSet),
1209 "mpath" => Ok(NodeTypeTag::SvgMpath),
1210
1211 "title" => Ok(NodeTypeTag::Title),
1213 "meta" => Ok(NodeTypeTag::Meta),
1214 "link" => Ok(NodeTypeTag::Link),
1215 "script" => Ok(NodeTypeTag::Script),
1216 "style" => Ok(NodeTypeTag::Style),
1217 "base" => Ok(NodeTypeTag::Base),
1218
1219 "img" => Ok(NodeTypeTag::Img),
1221 "virtual-view" | "iframe" => Ok(NodeTypeTag::VirtualView),
1222 "icon" => Ok(NodeTypeTag::Icon),
1223 "geolocation-probe" => Ok(NodeTypeTag::GeolocationProbe),
1224
1225 "before" | "::before" => Ok(NodeTypeTag::Before),
1227 "after" | "::after" => Ok(NodeTypeTag::After),
1228 "marker" | "::marker" => Ok(NodeTypeTag::Marker),
1229 "placeholder" | "::placeholder" => Ok(NodeTypeTag::Placeholder),
1230
1231 other => Err(NodeTypeTagParseError::Invalid(other)),
1232 }
1233 }
1234}
1235
1236impl fmt::Display for NodeTypeTag {
1237 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1238 match self {
1239 NodeTypeTag::Html => write!(f, "html"),
1241 NodeTypeTag::Head => write!(f, "head"),
1242 NodeTypeTag::Body => write!(f, "body"),
1243
1244 NodeTypeTag::Div => write!(f, "div"),
1246 NodeTypeTag::P => write!(f, "p"),
1247 NodeTypeTag::Article => write!(f, "article"),
1248 NodeTypeTag::Section => write!(f, "section"),
1249 NodeTypeTag::Nav => write!(f, "nav"),
1250 NodeTypeTag::Aside => write!(f, "aside"),
1251 NodeTypeTag::Header => write!(f, "header"),
1252 NodeTypeTag::Footer => write!(f, "footer"),
1253 NodeTypeTag::Main => write!(f, "main"),
1254 NodeTypeTag::Figure => write!(f, "figure"),
1255 NodeTypeTag::FigCaption => write!(f, "figcaption"),
1256
1257 NodeTypeTag::H1 => write!(f, "h1"),
1259 NodeTypeTag::H2 => write!(f, "h2"),
1260 NodeTypeTag::H3 => write!(f, "h3"),
1261 NodeTypeTag::H4 => write!(f, "h4"),
1262 NodeTypeTag::H5 => write!(f, "h5"),
1263 NodeTypeTag::H6 => write!(f, "h6"),
1264
1265 NodeTypeTag::Br => write!(f, "br"),
1267 NodeTypeTag::Hr => write!(f, "hr"),
1268 NodeTypeTag::Pre => write!(f, "pre"),
1269 NodeTypeTag::BlockQuote => write!(f, "blockquote"),
1270 NodeTypeTag::Address => write!(f, "address"),
1271 NodeTypeTag::Details => write!(f, "details"),
1272 NodeTypeTag::Summary => write!(f, "summary"),
1273 NodeTypeTag::Dialog => write!(f, "dialog"),
1274
1275 NodeTypeTag::Ul => write!(f, "ul"),
1277 NodeTypeTag::Ol => write!(f, "ol"),
1278 NodeTypeTag::Li => write!(f, "li"),
1279 NodeTypeTag::Dl => write!(f, "dl"),
1280 NodeTypeTag::Dt => write!(f, "dt"),
1281 NodeTypeTag::Dd => write!(f, "dd"),
1282 NodeTypeTag::Menu => write!(f, "menu"),
1283 NodeTypeTag::MenuItem => write!(f, "menuitem"),
1284 NodeTypeTag::Dir => write!(f, "dir"),
1285
1286 NodeTypeTag::Table => write!(f, "table"),
1288 NodeTypeTag::Caption => write!(f, "caption"),
1289 NodeTypeTag::THead => write!(f, "thead"),
1290 NodeTypeTag::TBody => write!(f, "tbody"),
1291 NodeTypeTag::TFoot => write!(f, "tfoot"),
1292 NodeTypeTag::Tr => write!(f, "tr"),
1293 NodeTypeTag::Th => write!(f, "th"),
1294 NodeTypeTag::Td => write!(f, "td"),
1295 NodeTypeTag::ColGroup => write!(f, "colgroup"),
1296 NodeTypeTag::Col => write!(f, "col"),
1297
1298 NodeTypeTag::Form => write!(f, "form"),
1300 NodeTypeTag::FieldSet => write!(f, "fieldset"),
1301 NodeTypeTag::Legend => write!(f, "legend"),
1302 NodeTypeTag::Label => write!(f, "label"),
1303 NodeTypeTag::Input => write!(f, "input"),
1304 NodeTypeTag::Button => write!(f, "button"),
1305 NodeTypeTag::Select => write!(f, "select"),
1306 NodeTypeTag::OptGroup => write!(f, "optgroup"),
1307 NodeTypeTag::SelectOption => write!(f, "option"),
1308 NodeTypeTag::TextArea => write!(f, "textarea"),
1309 NodeTypeTag::Output => write!(f, "output"),
1310 NodeTypeTag::Progress => write!(f, "progress"),
1311 NodeTypeTag::Meter => write!(f, "meter"),
1312 NodeTypeTag::DataList => write!(f, "datalist"),
1313
1314 NodeTypeTag::Span => write!(f, "span"),
1316 NodeTypeTag::A => write!(f, "a"),
1317 NodeTypeTag::Em => write!(f, "em"),
1318 NodeTypeTag::Strong => write!(f, "strong"),
1319 NodeTypeTag::B => write!(f, "b"),
1320 NodeTypeTag::I => write!(f, "i"),
1321 NodeTypeTag::U => write!(f, "u"),
1322 NodeTypeTag::S => write!(f, "s"),
1323 NodeTypeTag::Mark => write!(f, "mark"),
1324 NodeTypeTag::Del => write!(f, "del"),
1325 NodeTypeTag::Ins => write!(f, "ins"),
1326 NodeTypeTag::Code => write!(f, "code"),
1327 NodeTypeTag::Samp => write!(f, "samp"),
1328 NodeTypeTag::Kbd => write!(f, "kbd"),
1329 NodeTypeTag::Var => write!(f, "var"),
1330 NodeTypeTag::Cite => write!(f, "cite"),
1331 NodeTypeTag::Dfn => write!(f, "dfn"),
1332 NodeTypeTag::Abbr => write!(f, "abbr"),
1333 NodeTypeTag::Acronym => write!(f, "acronym"),
1334 NodeTypeTag::Q => write!(f, "q"),
1335 NodeTypeTag::Time => write!(f, "time"),
1336 NodeTypeTag::Sub => write!(f, "sub"),
1337 NodeTypeTag::Sup => write!(f, "sup"),
1338 NodeTypeTag::Small => write!(f, "small"),
1339 NodeTypeTag::Big => write!(f, "big"),
1340 NodeTypeTag::Bdo => write!(f, "bdo"),
1341 NodeTypeTag::Bdi => write!(f, "bdi"),
1342 NodeTypeTag::Wbr => write!(f, "wbr"),
1343 NodeTypeTag::Ruby => write!(f, "ruby"),
1344 NodeTypeTag::Rt => write!(f, "rt"),
1345 NodeTypeTag::Rtc => write!(f, "rtc"),
1346 NodeTypeTag::Rp => write!(f, "rp"),
1347 NodeTypeTag::Data => write!(f, "data"),
1348
1349 NodeTypeTag::Canvas => write!(f, "canvas"),
1351 NodeTypeTag::Object => write!(f, "object"),
1352 NodeTypeTag::Param => write!(f, "param"),
1353 NodeTypeTag::Embed => write!(f, "embed"),
1354 NodeTypeTag::Audio => write!(f, "audio"),
1355 NodeTypeTag::Video => write!(f, "video"),
1356 NodeTypeTag::Source => write!(f, "source"),
1357 NodeTypeTag::Track => write!(f, "track"),
1358 NodeTypeTag::Map => write!(f, "map"),
1359 NodeTypeTag::Area => write!(f, "area"),
1360 NodeTypeTag::Svg => write!(f, "svg"),
1361 NodeTypeTag::SvgPath => write!(f, "path"),
1362 NodeTypeTag::SvgCircle => write!(f, "circle"),
1363 NodeTypeTag::SvgRect => write!(f, "rect"),
1364 NodeTypeTag::SvgEllipse => write!(f, "ellipse"),
1365 NodeTypeTag::SvgLine => write!(f, "line"),
1366 NodeTypeTag::SvgPolygon => write!(f, "polygon"),
1367 NodeTypeTag::SvgPolyline => write!(f, "polyline"),
1368 NodeTypeTag::SvgG => write!(f, "g"),
1369
1370 NodeTypeTag::SvgDefs => write!(f, "defs"),
1372 NodeTypeTag::SvgSymbol => write!(f, "symbol"),
1373 NodeTypeTag::SvgUse => write!(f, "use"),
1374 NodeTypeTag::SvgSwitch => write!(f, "switch"),
1375
1376 NodeTypeTag::SvgText => write!(f, "svg:text"),
1378 NodeTypeTag::SvgTspan => write!(f, "tspan"),
1379 NodeTypeTag::SvgTextPath => write!(f, "textpath"),
1380
1381 NodeTypeTag::SvgLinearGradient => write!(f, "lineargradient"),
1383 NodeTypeTag::SvgRadialGradient => write!(f, "radialgradient"),
1384 NodeTypeTag::SvgStop => write!(f, "stop"),
1385 NodeTypeTag::SvgPattern => write!(f, "pattern"),
1386
1387 NodeTypeTag::SvgClipPathElement => write!(f, "clippath"),
1389 NodeTypeTag::SvgMask => write!(f, "mask"),
1390
1391 NodeTypeTag::SvgFilter => write!(f, "filter"),
1393 NodeTypeTag::SvgFeBlend => write!(f, "feblend"),
1394 NodeTypeTag::SvgFeColorMatrix => write!(f, "fecolormatrix"),
1395 NodeTypeTag::SvgFeComponentTransfer => write!(f, "fecomponenttransfer"),
1396 NodeTypeTag::SvgFeComposite => write!(f, "fecomposite"),
1397 NodeTypeTag::SvgFeConvolveMatrix => write!(f, "feconvolvematrix"),
1398 NodeTypeTag::SvgFeDiffuseLighting => write!(f, "fediffuselighting"),
1399 NodeTypeTag::SvgFeDisplacementMap => write!(f, "fedisplacementmap"),
1400 NodeTypeTag::SvgFeDistantLight => write!(f, "fedistantlight"),
1401 NodeTypeTag::SvgFeDropShadow => write!(f, "fedropshadow"),
1402 NodeTypeTag::SvgFeFlood => write!(f, "feflood"),
1403 NodeTypeTag::SvgFeFuncR => write!(f, "fefuncr"),
1404 NodeTypeTag::SvgFeFuncG => write!(f, "fefuncg"),
1405 NodeTypeTag::SvgFeFuncB => write!(f, "fefuncb"),
1406 NodeTypeTag::SvgFeFuncA => write!(f, "fefunca"),
1407 NodeTypeTag::SvgFeGaussianBlur => write!(f, "fegaussianblur"),
1408 NodeTypeTag::SvgFeImage => write!(f, "feimage"),
1409 NodeTypeTag::SvgFeMerge => write!(f, "femerge"),
1410 NodeTypeTag::SvgFeMergeNode => write!(f, "femergenode"),
1411 NodeTypeTag::SvgFeMorphology => write!(f, "femorphology"),
1412 NodeTypeTag::SvgFeOffset => write!(f, "feoffset"),
1413 NodeTypeTag::SvgFePointLight => write!(f, "fepointlight"),
1414 NodeTypeTag::SvgFeSpecularLighting => write!(f, "fespecularlighting"),
1415 NodeTypeTag::SvgFeSpotLight => write!(f, "fespotlight"),
1416 NodeTypeTag::SvgFeTile => write!(f, "fetile"),
1417 NodeTypeTag::SvgFeTurbulence => write!(f, "feturbulence"),
1418
1419 NodeTypeTag::SvgMarker => write!(f, "svg:marker"),
1421 NodeTypeTag::SvgImage => write!(f, "svg:image"),
1422 NodeTypeTag::SvgForeignObject => write!(f, "foreignobject"),
1423
1424 NodeTypeTag::SvgTitle => write!(f, "svg:title"),
1426 NodeTypeTag::SvgDesc => write!(f, "desc"),
1427 NodeTypeTag::SvgMetadata => write!(f, "metadata"),
1428 NodeTypeTag::SvgA => write!(f, "svg:a"),
1429 NodeTypeTag::SvgView => write!(f, "view"),
1430 NodeTypeTag::SvgStyle => write!(f, "svg:style"),
1431 NodeTypeTag::SvgScript => write!(f, "svg:script"),
1432
1433 NodeTypeTag::SvgAnimate => write!(f, "animate"),
1435 NodeTypeTag::SvgAnimateMotion => write!(f, "animatemotion"),
1436 NodeTypeTag::SvgAnimateTransform => write!(f, "animatetransform"),
1437 NodeTypeTag::SvgSet => write!(f, "set"),
1438 NodeTypeTag::SvgMpath => write!(f, "mpath"),
1439
1440 NodeTypeTag::Title => write!(f, "title"),
1442 NodeTypeTag::Meta => write!(f, "meta"),
1443 NodeTypeTag::Link => write!(f, "link"),
1444 NodeTypeTag::Script => write!(f, "script"),
1445 NodeTypeTag::Style => write!(f, "style"),
1446 NodeTypeTag::Base => write!(f, "base"),
1447
1448 NodeTypeTag::Text => write!(f, "text"),
1450 NodeTypeTag::Img => write!(f, "img"),
1451 NodeTypeTag::VirtualView => write!(f, "virtual-view"),
1452 NodeTypeTag::Icon => write!(f, "icon"),
1453 NodeTypeTag::GeolocationProbe => write!(f, "geolocation-probe"),
1454
1455 NodeTypeTag::Before => write!(f, "::before"),
1457 NodeTypeTag::After => write!(f, "::after"),
1458 NodeTypeTag::Marker => write!(f, "::marker"),
1459 NodeTypeTag::Placeholder => write!(f, "::placeholder"),
1460 }
1461 }
1462}
1463
1464#[derive(Clone, Hash, Default, PartialEq, Eq, PartialOrd, Ord)]
1476#[repr(C)]
1477pub struct CssPath {
1478 pub selectors: CssPathSelectorVec,
1479}
1480
1481impl_vec!(CssPathSelector, CssPathSelectorVec, CssPathSelectorVecDestructor, CssPathSelectorVecDestructorType, CssPathSelectorVecSlice, OptionCssPathSelector);
1482impl_vec_debug!(CssPathSelector, CssPathSelectorVec);
1483impl_vec_partialord!(CssPathSelector, CssPathSelectorVec);
1484impl_vec_ord!(CssPathSelector, CssPathSelectorVec);
1485impl_vec_clone!(
1486 CssPathSelector,
1487 CssPathSelectorVec,
1488 CssPathSelectorVecDestructor
1489);
1490impl_vec_partialeq!(CssPathSelector, CssPathSelectorVec);
1491impl_vec_eq!(CssPathSelector, CssPathSelectorVec);
1492impl_vec_hash!(CssPathSelector, CssPathSelectorVec);
1493
1494impl CssPath {
1495 pub fn new(selectors: Vec<CssPathSelector>) -> Self {
1496 Self {
1497 selectors: selectors.into(),
1498 }
1499 }
1500}
1501
1502impl fmt::Display for CssPath {
1503 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1504 for selector in self.selectors.as_ref() {
1505 write!(f, "{}", selector)?;
1506 }
1507 Ok(())
1508 }
1509}
1510
1511impl fmt::Debug for CssPath {
1512 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1513 write!(f, "{}", self)
1514 }
1515}
1516
1517#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1518#[repr(C, u8)]
1519#[derive(Default)]
1520pub enum CssPathSelector {
1521 #[default]
1523 Global,
1524 Type(NodeTypeTag),
1526 Class(AzString),
1528 Id(AzString),
1530 PseudoSelector(CssPathPseudoSelector),
1532 Attribute(CssAttributeSelector),
1534 DirectChildren,
1536 Children,
1538 AdjacentSibling,
1540 GeneralSibling,
1542}
1543
1544#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1546#[repr(C)]
1547pub struct CssAttributeSelector {
1548 pub name: AzString,
1549 pub op: AttributeMatchOp,
1550 pub value: OptionString,
1551}
1552
1553impl Default for CssAttributeSelector {
1554 fn default() -> Self {
1555 Self {
1556 name: AzString::default(),
1557 op: AttributeMatchOp::Exists,
1558 value: OptionString::None,
1559 }
1560 }
1561}
1562
1563#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1565#[repr(C)]
1566pub enum AttributeMatchOp {
1567 Exists,
1569 Eq,
1571 Includes,
1573 DashMatch,
1575 Prefix,
1577 Suffix,
1579 Substring,
1581}
1582
1583impl Default for AttributeMatchOp {
1584 fn default() -> Self {
1585 AttributeMatchOp::Exists
1586 }
1587}
1588
1589impl_option!(
1590 CssPathSelector,
1591 OptionCssPathSelector,
1592 copy = false,
1593 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
1594);
1595
1596
1597impl fmt::Display for CssPathSelector {
1598 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1599 use self::CssPathSelector::*;
1600 match &self {
1601 Global => write!(f, "*"),
1602 Type(n) => write!(f, "{}", n),
1603 Class(c) => write!(f, ".{}", c),
1604 Id(i) => write!(f, "#{}", i),
1605 PseudoSelector(p) => write!(f, ":{}", p),
1606 Attribute(a) => write!(f, "{}", a),
1607 DirectChildren => write!(f, ">"),
1608 Children => write!(f, " "),
1609 AdjacentSibling => write!(f, "+"),
1610 GeneralSibling => write!(f, "~"),
1611 }
1612 }
1613}
1614
1615impl fmt::Display for CssAttributeSelector {
1616 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1617 match (&self.op, self.value.as_ref()) {
1618 (AttributeMatchOp::Exists, _) => write!(f, "[{}]", self.name),
1619 (op, Some(v)) => write!(f, "[{}{}=\"{}\"]", self.name, op.symbol_prefix(), v),
1620 (op, None) => write!(f, "[{}{}=\"\"]", self.name, op.symbol_prefix()),
1621 }
1622 }
1623}
1624
1625impl AttributeMatchOp {
1626 pub fn symbol_prefix(&self) -> &'static str {
1629 match self {
1630 AttributeMatchOp::Exists => "",
1631 AttributeMatchOp::Eq => "",
1632 AttributeMatchOp::Includes => "~",
1633 AttributeMatchOp::DashMatch => "|",
1634 AttributeMatchOp::Prefix => "^",
1635 AttributeMatchOp::Suffix => "$",
1636 AttributeMatchOp::Substring => "*",
1637 }
1638 }
1639}
1640
1641#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1642#[repr(C, u8)]
1643pub enum CssPathPseudoSelector {
1644 First,
1646 Last,
1648 NthChild(CssNthChildSelector),
1650 Hover,
1652 Active,
1654 Focus,
1656 Lang(AzString),
1658 Backdrop,
1660 Dragging,
1662 DragOver,
1664}
1665
1666#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1668#[repr(C, u8)]
1669pub enum CssNthChildSelector {
1670 Number(u32),
1671 Even,
1672 Odd,
1673 Pattern(CssNthChildPattern),
1674}
1675
1676#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1678#[repr(C)]
1679pub struct CssNthChildPattern {
1680 pub pattern_repeat: u32,
1681 pub offset: u32,
1682}
1683
1684impl fmt::Display for CssNthChildSelector {
1685 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1686 use self::CssNthChildSelector::*;
1687 match &self {
1688 Number(u) => write!(f, "{}", u),
1689 Even => write!(f, "even"),
1690 Odd => write!(f, "odd"),
1691 Pattern(p) => write!(f, "{}n + {}", p.pattern_repeat, p.offset),
1692 }
1693 }
1694}
1695
1696impl fmt::Display for CssPathPseudoSelector {
1697 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1698 use self::CssPathPseudoSelector::*;
1699 match &self {
1700 First => write!(f, "first"),
1701 Last => write!(f, "last"),
1702 NthChild(u) => write!(f, "nth-child({})", u),
1703 Hover => write!(f, "hover"),
1704 Active => write!(f, "active"),
1705 Focus => write!(f, "focus"),
1706 Lang(lang) => write!(f, "lang({})", lang.as_str()),
1707 Backdrop => write!(f, "backdrop"),
1708 Dragging => write!(f, "dragging"),
1709 DragOver => write!(f, "drag-over"),
1710 }
1711 }
1712}
1713
1714impl Css {
1715 pub fn empty() -> Self {
1717 Default::default()
1718 }
1719
1720 pub fn sort_by_specificity(&mut self) {
1725 self.rules.as_mut().sort_by(|a, b| {
1726 a.priority.cmp(&b.priority)
1727 .then_with(|| get_specificity(&a.path).cmp(&get_specificity(&b.path)))
1728 });
1729 }
1730
1731 pub fn rules<'a>(&'a self) -> core::slice::Iter<'a, CssRuleBlock> {
1732 self.rules.as_ref().iter()
1733 }
1734
1735 pub fn iter_inline_properties<'a>(
1743 &'a self,
1744 ) -> impl Iterator<
1745 Item = (
1746 &'a crate::props::property::CssProperty,
1747 &'a DynamicSelectorVec,
1748 ),
1749 > + 'a {
1750 self.rules.as_ref().iter().flat_map(|r| {
1751 r.declarations.as_ref().iter().filter_map(move |d| match d {
1752 CssDeclaration::Static(p) => Some((p, &r.conditions)),
1753 CssDeclaration::Dynamic(_) => None,
1754 })
1755 })
1756 }
1757}
1758
1759#[cfg(test)]
1760mod priority_sort_tests {
1761 use super::*;
1762 use crate::css::rule_priority;
1763
1764 fn rule_with(priority: u8, selectors: Vec<CssPathSelector>) -> CssRuleBlock {
1765 CssRuleBlock {
1766 path: CssPath { selectors: selectors.into() },
1767 declarations: Vec::new().into(),
1768 conditions: DynamicSelectorVec::from_const_slice(&[]),
1769 priority,
1770 }
1771 }
1772
1773 #[test]
1776 fn sort_by_priority_then_specificity() {
1777 let mut css = Css::new(vec![
1778 rule_with(rule_priority::AUTHOR, vec![CssPathSelector::Global]),
1780 rule_with(rule_priority::UA, vec![
1782 CssPathSelector::Id("ua-id".to_string().into()),
1783 CssPathSelector::Class("ua-class".to_string().into()),
1784 ]),
1785 rule_with(rule_priority::AUTHOR, vec![
1787 CssPathSelector::Id("a-id".to_string().into()),
1788 ]),
1789 rule_with(rule_priority::SYSTEM, vec![CssPathSelector::Global]),
1791 ]);
1792 css.sort_by_specificity();
1793 let priorities: Vec<u8> = css.rules.as_ref().iter().map(|r| r.priority).collect();
1794 assert_eq!(
1795 priorities,
1796 vec![rule_priority::UA, rule_priority::SYSTEM, rule_priority::AUTHOR, rule_priority::AUTHOR],
1797 "rules must sort by layer first; specificity only breaks ties within a layer"
1798 );
1799 let last_two_specificity: Vec<_> = css.rules.as_ref().iter()
1801 .filter(|r| r.priority == rule_priority::AUTHOR)
1802 .map(|r| get_specificity(&r.path))
1803 .collect();
1804 assert!(last_two_specificity[0] < last_two_specificity[1]);
1805 }
1806}
1807
1808pub fn get_specificity(path: &CssPath) -> (usize, usize, usize, usize) {
1811 let id_count = path
1812 .selectors
1813 .iter()
1814 .filter(|x| matches!(x, CssPathSelector::Id(_)))
1815 .count();
1816 let class_count = path
1817 .selectors
1818 .iter()
1819 .filter(|x| {
1820 matches!(
1821 x,
1822 CssPathSelector::Class(_)
1823 | CssPathSelector::PseudoSelector(_)
1824 | CssPathSelector::Attribute(_)
1825 )
1826 })
1827 .count();
1828 let div_count = path
1829 .selectors
1830 .iter()
1831 .filter(|x| matches!(x, CssPathSelector::Type(_)))
1832 .count();
1833 (id_count, class_count, div_count, path.selectors.len())
1834}