1use super::prelude::*;
2use crate::Percentage;
3
4#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
25#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
26pub enum EasingFunction<'a> {
27 #[cfg_attr(feature = "visitable", visit(skip))]
28 #[atom(CssAtomSet::Linear)]
29 Linear(T![Ident]),
30 #[cfg_attr(feature = "visitable", visit(skip))]
31 #[atom(CssAtomSet::Ease)]
32 Ease(T![Ident]),
33 #[cfg_attr(feature = "visitable", visit(skip))]
34 #[atom(CssAtomSet::EaseIn)]
35 EaseIn(T![Ident]),
36 #[cfg_attr(feature = "visitable", visit(skip))]
37 #[atom(CssAtomSet::EaseOut)]
38 EaseOut(T![Ident]),
39 #[cfg_attr(feature = "visitable", visit(skip))]
40 #[atom(CssAtomSet::EaseInOut)]
41 EaseInOut(T![Ident]),
42 #[cfg_attr(feature = "visitable", visit(skip))]
43 #[atom(CssAtomSet::StepStart)]
44 StepStart(T![Ident]),
45 #[cfg_attr(feature = "visitable", visit(skip))]
46 #[atom(CssAtomSet::StepEnd)]
47 StepEnd(T![Ident]),
48 #[atom(CssAtomSet::Linear)]
49 LinearFunction(LinearFunction<'a>),
50 #[atom(CssAtomSet::CubicBezier)]
51 CubicBezierFunction(CubicBezierFunction),
52 #[atom(CssAtomSet::Steps)]
53 StepsFunction(StepsFunction),
54}
55
56#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
58#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
59pub struct LinearFunction<'a> {
60 #[atom(CssAtomSet::Linear)]
61 pub name: T![Function],
62 pub params: CommaSeparated<'a, LinearFunctionParams>,
63 pub close: T![')'],
64}
65
66#[derive(Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
67#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
68#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
69pub struct LinearFunctionParams(T![Number], Option<Percentage>, Option<Percentage>);
70
71impl<'a> Parse<'a> for LinearFunctionParams {
72 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
73 where
74 I: Iterator<Item = Cursor> + Clone,
75 {
76 let mut num = p.parse_if_peek::<T![Number]>()?;
77 let percent = p.parse_if_peek::<Percentage>()?;
78 let percent2 = p.parse_if_peek::<Percentage>()?;
79 if num.is_none() {
80 num = Some(p.parse::<T![Number]>()?);
81 }
82 Ok(Self(num.unwrap(), percent, percent2))
83 }
84}
85
86#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
88#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
89pub struct CubicBezierFunction {
90 #[atom(CssAtomSet::CubicBezier)]
91 pub name: T![Function],
92 pub params: CubicBezierFunctionParams,
93 pub close: T![')'],
94}
95
96#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
97#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
98pub struct CubicBezierFunctionParams {
99 x1: T![Number],
100 c1: Option<T![,]>,
101 x2: T![Number],
102 c2: Option<T![,]>,
103 y1: T![Number],
104 c3: Option<T![,]>,
105 y2: T![Number],
106}
107
108#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
110#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
111pub struct StepsFunction {
112 #[atom(CssAtomSet::Steps)]
113 pub name: T![Function],
114 pub params: StepsFunctionParams,
115 pub close: T![')'],
116}
117
118#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
119#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
120pub struct StepsFunctionParams(CSSInt, Option<T![,]>, Option<StepPosition>);
121
122#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
123#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
124pub enum StepPosition {
125 #[atom(CssAtomSet::JumpStart)]
126 JumpStart(T![Ident]),
127 #[atom(CssAtomSet::JumpEnd)]
128 JumpEnd(T![Ident]),
129 #[atom(CssAtomSet::JumpNone)]
130 JumpNone(T![Ident]),
131 #[atom(CssAtomSet::JumpBoth)]
132 JumpBoth(T![Ident]),
133 #[atom(CssAtomSet::Start)]
134 Start(T![Ident]),
135 #[atom(CssAtomSet::End)]
136 End(T![Ident]),
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use crate::CssAtomSet;
143 use css_parse::{assert_parse, assert_parse_error};
144
145 #[test]
146 fn size_test() {
147 assert_eq!(std::mem::size_of::<EasingFunction>(), 120);
148 }
149
150 #[test]
151 fn test_writes() {
152 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "ease-in-out");
153 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "linear(0,1)");
154 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "linear(0,0.25,1)");
155 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "linear(0,0.5 25% 75%,1)");
156 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "cubic-bezier(0.25,0.1,0.25,1)");
157 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "cubic-bezier(0.1,-0.6,0.2,0)");
158 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "cubic-bezier(0,0,1,1)");
159 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "steps(4,end)");
160 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "steps(10,jump-both)");
161 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "linear(0,0.25,1)");
162 assert_parse!(CssAtomSet::ATOMS, EasingFunction, "cubic-bezier(0.1 -0.6 0.2 0)");
163 }
164
165 #[test]
166 fn test_errors() {
167 assert_parse_error!(CssAtomSet::ATOMS, EasingFunction, "foo");
168 assert_parse_error!(CssAtomSet::ATOMS, EasingFunction, "linear()");
169 assert_parse_error!(CssAtomSet::ATOMS, EasingFunction, "cubic-bezier(0.1, red, 1.0, green)");
170 }
171}