css_parse/syntax/
rule_list.rs1use crate::{
2 CursorSink, Kind, KindSet, NodeMetadata, NodeWithMetadata, Parse, Parser, Peek, Result, SemanticEq, T, ToCursors,
3 ToSpan, token_macros,
4};
5use bumpalo::collections::Vec;
6
7#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[cfg_attr(
25 feature = "serde",
26 derive(serde::Serialize),
27 serde(bound(serialize = "R: serde::Serialize, M: serde::Serialize"))
28)]
29pub struct RuleList<'a, R, M>
30where
31 R: NodeWithMetadata<M>,
32 M: NodeMetadata,
33{
34 pub open_curly: token_macros::LeftCurly,
35 pub rules: Vec<'a, R>,
36 pub close_curly: Option<token_macros::RightCurly>,
37 #[cfg_attr(feature = "serde", serde(skip))]
38 pub meta: M,
39}
40
41impl<'a, R, M> Peek<'a> for RuleList<'a, R, M>
42where
43 R: NodeWithMetadata<M>,
44 M: NodeMetadata,
45{
46 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::LeftCurly]);
47}
48
49impl<'a, R, M> Parse<'a> for RuleList<'a, R, M>
50where
51 R: Parse<'a> + NodeWithMetadata<M>,
52 M: NodeMetadata,
53{
54 fn parse<Iter>(p: &mut Parser<'a, Iter>) -> Result<Self>
55 where
56 Iter: Iterator<Item = crate::Cursor> + Clone,
57 {
58 let open_curly = p.parse::<T!['{']>()?;
59 let mut rules = Vec::new_in(p.bump());
60 let mut meta = M::default();
61 loop {
62 p.parse_if_peek::<T![;]>().ok();
63 if p.at_end() {
64 return Ok(Self { open_curly, rules, close_curly: None, meta });
65 }
66 let close_curly = p.parse_if_peek::<T!['}']>()?;
67 if close_curly.is_some() {
68 return Ok(Self { open_curly, rules, close_curly, meta });
69 }
70 let rule = p.parse::<R>()?;
71 meta = meta.merge(rule.metadata());
72 rules.push(rule);
73 }
74 }
75}
76
77impl<'a, R, M> ToCursors for RuleList<'a, R, M>
78where
79 R: ToCursors + NodeWithMetadata<M>,
80 M: NodeMetadata,
81{
82 fn to_cursors(&self, s: &mut impl CursorSink) {
83 ToCursors::to_cursors(&self.open_curly, s);
84 ToCursors::to_cursors(&self.rules, s);
85 ToCursors::to_cursors(&self.close_curly, s);
86 }
87}
88
89impl<'a, R, M> ToSpan for RuleList<'a, R, M>
90where
91 R: ToSpan + NodeWithMetadata<M>,
92 M: NodeMetadata,
93{
94 fn to_span(&self) -> css_lexer::Span {
95 self.open_curly.to_span()
96 + if let Some(close) = self.close_curly { close.to_span() } else { self.rules.to_span() }
97 }
98}
99
100impl<'a, R, M> NodeWithMetadata<M> for RuleList<'a, R, M>
101where
102 R: NodeWithMetadata<M>,
103 M: NodeMetadata,
104{
105 fn metadata(&self) -> M {
106 self.meta
107 }
108}
109
110impl<'a, R, M> SemanticEq for RuleList<'a, R, M>
111where
112 R: NodeWithMetadata<M> + SemanticEq,
113 M: NodeMetadata,
114{
115 fn semantic_eq(&self, other: &Self) -> bool {
116 self.open_curly.semantic_eq(&other.open_curly)
117 && self.rules.semantic_eq(&other.rules)
118 && self.close_curly.semantic_eq(&other.close_curly)
119 }
120}