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