1use super::super::prelude::*;
2use crate::{types::Ratio, units::Length};
3use css_parse::{discrete_feature, ranged_feature};
4#[cfg(feature = "visitable")]
5use csskit_proc_macro::visit;
6
7ranged_feature!(
8 #[derive(ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
10 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
11 pub enum WidthContainerFeature{CssAtomSet::Width, Length}
12);
13
14ranged_feature!(
15 #[derive(ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
16 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
17 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
18 pub enum HeightContainerFeature{CssAtomSet::Height, Length}
19);
20
21ranged_feature!(
22 #[derive(ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
23 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
24 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
25 pub enum InlineSizeContainerFeature{CssAtomSet::InlineSize, Length}
26);
27
28ranged_feature!(
29 #[derive(ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
31 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
32 pub enum BlockSizeContainerFeature{CssAtomSet::BlockSize, Length}
33);
34
35ranged_feature!(
36 #[derive(ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
37 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
38 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
39 pub enum AspectRatioContainerFeature{CssAtomSet::AspectRatio, Ratio}
40);
41
42#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
44#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
45pub enum OrientationContainerFeatureKeyword {
46 #[atom(CssAtomSet::Portrait)]
47 Portrait(T![Ident]),
48 #[atom(CssAtomSet::Landscape)]
49 Landscape(T![Ident]),
50}
51
52discrete_feature!(
53 #[derive(ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
54 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
55 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
56 pub enum OrientationContainerFeature{CssAtomSet::Orientation, OrientationContainerFeatureKeyword}
57);
58
59#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
61#[cfg_attr(feature = "visitable", visit)]
62pub enum StyleQuery<'a> {
63 Is(Declaration<'a, StyleValue<'a>, CssMetadata>),
64 Not(T![Ident], Declaration<'a, StyleValue<'a>, CssMetadata>),
65 And(Vec<'a, (Declaration<'a, StyleValue<'a>, CssMetadata>, Option<T![Ident]>)>),
66 Or(Vec<'a, (Declaration<'a, StyleValue<'a>, CssMetadata>, Option<T![Ident]>)>),
67}
68
69impl<'a> FeatureConditionList<'a> for StyleQuery<'a> {
70 type FeatureCondition = Declaration<'a, StyleValue<'a>, CssMetadata>;
71 fn keyword_is_not<I>(p: &Parser<'a, I>, c: Cursor) -> bool
72 where
73 I: Iterator<Item = Cursor> + Clone,
74 {
75 p.equals_atom(c, &CssAtomSet::Not)
76 }
77 fn keyword_is_and<I>(p: &Parser<'a, I>, c: Cursor) -> bool
78 where
79 I: Iterator<Item = Cursor> + Clone,
80 {
81 p.equals_atom(c, &CssAtomSet::And)
82 }
83 fn keyword_is_or<I>(p: &Parser<'a, I>, c: Cursor) -> bool
84 where
85 I: Iterator<Item = Cursor> + Clone,
86 {
87 p.equals_atom(c, &CssAtomSet::Or)
88 }
89 fn build_is(feature: Self::FeatureCondition) -> Self {
90 Self::Is(feature)
91 }
92 fn build_not(keyword: T![Ident], feature: Self::FeatureCondition) -> Self {
93 Self::Not(keyword, feature)
94 }
95 fn build_and(feature: Vec<'a, (Self::FeatureCondition, Option<T![Ident]>)>) -> Self {
96 Self::And(feature)
97 }
98 fn build_or(feature: Vec<'a, (Self::FeatureCondition, Option<T![Ident]>)>) -> Self {
99 Self::Or(feature)
100 }
101}
102
103impl<'a> Parse<'a> for StyleQuery<'a> {
104 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
105 where
106 I: Iterator<Item = Cursor> + Clone,
107 {
108 Self::parse_condition(p)
109 }
110}
111
112#[cfg(feature = "visitable")]
113impl<'a> VisitableTrait for StyleQuery<'a> {
114 fn accept<V: Visit>(&self, v: &mut V) {
115 v.visit_style_query(self);
116 match self {
117 Self::Is(feature) => feature.accept(v),
118 Self::Not(_, feature) => feature.accept(v),
119 Self::And(features) => {
120 for (feature, _) in features {
121 feature.accept(v);
122 }
123 }
124 Self::Or(features) => {
125 for (feature, _) in features {
126 feature.accept(v);
127 }
128 }
129 }
130 }
131}
132
133#[cfg(feature = "visitable")]
134impl<'a> VisitableMut for StyleQuery<'a> {
135 fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
136 v.visit_style_query(self);
137 match self {
138 Self::Is(feature) => feature.accept_mut(v),
139 Self::Not(_, feature) => feature.accept_mut(v),
140 Self::And(features) => {
141 for (feature, _) in features {
142 feature.accept_mut(v);
143 }
144 }
145 Self::Or(features) => {
146 for (feature, _) in features {
147 feature.accept_mut(v);
148 }
149 }
150 }
151 }
152}
153
154#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
155#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
156#[cfg_attr(feature = "visitable", visit)]
157pub enum ScrollStateQuery<'a> {
158 Is(ScrollStateFeature),
159 Not(T![Ident], ScrollStateFeature),
160 And(Vec<'a, (ScrollStateFeature, Option<T![Ident]>)>),
161 Or(Vec<'a, (ScrollStateFeature, Option<T![Ident]>)>),
162}
163
164impl<'a> FeatureConditionList<'a> for ScrollStateQuery<'a> {
165 type FeatureCondition = ScrollStateFeature;
166 fn keyword_is_not<I>(p: &Parser<'a, I>, c: Cursor) -> bool
167 where
168 I: Iterator<Item = Cursor> + Clone,
169 {
170 p.equals_atom(c, &CssAtomSet::Not)
171 }
172 fn keyword_is_and<I>(p: &Parser<'a, I>, c: Cursor) -> bool
173 where
174 I: Iterator<Item = Cursor> + Clone,
175 {
176 p.equals_atom(c, &CssAtomSet::And)
177 }
178 fn keyword_is_or<I>(p: &Parser<'a, I>, c: Cursor) -> bool
179 where
180 I: Iterator<Item = Cursor> + Clone,
181 {
182 p.equals_atom(c, &CssAtomSet::Or)
183 }
184 fn build_is(feature: ScrollStateFeature) -> Self {
185 Self::Is(feature)
186 }
187 fn build_not(keyword: T![Ident], feature: ScrollStateFeature) -> Self {
188 Self::Not(keyword, feature)
189 }
190 fn build_and(feature: Vec<'a, (ScrollStateFeature, Option<T![Ident]>)>) -> Self {
191 Self::And(feature)
192 }
193 fn build_or(feature: Vec<'a, (ScrollStateFeature, Option<T![Ident]>)>) -> Self {
194 Self::Or(feature)
195 }
196}
197
198impl<'a> Parse<'a> for ScrollStateQuery<'a> {
199 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
200 where
201 I: Iterator<Item = Cursor> + Clone,
202 {
203 Self::parse_condition(p)
204 }
205}
206
207#[cfg(feature = "visitable")]
208impl<'a> VisitableTrait for ScrollStateQuery<'a> {
209 fn accept<V: Visit>(&self, v: &mut V) {
210 match self {
211 Self::Is(feature) => feature.accept(v),
212 Self::Not(_, feature) => feature.accept(v),
213 Self::And(features) => {
214 for (feature, _) in features {
215 feature.accept(v);
216 }
217 }
218 Self::Or(features) => {
219 for (feature, _) in features {
220 feature.accept(v);
221 }
222 }
223 }
224 }
225}
226
227#[cfg(feature = "visitable")]
228impl<'a> VisitableMut for ScrollStateQuery<'a> {
229 fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
230 match self {
231 Self::Is(feature) => feature.accept_mut(v),
232 Self::Not(_, feature) => feature.accept_mut(v),
233 Self::And(features) => {
234 for (feature, _) in features {
235 feature.accept_mut(v);
236 }
237 }
238 Self::Or(features) => {
239 for (feature, _) in features {
240 feature.accept_mut(v);
241 }
242 }
243 }
244 }
245}
246
247#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
248#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
249#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
250pub enum ScrollStateFeature {
251 Scrollable(ScrollableScrollStateFeature),
252 Snapped(SnappedScrollStateFeature),
253 Stuck(StuckScrollStateFeature),
254}
255
256discrete_feature!(
257 #[derive(Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
258 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
259 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
260 pub enum ScrollableScrollStateFeature{CssAtomSet::Scrollable, ScrollableScrollStateFeatureKeyword}
261);
262
263#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
264#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
265#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
266pub enum ScrollableScrollStateFeatureKeyword {
267 #[atom(CssAtomSet::None)]
268 None(T![Ident]),
269 #[atom(CssAtomSet::Top)]
270 Top(T![Ident]),
271 #[atom(CssAtomSet::Right)]
272 Right(T![Ident]),
273 #[atom(CssAtomSet::Bottom)]
274 Bottom(T![Ident]),
275 #[atom(CssAtomSet::Left)]
276 Left(T![Ident]),
277 #[atom(CssAtomSet::BlockStart)]
278 BlockStart(T![Ident]),
279 #[atom(CssAtomSet::InlineStart)]
280 InlineStart(T![Ident]),
281 #[atom(CssAtomSet::BlockEnd)]
282 BlockEnd(T![Ident]),
283 #[atom(CssAtomSet::InlineEnd)]
284 InlineEnd(T![Ident]),
285 #[atom(CssAtomSet::X)]
286 X(T![Ident]),
287 #[atom(CssAtomSet::Y)]
288 Y(T![Ident]),
289 #[atom(CssAtomSet::Block)]
290 Block(T![Ident]),
291 #[atom(CssAtomSet::Inline)]
292 Inline(T![Ident]),
293 #[atom(CssAtomSet::Discrete)]
294 Discrete(T![Ident]),
295}
296
297discrete_feature!(
298 #[derive(Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
299 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
300 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
301 pub enum SnappedScrollStateFeature{CssAtomSet::Snapped, SnappedScrollStateFeatureKeyword}
302);
303
304#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
305#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
306#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
307pub enum SnappedScrollStateFeatureKeyword {
308 #[atom(CssAtomSet::None)]
309 None(T![Ident]),
310 #[atom(CssAtomSet::X)]
311 X(T![Ident]),
312 #[atom(CssAtomSet::Y)]
313 Y(T![Ident]),
314 #[atom(CssAtomSet::Block)]
315 Block(T![Ident]),
316 #[atom(CssAtomSet::Inline)]
317 Inline(T![Ident]),
318 #[atom(CssAtomSet::Both)]
319 Both(T![Ident]),
320 #[atom(CssAtomSet::Discrete)]
321 Discrete(T![Ident]),
322}
323
324discrete_feature!(
325 #[derive(Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
326 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
327 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
328 pub enum StuckScrollStateFeature{CssAtomSet::Stuck, StuckScrollStateFeatureKeyword}
329);
330
331#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
332#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
333#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
334pub enum StuckScrollStateFeatureKeyword {
335 #[atom(CssAtomSet::None)]
336 None(T![Ident]),
337 #[atom(CssAtomSet::Top)]
338 Top(T![Ident]),
339 #[atom(CssAtomSet::Right)]
340 Right(T![Ident]),
341 #[atom(CssAtomSet::Bottom)]
342 Bottom(T![Ident]),
343 #[atom(CssAtomSet::Left)]
344 Left(T![Ident]),
345 #[atom(CssAtomSet::BlockStart)]
346 BlockStart(T![Ident]),
347 #[atom(CssAtomSet::InlineStart)]
348 InlineStart(T![Ident]),
349 #[atom(CssAtomSet::BlockEnd)]
350 BlockEnd(T![Ident]),
351 #[atom(CssAtomSet::InlineEnd)]
352 InlineEnd(T![Ident]),
353 #[atom(CssAtomSet::Discrete)]
354 Discrete(T![Ident]),
355}
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360 use crate::CssAtomSet;
361 use css_parse::{assert_parse, assert_parse_error};
362
363 #[test]
364 fn size_test() {
365 assert_eq!(std::mem::size_of::<WidthContainerFeature>(), 124);
366 assert_eq!(std::mem::size_of::<HeightContainerFeature>(), 124);
367 assert_eq!(std::mem::size_of::<InlineSizeContainerFeature>(), 124);
368 assert_eq!(std::mem::size_of::<BlockSizeContainerFeature>(), 124);
369 assert_eq!(std::mem::size_of::<AspectRatioContainerFeature>(), 180);
370 assert_eq!(std::mem::size_of::<OrientationContainerFeature>(), 64);
371 assert_eq!(std::mem::size_of::<StyleQuery>(), 384);
372 assert_eq!(std::mem::size_of::<ScrollStateQuery>(), 80);
373 assert_eq!(std::mem::size_of::<ScrollStateFeature>(), 68);
374 assert_eq!(std::mem::size_of::<ScrollableScrollStateFeature>(), 64);
375 assert_eq!(std::mem::size_of::<SnappedScrollStateFeature>(), 64);
376 assert_eq!(std::mem::size_of::<StuckScrollStateFeature>(), 64);
377 }
378
379 #[test]
380 fn test_writes() {
381 assert_parse!(CssAtomSet::ATOMS, WidthContainerFeature, "(width:360px)");
382 assert_parse!(CssAtomSet::ATOMS, WidthContainerFeature, "(width>=1400px)");
383 assert_parse!(CssAtomSet::ATOMS, WidthContainerFeature, "(100px<=width)");
384 assert_parse!(CssAtomSet::ATOMS, WidthContainerFeature, "(100px<=width>1400px)");
385 assert_parse!(CssAtomSet::ATOMS, HeightContainerFeature, "(height:360px)");
386 assert_parse!(CssAtomSet::ATOMS, HeightContainerFeature, "(height>=1400px)");
387 assert_parse!(CssAtomSet::ATOMS, HeightContainerFeature, "(100px<=height)");
388 assert_parse!(CssAtomSet::ATOMS, HeightContainerFeature, "(100px<=height>1400px)");
389 }
390
391 #[test]
392 fn test_errors() {
393 assert_parse_error!(CssAtomSet::ATOMS, WidthContainerFeature, "(min-width > 10px)");
394 assert_parse_error!(CssAtomSet::ATOMS, WidthContainerFeature, "(width: 1%)");
395 }
396}