css_parse/syntax/
component_values.rs

1use crate::{
2	AssociatedWhitespaceRules, Cursor, CursorSink, DeclarationValue, Parse, Parser, Peek, Result, Span, ToCursors,
3	ToSpan,
4};
5use bumpalo::collections::Vec;
6
7use super::ComponentValue;
8
9// https://drafts.csswg.org/css-syntax-3/#consume-list-of-components
10#[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	fn peek(p: &Parser<'a>, c: Cursor) -> bool {
18		ComponentValue::peek(p, c)
19	}
20}
21
22impl<'a> Parse<'a> for ComponentValues<'a> {
23	// https://drafts.csswg.org/css-syntax-3/#consume-list-of-components
24	fn parse(p: &mut Parser<'a>) -> Result<Self> {
25		let mut values = Vec::new_in(p.bump());
26		let mut last_was_whitespace = false;
27		loop {
28			if p.at_end() {
29				break;
30			}
31			if p.next_is_stop() {
32				break;
33			}
34			if p.peek::<ComponentValue>() {
35				let mut value = p.parse::<ComponentValue>()?;
36				if let ComponentValue::Delim(d) = value {
37					if last_was_whitespace {
38						let rules = d.associated_whitespace() | AssociatedWhitespaceRules::EnforceBefore;
39						value = ComponentValue::Delim(d.with_associated_whitespace(rules))
40					}
41				}
42				last_was_whitespace = matches!(value, ComponentValue::Whitespace(_));
43				values.push(value);
44			} else {
45				break;
46			}
47		}
48		Ok(Self { values })
49	}
50}
51
52impl<'a> DeclarationValue<'a> for ComponentValues<'a> {
53	type ComputedValue = ComponentValues<'a>;
54
55	fn is_initial(&self) -> bool {
56		false
57	}
58
59	fn is_inherit(&self) -> bool {
60		false
61	}
62
63	fn is_unset(&self) -> bool {
64		false
65	}
66
67	fn is_revert(&self) -> bool {
68		false
69	}
70
71	fn is_revert_layer(&self) -> bool {
72		false
73	}
74
75	fn needs_computing(&self) -> bool {
76		false
77	}
78
79	fn parse_custom_declaration_value(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
80		Self::parse(p)
81	}
82
83	fn parse_computed_declaration_value(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
84		Self::parse(p)
85	}
86
87	fn parse_unknown_declaration_value(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
88		Self::parse(p)
89	}
90}
91
92impl<'a> ToCursors for ComponentValues<'a> {
93	fn to_cursors(&self, s: &mut impl CursorSink) {
94		ToCursors::to_cursors(&self.values, s)
95	}
96}
97
98impl<'a> ToSpan for ComponentValues<'a> {
99	fn to_span(&self) -> Span {
100		self.values.to_span()
101	}
102}
103
104#[cfg(test)]
105mod tests {
106	use super::*;
107	use crate::test_helpers::*;
108
109	#[test]
110	fn size_test() {
111		assert_eq!(std::mem::size_of::<ComponentValues>(), 32);
112	}
113
114	#[test]
115	fn test_writes() {
116		assert_parse!(ComponentValues, "body{color:black}");
117		assert_parse!(ComponentValues, "body");
118	}
119}