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