css_parse/syntax/
component_values.rs1use crate::{
2 AssociatedWhitespaceRules, Cursor, CursorSink, DeclarationValue, KindSet, NodeMetadata, NodeWithMetadata, Parse,
3 Parser, Peek, Result, SemanticEq, Span, ToCursors, ToSpan,
4};
5use bumpalo::collections::Vec;
6
7use super::ComponentValue;
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
12pub struct ComponentValues<'a> {
13 values: Vec<'a, ComponentValue<'a>>,
14}
15
16impl<'a> Peek<'a> for ComponentValues<'a> {
17 const PEEK_KINDSET: KindSet = ComponentValue::PEEK_KINDSET;
18}
19
20impl<'a> Parse<'a> for ComponentValues<'a> {
21 fn parse<Iter>(p: &mut Parser<'a, Iter>) -> Result<Self>
23 where
24 Iter: Iterator<Item = Cursor> + Clone,
25 {
26 let mut values = Vec::new_in(p.bump());
27 let mut last_was_whitespace = false;
28
29 loop {
30 if p.at_end() {
31 break;
32 }
33 if p.next_is_stop() {
34 break;
35 }
36 if let Some(mut value) = p.parse_if_peek::<ComponentValue>()? {
37 if let ComponentValue::Delim(d) = value
38 && last_was_whitespace
39 && d.associated_whitespace().contains(AssociatedWhitespaceRules::EnforceAfter)
40 {
41 let rules = d.associated_whitespace() | AssociatedWhitespaceRules::EnforceBefore;
42 value = ComponentValue::Delim(d.with_associated_whitespace(rules))
43 }
44 last_was_whitespace = matches!(value, ComponentValue::Whitespace(_));
45 values.push(value);
46 } else {
47 break;
48 }
49 }
50 Ok(Self { values })
51 }
52}
53
54impl<'a, M: NodeMetadata> NodeWithMetadata<M> for ComponentValues<'a> {
55 fn metadata(&self) -> M {
56 M::default()
57 }
58}
59
60impl<'a> DeclarationValue<'a, ()> for ComponentValues<'a> {
61 type ComputedValue = ComponentValues<'a>;
62
63 fn is_initial(&self) -> bool {
64 false
65 }
66
67 fn is_inherit(&self) -> bool {
68 false
69 }
70
71 fn is_unset(&self) -> bool {
72 false
73 }
74
75 fn is_revert(&self) -> bool {
76 false
77 }
78
79 fn is_revert_layer(&self) -> bool {
80 false
81 }
82
83 fn needs_computing(&self) -> bool {
84 false
85 }
86
87 fn parse_custom_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
88 where
89 Iter: Iterator<Item = crate::Cursor> + Clone,
90 {
91 Self::parse(p)
92 }
93
94 fn parse_computed_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
95 where
96 Iter: Iterator<Item = crate::Cursor> + Clone,
97 {
98 Self::parse(p)
99 }
100
101 fn parse_unknown_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
102 where
103 Iter: Iterator<Item = crate::Cursor> + Clone,
104 {
105 Self::parse(p)
106 }
107}
108
109impl<'a> ToCursors for ComponentValues<'a> {
110 fn to_cursors(&self, s: &mut impl CursorSink) {
111 ToCursors::to_cursors(&self.values, s)
112 }
113}
114
115impl<'a> ToSpan for ComponentValues<'a> {
116 fn to_span(&self) -> Span {
117 self.values.to_span()
118 }
119}
120
121impl<'a> SemanticEq for ComponentValues<'a> {
123 fn semantic_eq(&self, other: &Self) -> bool {
124 self.values.semantic_eq(&other.values)
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use crate::{EmptyAtomSet, test_helpers::*};
132
133 #[test]
134 fn size_test() {
135 assert_eq!(std::mem::size_of::<ComponentValues>(), 32);
136 }
137
138 #[test]
139 fn test_writes() {
140 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, "body{color:black}");
141 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, "body");
142 }
143
144 #[test]
145 fn test_writes_with_trivia() {
146 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, "/*comment*/foo");
147 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, " /*comment*/ foo");
148 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, "/*a*/foo/*b*/bar");
149 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, "foo/*comment*/bar");
150 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, " \t foo");
151 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, " /*start*/ foo /*mid*/ bar");
152 assert_parse!(EmptyAtomSet::ATOMS, ComponentValues, "/*comment*/foo");
153 }
154}