css_parse/syntax/
declaration.rs1use crate::{
2 BangImportant, Cursor, CursorSink, DeclarationValue, Kind, Parse, Parser, Peek, Result, Span, T, ToCursors, ToSpan,
3 token_macros,
4};
5use std::marker::PhantomData;
6
7#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
31pub struct Declaration<'a, V: DeclarationValue<'a>> {
32 pub name: token_macros::Ident,
33 pub colon: token_macros::Colon,
34 pub value: V,
35 pub important: Option<BangImportant>,
36 pub semicolon: Option<token_macros::Semicolon>,
37 #[cfg_attr(feature = "serde", serde(skip))]
38 _phantom: PhantomData<&'a ()>,
39}
40
41impl<'a, V: DeclarationValue<'a>> Peek<'a> for Declaration<'a, V> {
42 fn peek(p: &Parser<'a>, c: Cursor) -> bool {
43 c == Kind::Ident && p.peek_n(2) == Kind::Colon
44 }
45}
46
47impl<'a, V: DeclarationValue<'a>> Parse<'a> for Declaration<'a, V> {
48 fn parse(p: &mut Parser<'a>) -> Result<Self> {
49 let name = p.parse::<T![Ident]>()?;
50 let colon = p.parse::<T![:]>()?;
51 let c: Cursor = name.into();
52 let value = <V>::parse_declaration_value(p, c)?;
53 let important = p.parse_if_peek::<BangImportant>()?;
54 let semicolon = p.parse_if_peek::<T![;]>()?;
55 Ok(Self { name, colon, value, important, semicolon, _phantom: PhantomData })
56 }
57}
58
59impl<'a, V: DeclarationValue<'a> + ToCursors> ToCursors for Declaration<'a, V> {
60 fn to_cursors(&self, s: &mut impl CursorSink) {
61 ToCursors::to_cursors(&self.name, s);
62 ToCursors::to_cursors(&self.colon, s);
63 ToCursors::to_cursors(&self.value, s);
64 ToCursors::to_cursors(&self.important, s);
65 ToCursors::to_cursors(&self.semicolon, s);
66 }
67}
68
69impl<'a, V: DeclarationValue<'a> + ToSpan> ToSpan for Declaration<'a, V> {
70 fn to_span(&self) -> Span {
71 self.name.to_span() + self.value.to_span() + self.important.to_span() + self.semicolon.to_span()
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::EmptyAtomSet;
79 use crate::test_helpers::*;
80
81 #[derive(Debug)]
82 struct Decl(T![Ident]);
83 impl<'a> DeclarationValue<'a> for Decl {
84 type ComputedValue = T![Eof];
85
86 fn is_initial(&self) -> bool {
87 false
88 }
89
90 fn is_inherit(&self) -> bool {
91 false
92 }
93
94 fn is_unset(&self) -> bool {
95 false
96 }
97
98 fn is_revert(&self) -> bool {
99 false
100 }
101
102 fn is_revert_layer(&self) -> bool {
103 false
104 }
105
106 fn needs_computing(&self) -> bool {
107 false
108 }
109
110 fn parse_specified_declaration_value(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
111 p.parse::<T![Ident]>().map(Self)
112 }
113 }
114
115 impl ToCursors for Decl {
116 fn to_cursors(&self, s: &mut impl CursorSink) {
117 s.append(self.0.into())
118 }
119 }
120
121 impl ToSpan for Decl {
122 fn to_span(&self) -> Span {
123 self.0.to_span()
124 }
125 }
126
127 #[test]
128 fn size_test() {
129 assert_eq!(std::mem::size_of::<Declaration<Decl>>(), 80);
130 }
131
132 #[test]
133 fn test_writes() {
134 assert_parse!(EmptyAtomSet::ATOMS, Declaration<Decl>, "color:black;");
135 }
136}