lewp_css/domain/at_rules/counter_style/
counter_style_at_rule.rs1use {
2 super::System::{self, *},
3 crate::{
4 domain::{at_rules::counter_style::*, CounterStyleIdent},
5 parsers::{CounterStyleAtRuleParser, ParserContext},
6 CustomParseError,
7 },
8 cssparser::{DeclarationListParser, ParseError, Parser, ToCss},
9 std::{borrow::Cow, fmt},
10};
11
12#[derive(Clone, Debug)]
17pub struct CounterStyleAtRule {
18 pub name: CounterStyleIdent,
19
20 pub system: Option<System>,
22
23 pub negative: Option<Negative>,
25
26 pub prefix: Option<Symbol>,
28
29 pub suffix: Option<Symbol>,
31
32 pub range: Option<Ranges>,
34
35 pub pad: Option<Pad>,
37
38 pub fallback: Option<Fallback>,
40
41 pub symbols: Option<Symbols>,
43
44 pub additive_symbols: Option<AdditiveSymbols>,
46
47 pub speak_as: Option<SpeakAs>,
49}
50
51impl ToCss for CounterStyleAtRule {
52 fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
53 #[inline(always)]
54 fn write<W: fmt::Write, T: ToCss>(
55 afterFirst: &mut bool,
56 dest: &mut W,
57 name: &str,
58 value: &Option<T>,
59 ) -> fmt::Result {
60 if let &Some(ref value) = value {
61 if *afterFirst {
62 dest.write_char(';')?;
63 } else {
64 *afterFirst = true;
65 }
66 dest.write_str(name)?;
67 dest.write_char(':')?;
68 value.to_css(dest)
69 } else {
70 Ok(())
71 }
72 }
73
74 dest.write_str("@counter-style ")?;
75 self.name.to_css(dest)?;
76 dest.write_char('{')?;
77 let mut afterFirst = false;
78 write(&mut afterFirst, dest, "system", &self.system)?;
79 write(&mut afterFirst, dest, "negative", &self.negative)?;
80 write(&mut afterFirst, dest, "prefix", &self.prefix)?;
81 write(&mut afterFirst, dest, "suffix", &self.suffix)?;
82 write(&mut afterFirst, dest, "range", &self.range)?;
83 write(&mut afterFirst, dest, "pad", &self.pad)?;
84 write(&mut afterFirst, dest, "fallback", &self.fallback)?;
85 write(&mut afterFirst, dest, "symbols", &self.symbols)?;
86 write(
87 &mut afterFirst,
88 dest,
89 "additive-symbols",
90 &self.additive_symbols,
91 )?;
92 write(&mut afterFirst, dest, "speak-as", &self.speak_as)?;
93 dest.write_char('}')
94 }
95}
96
97impl CounterStyleAtRule {
98 #[inline(always)]
99 fn empty(name: CounterStyleIdent) -> Self {
100 Self {
101 name,
102 system: None,
103 negative: None,
104 prefix: None,
105 suffix: None,
106 range: None,
107 pad: None,
108 fallback: None,
109 symbols: None,
110 additive_symbols: None,
111 speak_as: None,
112 }
113 }
114
115 #[inline(always)]
117 pub fn name(&self) -> &CounterStyleIdent {
118 &self.name
119 }
120
121 #[inline(always)]
123 pub fn system(&self) -> Cow<System> {
124 if let Some(ref value) = self.system {
125 Cow::Borrowed(value)
126 } else {
127 Cow::Owned(System::Symbolic)
128 }
129 }
130
131 #[inline(always)]
133 pub fn negative(&self) -> Cow<Negative> {
134 if let Some(ref value) = self.negative {
135 Cow::Borrowed(value)
136 } else {
137 Cow::Owned(Negative(Symbol::String("-".to_owned()), None))
138 }
139 }
140
141 #[inline(always)]
143 pub fn prefix(&self) -> Cow<Symbol> {
144 if let Some(ref value) = self.prefix {
145 Cow::Borrowed(value)
146 } else {
147 Cow::Owned(Symbol::String("".to_owned()))
148 }
149 }
150
151 #[inline(always)]
153 pub fn suffix(&self) -> Cow<Symbol> {
154 if let Some(ref value) = self.suffix {
155 Cow::Borrowed(value)
156 } else {
157 Cow::Owned(Symbol::String(". ".to_owned()))
158 }
159 }
160
161 #[inline(always)]
163 pub fn range(&self) -> Cow<Ranges> {
164 if let Some(ref value) = self.range {
165 Cow::Borrowed(value)
166 } else {
167 Cow::Owned(Ranges::empty())
168 }
169 }
170
171 #[inline(always)]
173 pub fn pad(&self) -> Cow<Pad> {
174 if let Some(ref value) = self.pad {
175 Cow::Borrowed(value)
176 } else {
177 Cow::Owned(Pad(0, Symbol::String("".to_owned())))
178 }
179 }
180
181 #[inline(always)]
183 pub fn fallback(&self) -> Cow<Fallback> {
184 if let Some(ref value) = self.fallback {
185 Cow::Borrowed(value)
186 } else {
187 Cow::Owned(Fallback(CounterStyleIdent::decimal))
188 }
189 }
190
191 #[inline(always)]
193 pub fn symbols(&self) -> Option<&Symbols> {
194 self.symbols.as_ref()
195 }
196
197 #[inline(always)]
199 pub fn additive_symbols(&self) -> Option<&AdditiveSymbols> {
200 self.additive_symbols.as_ref()
201 }
202
203 #[inline(always)]
205 pub fn speak_as(&self) -> Cow<SpeakAs> {
206 if let Some(ref value) = self.speak_as {
207 Cow::Borrowed(value)
208 } else {
209 Cow::Owned(SpeakAs::Auto)
210 }
211 }
212
213 pub(crate) fn parse_body<'i, 't>(
215 name: CounterStyleIdent,
216 context: &ParserContext,
217 input: &mut Parser<'i, 't>,
218 ) -> Result<CounterStyleAtRule, ParseError<'i, CustomParseError<'i>>> {
219 let mut rule = CounterStyleAtRule::empty(name);
220
221 {
222 let parser = CounterStyleAtRuleParser {
223 context,
224 rule: &mut rule,
225 };
226 let iterator = DeclarationListParser::new(input, parser);
227 for declaration in iterator {
228 if declaration.is_err() {
229 return Err(declaration.unwrap_err().0);
230 }
231 }
232 }
233
234 match *rule.system() {
235 ref system @ Cyclic
236 | ref system @ Fixed { .. }
237 | ref system @ Symbolic
238 | ref system @ Alphabetic
239 | ref system @ Numeric
240 if rule.symbols.is_none() =>
241 {
242 return Err(ParseError::from(
243 CustomParseError::InvalidCounterStyleWithoutSymbols(system.clone()),
244 ))
245 }
246
247 ref system @ Alphabetic | ref system @ Numeric
248 if rule.symbols().unwrap().0.len() < 2 =>
249 {
250 return Err(ParseError::from(
251 CustomParseError::InvalidCounterStyleNotEnoughSymbols(system.clone()),
252 ))
253 }
254
255 Additive if rule.additive_symbols.is_none() => {
256 return Err(ParseError::from(
257 CustomParseError::InvalidCounterStyleWithoutAdditiveSymbols,
258 ))
259 }
260
261 Extends(_) if rule.symbols.is_some() => {
262 return Err(ParseError::from(
263 CustomParseError::InvalidCounterStyleExtendsWithSymbols,
264 ))
265 }
266
267 Extends(_) if rule.additive_symbols.is_some() => {
268 return Err(ParseError::from(
269 CustomParseError::InvalidCounterStyleExtendsWithAdditiveSymbols,
270 ))
271 }
272
273 _ => {}
274 };
275
276 Ok(rule)
277 }
278}