css_ast/rules/container/
features.rs

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}