Skip to main content

css_ast/functions/
repeat_function.rs

1use super::prelude::*;
2use crate::{LineNames, NonEmpty, PositiveNonZeroInt};
3
4/// ```text,ignore
5/// <track-repeat>           = repeat( [ <integer [1,∞]> ] , [ <line-names>? <track-size> ]+ <line-names>? )
6/// <fixed-repeat>           = repeat( [ <integer [1,∞]> ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
7/// <auto-repeat>            = repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
8/// <repeat-line-width>      = repeat( [ <integer [1,∞]> ] , [ <line-width> ]+ )
9/// <auto-repeat-line-width> = repeat( auto , [ <line-width> ]+ )
10/// ```
11#[node]
12#[derive(Parse, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
14#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
15#[derive(csskit_derives::NodeWithMetadata)]
16pub struct RepeatFunction<Items, Count = PositiveNonZeroInt> {
17	#[cfg_attr(feature = "visitable", visit(skip))]
18	#[atom(CssAtomSet::Repeat)]
19	pub name: css_parse::token_macros::Function,
20	#[cfg_attr(feature = "visitable", visit(skip))]
21	pub count: Count,
22	#[cfg_attr(feature = "visitable", visit(skip))]
23	#[semantic_eq(skip)]
24	pub comma: css_parse::token_macros::Comma,
25	pub items: Items,
26	#[cfg_attr(feature = "visitable", visit(skip))]
27	#[semantic_eq(skip)]
28	pub close: css_parse::token_macros::RightParen,
29}
30
31impl<'a, Items, Count: Peek<'a>> Peek<'a> for RepeatFunction<Items, Count> {
32	const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Function]);
33
34	#[inline(always)]
35	fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
36	where
37		I: Iterator<Item = Cursor> + Clone,
38	{
39		<css_parse::token_macros::Function>::peek(p, c)
40			&& p.equals_atom(c, &CssAtomSet::Repeat)
41			&& Count::peek(p, p.peek_n(2))
42	}
43}
44
45#[node]
46#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
48#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
49#[derive(csskit_derives::NodeWithMetadata)]
50pub struct NamedRepeatItems<'a, Item> {
51	pub leading_names: Option<LineNames<'a>>,
52	pub items: NonEmpty<Vec<'a, (Item, Option<LineNames<'a>>)>>,
53}
54
55#[node]
56#[derive(
57	Parse, Peek, IntoCursor, ToSpan, SemanticEq, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
58)]
59#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
60#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
61#[derive(csskit_derives::NodeWithMetadata)]
62pub enum AutoFillOrFit {
63	#[atom(CssAtomSet::AutoFill)]
64	AutoFill(T![Ident]),
65	#[atom(CssAtomSet::AutoFit)]
66	AutoFit(T![Ident]),
67}
68
69#[cfg(test)]
70mod tests {
71	use super::*;
72	use crate::{CssAtomSet, FixedSize};
73	use css_parse::{assert_parse, assert_peek_false};
74
75	type FixedRepeat<'a> = RepeatFunction<NamedRepeatItems<'a, FixedSize<'a>>>;
76	type AutoRepeat<'a> = RepeatFunction<NamedRepeatItems<'a, FixedSize<'a>>, AutoFillOrFit>;
77
78	#[test]
79	fn test_count_disambiguates_same_named_function() {
80		assert_parse!(CssAtomSet::ATOMS, FixedRepeat, "repeat(2,10px)");
81		assert_peek_false!(CssAtomSet::ATOMS, FixedRepeat, "repeat(auto-fill,10px)");
82		assert_parse!(CssAtomSet::ATOMS, AutoRepeat, "repeat(auto-fill,10px)");
83		assert_peek_false!(CssAtomSet::ATOMS, AutoRepeat, "repeat(2,10px)");
84	}
85}