style/properties_and_values/syntax/
mod.rs1use std::fmt::{self, Debug};
10use std::{borrow::Cow, fmt::Write};
11
12use crate::derives::*;
13use crate::parser::{Parse, ParserContext};
14use crate::values::CustomIdent;
15use cssparser::{Parser as CSSParser, Token};
16use style_traits::{
17 CssWriter, ParseError as StyleParseError, PropertySyntaxParseError as ParseError,
18 StyleParseErrorKind, ToCss,
19};
20
21use self::data_type::{DataType, DependentDataTypes};
22
23mod ascii;
24pub mod data_type;
25
26#[derive(Debug, Clone, Default, MallocSizeOf, PartialEq, ToShmem)]
28pub struct Descriptor {
29 pub components: Vec<Component>,
32 specified: Option<Box<str>>,
34}
35
36impl Descriptor {
37 pub const fn universal() -> Self {
39 Self {
40 components: Vec::new(),
41 specified: None,
42 }
43 }
44
45 #[inline]
47 pub fn is_universal(&self) -> bool {
48 self.components.is_empty()
49 }
50
51 #[inline]
53 pub fn specified_string(&self) -> Option<&str> {
54 self.specified.as_deref()
55 }
56
57 #[inline]
60 pub fn from_css_parser(input: &mut CSSParser) -> Result<Self, StyleParseError> {
61 let mut components = vec![];
62
63 if input.try_parse(|i| i.expect_delim('*')).is_ok() {
64 return Ok(Self::universal());
65 }
66
67 if let Ok(syntax_string) = input.try_parse(|i| i.expect_string_cloned()) {
69 return Self::from_str(syntax_string.as_ref(), true).map_err(
70 |err| StyleParseError::custom(StyleParseErrorKind::PropertySyntaxField(err)),
71 );
72 }
73
74 loop {
75 let name = Self::try_parse_component_name(input).map_err(|err| {
76 StyleParseError::custom(StyleParseErrorKind::PropertySyntaxField(err))
77 })?;
78
79 let multiplier = if name.is_pre_multiplied() {
80 None
81 } else {
82 Self::try_parse_multiplier(input)
83 };
84
85 let component = Component { multiplier, name };
86 components.push(component);
87 let Ok(delim) = input.next() else { break };
88
89 if delim != &Token::Delim('|') {
90 return Err(StyleParseError::custom(
91 StyleParseErrorKind::PropertySyntaxField(
92 ParseError::ExpectedPipeBetweenComponents,
93 ),
94 ));
95 }
96 }
97
98 Ok(Self {
99 components,
100 specified: None,
101 })
102 }
103
104 fn try_parse_multiplier(input: &mut CSSParser) -> Option<Multiplier> {
105 input
106 .try_parse(|input| {
107 let next = input.next_including_whitespace().map_err(|_| ())?;
108 match next {
109 Token::Delim('+') => Ok(Multiplier::Space),
110 Token::Delim('#') => Ok(Multiplier::Comma),
111 _ => Err(()),
112 }
113 })
114 .ok()
115 }
116
117 fn try_parse_component_name(input: &mut CSSParser) -> Result<ComponentName, ParseError> {
118 if input.try_parse(|input| input.expect_delim('<')).is_ok() {
119 let name = Self::parse_component_data_type_name(input)?;
120 match input.next_including_whitespace() {
121 Ok(&Token::Delim('>')) => Ok(ComponentName::DataType(name)),
122 _ => Err(ParseError::UnclosedDataTypeName),
123 }
124 } else {
125 input.try_parse(|input| {
126 let name = CustomIdent::parse(input, &[]).map_err(|_| ParseError::InvalidName)?;
127 Ok(ComponentName::Ident(name))
128 })
129 }
130 }
131
132 fn parse_component_data_type_name(input: &mut CSSParser) -> Result<DataType, ParseError> {
133 let ty = match input.next_including_whitespace() {
134 Ok(Token::Ident(name)) => DataType::from_str(name),
135 _ => None,
136 };
137 ty.ok_or(ParseError::UnknownDataTypeName)
138 }
139
140 pub fn from_str(css: &str, save_specified: bool) -> Result<Self, ParseError> {
143 let input = ascii::trim_ascii_whitespace(css);
145
146 if input.is_empty() {
148 return Err(ParseError::EmptyInput);
149 }
150
151 let specified = if save_specified {
152 Some(Box::from(css))
153 } else {
154 None
155 };
156
157 if input.len() == 1 && input.as_bytes()[0] == b'*' {
160 return Ok(Self {
161 components: Default::default(),
162 specified,
163 });
164 }
165
166 let mut components = vec![];
173 {
174 let mut input = Parser::new(input, &mut components);
175 input.parse()?;
177 }
178 Ok(Self {
179 components,
180 specified,
181 })
182 }
183
184 pub fn dependent_types(&self) -> DependentDataTypes {
186 let mut types = DependentDataTypes::empty();
187 for component in self.components.iter() {
188 let t = match &component.name {
189 ComponentName::DataType(t) => t,
190 ComponentName::Ident(_) => continue,
191 };
192 types.insert(t.dependent_types());
193 }
194 types
195 }
196}
197
198impl ToCss for Descriptor {
199 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
200 where
201 W: Write,
202 {
203 if let Some(ref specified) = self.specified {
204 return specified.to_css(dest);
205 }
206
207 if self.is_universal() {
208 return dest.write_char('*');
209 }
210
211 let mut first = true;
212 for component in &*self.components {
213 if !first {
214 dest.write_str(" | ")?;
215 }
216 component.to_css(dest)?;
217 first = false;
218 }
219
220 Ok(())
221 }
222}
223
224impl Parse for Descriptor {
225 fn parse(_: &ParserContext, parser: &mut CSSParser) -> Result<Self, StyleParseError> {
227 let input = parser.expect_string()?;
228 Descriptor::from_str(input.as_ref(), true)
229 .map_err(|err| StyleParseError::custom(StyleParseErrorKind::PropertySyntaxField(err)))
230 }
231}
232
233#[derive(
235 Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
236)]
237pub enum Multiplier {
238 Space,
240 Comma,
242}
243
244impl ToCss for Multiplier {
245 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
246 where
247 W: Write,
248 {
249 dest.write_char(match *self {
250 Multiplier::Space => '+',
251 Multiplier::Comma => '#',
252 })
253 }
254}
255
256#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
258pub struct Component {
259 name: ComponentName,
260 multiplier: Option<Multiplier>,
261}
262
263impl Component {
264 #[inline]
266 pub fn name(&self) -> &ComponentName {
267 &self.name
268 }
269
270 #[inline]
272 pub fn multiplier(&self) -> Option<Multiplier> {
273 self.multiplier
274 }
275
276 #[inline]
278 pub fn unpremultiplied(&self) -> Cow<'_, Self> {
279 match self.name.unpremultiply() {
280 Some(component) => {
281 debug_assert!(
282 self.multiplier.is_none(),
283 "Shouldn't have parsed a multiplier for a pre-multiplied data type name",
284 );
285 Cow::Owned(component)
286 },
287 None => Cow::Borrowed(self),
288 }
289 }
290}
291
292impl ToCss for Component {
293 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
294 where
295 W: Write,
296 {
297 self.name().to_css(dest)?;
298 self.multiplier().to_css(dest)
299 }
300}
301
302#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
304pub enum ComponentName {
305 DataType(DataType),
307 Ident(CustomIdent),
309}
310
311impl ComponentName {
312 fn unpremultiply(&self) -> Option<Component> {
313 match *self {
314 ComponentName::DataType(ref t) => t.unpremultiply(),
315 ComponentName::Ident(..) => None,
316 }
317 }
318
319 fn is_pre_multiplied(&self) -> bool {
321 self.unpremultiply().is_some()
322 }
323}
324
325struct Parser<'a> {
326 input: &'a str,
327 position: usize,
328 output: &'a mut Vec<Component>,
329}
330
331impl<'a> Parser<'a> {
332 fn new(input: &'a str, output: &'a mut Vec<Component>) -> Self {
333 Self {
334 input,
335 position: 0,
336 output,
337 }
338 }
339
340 fn peek(&self) -> Option<u8> {
341 self.input.as_bytes().get(self.position).cloned()
342 }
343
344 fn parse(&mut self) -> Result<(), ParseError> {
345 loop {
347 let component = self.parse_component()?;
348 self.output.push(component);
349 self.skip_whitespace();
350
351 let byte = match self.peek() {
352 None => return Ok(()),
353 Some(b) => b,
354 };
355
356 if byte != b'|' {
357 return Err(ParseError::ExpectedPipeBetweenComponents);
358 }
359
360 self.position += 1;
361 }
362 }
363
364 fn skip_whitespace(&mut self) {
365 loop {
366 match self.peek() {
367 Some(c) if c.is_ascii_whitespace() => self.position += 1,
368 _ => return,
369 }
370 }
371 }
372
373 fn parse_data_type_name(&mut self) -> Result<DataType, ParseError> {
375 let start = self.position;
376 loop {
377 let byte = match self.peek() {
378 Some(b) => b,
379 None => return Err(ParseError::UnclosedDataTypeName),
380 };
381 if byte != b'>' {
382 self.position += 1;
383 continue;
384 }
385 let ty = match DataType::from_str(&self.input[start..self.position]) {
386 Some(ty) => ty,
387 None => return Err(ParseError::UnknownDataTypeName),
388 };
389 self.position += 1;
390 return Ok(ty);
391 }
392 }
393
394 fn parse_name(&mut self) -> Result<ComponentName, ParseError> {
395 let b = match self.peek() {
396 Some(b) => b,
397 None => return Err(ParseError::UnexpectedEOF),
398 };
399
400 if b == b'<' {
401 self.position += 1;
402 return Ok(ComponentName::DataType(self.parse_data_type_name()?));
403 }
404
405 let input = &self.input[self.position..];
406 let mut input = CSSParser::new(input);
407 let name = match CustomIdent::parse(&mut input, &[]) {
408 Ok(name) => name,
409 Err(_) => return Err(ParseError::InvalidName),
410 };
411 self.position += input.position().byte_index();
412 Ok(ComponentName::Ident(name))
413 }
414
415 fn parse_multiplier(&mut self) -> Option<Multiplier> {
416 let multiplier = match self.peek()? {
417 b'+' => Multiplier::Space,
418 b'#' => Multiplier::Comma,
419 _ => return None,
420 };
421 self.position += 1;
422 Some(multiplier)
423 }
424
425 fn parse_component(&mut self) -> Result<Component, ParseError> {
427 self.skip_whitespace();
429 let name = self.parse_name()?;
430 let multiplier = if name.is_pre_multiplied() {
431 None
432 } else {
433 self.parse_multiplier()
434 };
435 Ok(Component { name, multiplier })
436 }
437}