1use crate::{
2 AssociatedWhitespaceRules, Cursor, CursorSink, FunctionBlock, Kind, KindSet, Parse, Parser, Peek,
3 Result as ParserResult, SimpleBlock, Span, State, T, ToCursors, ToSpan, diagnostics,
4};
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(untagged))]
11pub enum ComponentValue<'a> {
12 SimpleBlock(SimpleBlock<'a>),
13 Function(FunctionBlock<'a>),
14 Whitespace(T![Whitespace]),
15 Number(T![Number]),
16 Dimension(T![Dimension]),
17 Ident(T![Ident]),
18 AtKeyword(T![AtKeyword]),
19 Hash(T![Hash]),
20 String(T![String]),
21 Url(T![Url]),
22 Delim(T![Delim]),
23 Colon(T![:]),
24 Semicolon(T![;]),
25 Comma(T![,]),
26}
27
28impl<'a> Peek<'a> for ComponentValue<'a> {
29 fn peek(_: &Parser<'a>, c: Cursor) -> bool {
30 let kindset = KindSet::new(&[
31 Kind::Whitespace,
32 Kind::Number,
33 Kind::Dimension,
34 Kind::Ident,
35 Kind::AtKeyword,
36 Kind::Hash,
37 Kind::String,
38 Kind::Url,
39 Kind::Delim,
40 Kind::Colon,
41 Kind::Semicolon,
42 Kind::Comma,
43 Kind::Function,
44 Kind::LeftCurly,
45 Kind::LeftParen,
46 Kind::LeftSquare,
47 ]);
48 c == kindset
49 }
50}
51
52impl<'a> Parse<'a> for ComponentValue<'a> {
54 fn parse(p: &mut Parser<'a>) -> ParserResult<Self> {
55 if p.peek::<T![' ']>() {
56 p.parse::<T![' ']>().map(Self::Whitespace)
57 } else if p.peek::<T![PairWiseStart]>() {
58 let old_state = p.set_state(State::Nested);
59 let block = p.parse::<SimpleBlock>();
60 p.set_state(old_state);
61 Ok(Self::SimpleBlock(block?))
62 } else if p.peek::<T![Function]>() {
63 p.parse::<FunctionBlock>().map(Self::Function)
64 } else if p.peek::<T![Number]>() {
65 p.parse::<T![Number]>().map(Self::Number)
66 } else if p.peek::<T![Dimension]>() {
67 p.parse::<T![Dimension]>().map(Self::Dimension)
68 } else if p.peek::<T![Ident]>() {
69 p.parse::<T![Ident]>().map(Self::Ident)
70 } else if p.peek::<T![AtKeyword]>() {
71 p.parse::<T![AtKeyword]>().map(Self::AtKeyword)
72 } else if p.peek::<T![Hash]>() {
73 p.parse::<T![Hash]>().map(Self::Hash)
74 } else if p.peek::<T![String]>() {
75 p.parse::<T![String]>().map(Self::String)
76 } else if p.peek::<T![Url]>() {
77 p.parse::<T![Url]>().map(Self::Url)
78 } else if p.peek::<T![Delim]>() {
79 p.parse::<T![Delim]>().map(|delim| {
80 let mut rules = AssociatedWhitespaceRules::none();
82 if p.peek_next_including_whitespace() == Kind::Whitespace {
83 rules |= AssociatedWhitespaceRules::EnforceAfter;
84 } else {
85 rules |= AssociatedWhitespaceRules::BanAfter;
86 }
87 Self::Delim(delim.with_associated_whitespace(rules))
88 })
89 } else if p.peek::<T![:]>() {
90 p.parse::<T![:]>().map(Self::Colon)
91 } else if p.peek::<T![;]>() {
92 p.parse::<T![;]>().map(Self::Semicolon)
93 } else if p.peek::<T![,]>() {
94 p.parse::<T![,]>().map(Self::Comma)
95 } else {
96 Err(diagnostics::Unexpected(p.next()))?
97 }
98 }
99}
100
101impl<'a> ToCursors for ComponentValue<'a> {
102 fn to_cursors(&self, s: &mut impl CursorSink) {
103 match self {
104 Self::SimpleBlock(t) => ToCursors::to_cursors(t, s),
105 Self::Function(t) => ToCursors::to_cursors(t, s),
106 Self::Ident(t) => ToCursors::to_cursors(t, s),
107 Self::AtKeyword(t) => ToCursors::to_cursors(t, s),
108 Self::Hash(t) => ToCursors::to_cursors(t, s),
109 Self::String(t) => ToCursors::to_cursors(t, s),
110 Self::Url(t) => ToCursors::to_cursors(t, s),
111 Self::Delim(t) => ToCursors::to_cursors(t, s),
112 Self::Number(t) => ToCursors::to_cursors(t, s),
113 Self::Dimension(t) => ToCursors::to_cursors(t, s),
114 Self::Whitespace(t) => ToCursors::to_cursors(t, s),
115 Self::Colon(t) => ToCursors::to_cursors(t, s),
116 Self::Semicolon(t) => ToCursors::to_cursors(t, s),
117 Self::Comma(t) => ToCursors::to_cursors(t, s),
118 }
119 }
120}
121
122impl<'a> ToSpan for ComponentValue<'a> {
123 fn to_span(&self) -> Span {
124 match self {
125 Self::SimpleBlock(t) => t.to_span(),
126 Self::Function(t) => t.to_span(),
127 Self::Ident(t) => t.to_span(),
128 Self::AtKeyword(t) => t.to_span(),
129 Self::Hash(t) => t.to_span(),
130 Self::String(t) => t.to_span(),
131 Self::Url(t) => t.to_span(),
132 Self::Delim(t) => t.to_span(),
133 Self::Number(t) => t.to_span(),
134 Self::Dimension(t) => t.to_span(),
135 Self::Whitespace(t) => t.to_span(),
136 Self::Colon(t) => t.to_span(),
137 Self::Semicolon(t) => t.to_span(),
138 Self::Comma(t) => t.to_span(),
139 }
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::test_helpers::*;
147
148 #[test]
149 fn size_test() {
150 assert_eq!(std::mem::size_of::<ComponentValue>(), 72);
151 }
152
153 #[test]
154 fn test_writes() {
155 assert_parse!(ComponentValue, "foo");
156 assert_parse!(ComponentValue, " ");
157 assert_parse!(ComponentValue, "{block}");
158 }
159}