css_parse/syntax/
at_rule.rs1use crate::{
2 Cursor, CursorSink, Parse, Parser, Peek, Result as ParserResult, Span, T, ToCursors, ToSpan, token_macros,
3};
4use std::marker::PhantomData;
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
59pub struct AtRule<AT, P, B>
60where
61 AT: Into<token_macros::AtKeyword>,
62{
63 pub name: token_macros::AtKeyword,
64 pub prelude: P,
65 pub block: B,
66 pub semicolon: Option<token_macros::Semicolon>,
67 #[cfg_attr(feature = "serde", serde(skip))]
68 _phantom: PhantomData<AT>,
69}
70
71impl<'a, AT, P, B> Peek<'a> for AtRule<AT, P, B>
72where
73 AT: Peek<'a> + Into<token_macros::AtKeyword>,
74{
75 fn peek(p: &Parser<'a>, c: Cursor) -> bool {
76 <AT>::peek(p, c)
77 }
78}
79
80impl<'a, AT, P, B> Parse<'a> for AtRule<AT, P, B>
81where
82 AT: Parse<'a> + Into<token_macros::AtKeyword>,
83 P: Parse<'a>,
84 B: Parse<'a>,
85{
86 fn parse(p: &mut Parser<'a>) -> ParserResult<Self> {
87 let name = p.parse::<AT>()?.into();
88 let prelude = p.parse::<P>()?;
89 let block = p.parse::<B>()?;
90 let semicolon = p.parse_if_peek::<T![;]>()?;
91 Ok(Self { name, prelude, block, semicolon, _phantom: PhantomData })
92 }
93}
94
95impl<AT, P, B> ToCursors for AtRule<AT, P, B>
96where
97 AT: Into<token_macros::AtKeyword>,
98 P: ToCursors,
99 B: ToCursors,
100{
101 fn to_cursors(&self, s: &mut impl CursorSink) {
102 ToCursors::to_cursors(&self.name, s);
103 ToCursors::to_cursors(&self.prelude, s);
104 ToCursors::to_cursors(&self.block, s);
105 ToCursors::to_cursors(&self.semicolon, s);
106 }
107}
108
109impl<AT, P, B> ToSpan for AtRule<AT, P, B>
110where
111 AT: Into<token_macros::AtKeyword>,
112 P: ToSpan,
113 B: ToSpan,
114{
115 fn to_span(&self) -> Span {
116 self.name.to_span()
117 + if let Some(semi) = self.semicolon {
118 semi.to_span()
119 } else {
120 self.prelude.to_span() + self.block.to_span()
121 }
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 use crate::{SimpleBlock, test_helpers::*};
129
130 #[test]
131 fn size_test() {
132 assert_eq!(std::mem::size_of::<AtRule<T![AtKeyword], T![Ident], T![Ident]>>(), 52);
133 }
134
135 #[test]
136 fn test_writes() {
137 assert_parse!(AtRule < T![AtKeyword], Option<T![Ident]>, SimpleBlock>, "@foo{}");
138 assert_parse!(AtRule < T![AtKeyword], Option<T![Ident]>, SimpleBlock>, "@foo prelude{}");
139 assert_parse!(AtRule < T![AtKeyword], T![Ident], SimpleBlock>, "@foo prelude{}");
140 }
141
142 #[test]
143 fn test_errors() {
144 assert_parse_error!(AtRule < T![AtKeyword], T![Ident], SimpleBlock>, "@foo{}");
145 }
146}